/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { money: 0, swishBestScore: 0, rhythmBestScore: 0, currentBasketballMode: "Warriorsball", defaultPlayers: ["player1", "player2", "player3"] }); /**** * Classes ****/ var AIOpponent = Container.expand(function () { var self = Container.call(this); //{7j_ai} self.isActive = true; self.score = 0; self.difficulty = 1.8; // Difficulty multiplier - much harder base difficulty self.shotTimer = 0; self.shotInterval = 80; // Frames between AI shots (1.33 seconds at 60fps) - shoot much more frequently self.targetHoop = null; // Which hoop AI is targeting self.accuracy = 0.95; // Base accuracy percentage - near perfect accuracy self.lastShotTime = 0; self.perfectShotChance = 0.8; // 80% chance for perfect shots - extremely high self.adaptiveTimer = 0; // Timer for adaptive difficulty self.playerScoreWhenLastShot = 0; // Track player score for adaptive difficulty self.update = function () { if (!self.isActive || gameMode !== 'ai_vs') return; // Adaptive difficulty - AI gets extremely aggressive if player is ahead var scoreDifference = LK.getScore() - self.score; if (scoreDifference > 4) { self.difficulty = 3.0; // Massive difficulty increase self.shotInterval = 60; // Shoot extremely frequently (1 second) self.accuracy = 0.98; // Nearly perfect accuracy self.perfectShotChance = 0.95; // Almost all shots are perfect } else if (scoreDifference > 2) { self.difficulty = 2.5; // Very high difficulty self.shotInterval = 70; // 1.17 seconds self.accuracy = 0.96; self.perfectShotChance = 0.9; } else if (scoreDifference > 0) { self.difficulty = 2.0; // High difficulty self.shotInterval = 80; // 1.33 seconds self.accuracy = 0.94; self.perfectShotChance = 0.85; } else if (scoreDifference < -2) { // AI is ahead, reduce difficulty slightly but still very challenging self.difficulty = 1.5; self.shotInterval = 100; // 1.67 seconds self.accuracy = 0.9; self.perfectShotChance = 0.7; } else { // Normal difficulty - much harder than before self.difficulty = 1.8; self.shotInterval = 80; // 1.33 seconds self.accuracy = 0.95; self.perfectShotChance = 0.8; } self.shotTimer++; if (self.shotTimer >= self.shotInterval) { self.takeShot(); self.shotTimer = 0; } }; self.takeShot = function () { // Randomly choose a hoop to target var availableHoops = [hoop, leftHoop, rightHoop]; self.targetHoop = availableHoops[Math.floor(Math.random() * availableHoops.length)]; // Determine shot position based on target hoop var startX, startY; if (self.targetHoop === leftHoop) { startX = 300 + (Math.random() - 0.5) * 100; // Some randomness startY = 2000; } else if (self.targetHoop === rightHoop) { startX = 1748 + (Math.random() - 0.5) * 100; startY = 2000; } else { startX = 1024 + (Math.random() - 0.5) * 100; startY = 2000; } // Determine if this will be a perfect shot var isPerfectShot = Math.random() < self.perfectShotChance; var ball = new Basketball(); ball.x = startX; ball.y = startY; ball.isAIShot = true; // Mark as AI shot ball.aiOpponent = self; // Reference to AI for scoring if (isPerfectShot || Math.random() < self.accuracy) { // Accurate shot var targetX = self.targetHoop.x; var targetY = self.targetHoop.y - 350; var deltaX = targetX - startX; var deltaY = targetY - startY; var time = 45; var gravity = 0.5; ball.velocityX = deltaX / time + (Math.random() - 0.5) * 2; // Small randomness ball.velocityY = deltaY / time - 0.5 * gravity * time - 1.5; if (isPerfectShot) { ball.guaranteedSwish = true; ball.isPerfectShot = true; } } else { // Inaccurate shot ball.velocityX = (self.targetHoop.x - startX) / 50 + (Math.random() - 0.5) * 8; ball.velocityY = -16 - Math.random() * 8; } basketballs.push(ball); game.addChild(ball); // Create reflection var reflection = new BallReflection(); reflection.parentBall = ball; ballReflections.push(reflection); game.addChild(reflection); // Add rotation tween(ball, { rotation: ball.rotation + Math.PI * 3 }, { duration: 1200, easing: tween.easeOut }); self.lastShotTime = LK.ticks; }; return self; }); var BallReflection = Container.expand(function () { var self = Container.call(this); var basketballAsset = getBasketballAsset(); var reflectionGraphics = self.attachAsset(basketballAsset, { anchorX: 0.5, anchorY: 0.5 }); // Make reflection more transparent and darker reflectionGraphics.alpha = 0.3; reflectionGraphics.tint = 0x666666; // Flip reflection vertically reflectionGraphics.scaleY = -0.8; // Flipped and slightly smaller reflectionGraphics.scaleX = 0.8; // Set z-index to render on floor reflectionGraphics.zIndex = -3; self.parentBall = null; self.floorY = 1832; // Move floor up 900 pixels (700 + 200) self.update = function () { if (!self.parentBall || !self.parentBall.isActive) { self.destroy(); return; } // Position reflection below the ball self.x = self.parentBall.x; self.y = self.floorY - (self.floorY - self.parentBall.y) * 0.2; // Reflection distance from floor // Match parent ball rotation self.rotation = self.parentBall.rotation; // Fade reflection based on ball height var heightFactor = Math.max(0, (self.floorY - self.parentBall.y) / 1000); reflectionGraphics.alpha = 0.3 * heightFactor; }; return self; }); var Basketball = Container.expand(function () { var self = Container.call(this); var basketballAsset = getBasketballAsset(); var ballGraphics = self.attachAsset(basketballAsset, { anchorX: 0.5, anchorY: 0.5 }); // Set z-index to render in front of player1 ballGraphics.zIndex = 2; self.velocityX = 0; self.velocityY = 0; self.gravity = 0.5; self.bounceDecay = 0.7; self.hasScored = false; self.isActive = true; self.guaranteedSwish = false; self.update = function () { if (!self.isActive) return; // Add fire effect when streak is beyond 5 if (currentStreak > 5 && !self.fireEffect) { self.fireEffect = true; // Create fire-like effect with orange/red tinting and scaling var _fireAnimation = function fireAnimation() { if (!self.isActive) return; var fireColors = [0xFF4500, 0xFF6347, 0xFF8C00, 0xFFD700, 0xFF0000]; var randomColor = fireColors[Math.floor(Math.random() * fireColors.length)]; tween(ballGraphics, { tint: randomColor, scaleX: 1.1 + Math.random() * 0.2, scaleY: 1.1 + Math.random() * 0.2 }, { duration: 100 + Math.random() * 100, easing: tween.easeInOut, onFinish: function onFinish() { if (self.isActive && currentStreak > 5) { _fireAnimation(); } else { // Reset to normal appearance when streak drops tween(ballGraphics, { tint: 0xFFFFFF, scaleX: 1.0, scaleY: 1.0 }, { duration: 200, easing: tween.easeOut }); self.fireEffect = false; } } }); }; _fireAnimation(); } self.velocityY += self.gravity; self.x += self.velocityX; self.y += self.velocityY; // Check hoop collision for all hoops var hoopsToCheck = [hoop]; if (typeof leftHoop !== 'undefined') { hoopsToCheck.push(leftHoop); } if (typeof rightHoop !== 'undefined') { hoopsToCheck.push(rightHoop); } for (var hoopIndex = 0; hoopIndex < hoopsToCheck.length; hoopIndex++) { var currentHoop = hoopsToCheck[hoopIndex]; if (currentHoop) { var hoopX = currentHoop.x; var hoopY = currentHoop.y - 350; // Adjust for hoop position within container var relativeX = self.x - hoopX; var relativeY = self.y - hoopY; // Check for scoring through hoop first (ball going through net area) // For guaranteed swish shots, use much more lenient detection var hoopDetectionWidth = self.guaranteedSwish ? 120 : 60; var hoopDetectionTop = self.guaranteedSwish ? -35 : -10; var hoopDetectionBottom = self.guaranteedSwish ? 80 : 50; if (Math.abs(relativeX) <= hoopDetectionWidth && relativeY >= hoopDetectionTop && relativeY <= hoopDetectionBottom && self.velocityY > 0 && !self.hasScored) { // Ball is going through hoop - animate net and score self.hasScored = true; self.isActive = false; // Set ball to render behind net and hoop ballGraphics.zIndex = -2; // Animate ball going through and down tween(self, { y: self.y + 100, x: hoopX + (Math.random() - 0.5) * 20 }, { duration: 500, easing: tween.easeIn }); // Animate net pulsate tween(currentHoop.net, { scaleX: 1.8, scaleY: 1.8 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(currentHoop.net, { scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeIn }); } }); // Replace net with onfire asset when streak is beyond 5 if (currentStreak > 5) { // Check if onfire asset doesn't already exist on this net if (!currentHoop.onfire) { // Hide the original net currentHoop.net.visible = false; currentHoop.onfire = currentHoop.addChild(LK.getAsset('Onfire', { anchorX: 0.5, anchorY: 0.5, scaleX: currentHoop.net.scaleX, scaleY: currentHoop.net.scaleY })); currentHoop.onfire.x = currentHoop.net.x; // Same as net currentHoop.onfire.y = currentHoop.net.y + 150; // Move down 150 pixels from net position (down 20 from previous) currentHoop.onfire.zIndex = 3; // Above net currentHoop.onfire.alpha = 1.0; // Play onfire sound when onfire asset replaces net LK.getSound('Onfire').play(); } // Animate onfire asset pulsate when scored if (currentHoop.onfire) { //{1u_new} tween(currentHoop.onfire, { scaleX: 2.0, scaleY: 2.0, alpha: 1.0 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { if (currentHoop.onfire) { //{1C_new} tween(currentHoop.onfire, { scaleX: 1.5, scaleY: 1.5, alpha: 0.9 }, { duration: 200, easing: tween.easeIn }); } //{1L_new} } }); } //{1M_new} // Animate onfire asset to make it look on fire var _onfireAnimation = function onfireAnimation() { if (!currentHoop.onfire || currentStreak <= 5) return; var fireColors = [0xFFFFFF, 0xFFFF00, 0xFFA500, 0xFF6347, 0xFF4500, 0xFF0000]; var randomColor = fireColors[Math.floor(Math.random() * fireColors.length)]; tween(currentHoop.onfire, { tint: randomColor, scaleX: 1.0 + Math.random() * 0.3, scaleY: 1.0 + Math.random() * 0.3, alpha: 0.9 + Math.random() * 0.1 }, { duration: 100 + Math.random() * 100, easing: tween.easeInOut, onFinish: function onFinish() { if (currentHoop.onfire && currentStreak > 5) { _onfireAnimation(); } else if (currentHoop.onfire && currentStreak <= 5) { // Remove onfire effect when streak is over and show net currentHoop.net.visible = true; currentHoop.onfire.destroy(); currentHoop.onfire = null; } } }); }; _onfireAnimation(); } // Score the basket // Check if this is an AI shot if (self.isAIShot && self.aiOpponent) { // AI scored - increment AI score self.aiOpponent.score += 2; if (aiScoreTxt) { aiScoreTxt.setText('AI: ' + self.aiOpponent.score); } // Early return to prevent AI shots from affecting player scores return; } else { // Player scored - increment player streak currentStreak++; } // Check for streak rewards var moneyEarned = 0; if (currentStreak === 10 && streakRewardsAwarded.indexOf(10) === -1) { moneyEarned = 20.00; streakRewardsAwarded.push(10); } else if (currentStreak === 20 && streakRewardsAwarded.indexOf(20) === -1) { moneyEarned = 50.00; streakRewardsAwarded.push(20); } else if (currentStreak === 30 && streakRewardsAwarded.indexOf(30) === -1) { moneyEarned = 75.00; streakRewardsAwarded.push(30); } else if (currentStreak === 50 && streakRewardsAwarded.indexOf(50) === -1) { moneyEarned = 100.00; streakRewardsAwarded.push(50); } if (moneyEarned > 0) { currentMoney += moneyEarned; storage.money = currentMoney; if (moneyTxt) { moneyTxt.setText('$' + currentMoney.toFixed(2)); } LK.getSound('Cash').play(); // Play cash sound when money is awarded } var points = 2; if (self.isPerfectShot) { // Use cycling color for perfect shot var flashColor = basketColors[currentColorIndex]; } // 2x multiplier removed - no longer applied when all backboards are same color // Apply rhythm multiplier if in rhythm mode if (typeof rhythmMultiplier !== 'undefined' && rhythmMultiplier > 1) { points = Math.floor(points * rhythmMultiplier); } LK.setScore(LK.getScore() + points); // In rhythm mode, check if score reached multiple of 50 points to reset timer if (gameMode === 'rhythm') { var currentScore = LK.getScore(); var previousScore = currentScore - points; var currentFifties = Math.floor(currentScore / 50); var previousFifties = Math.floor(previousScore / 50); if (currentFifties > previousFifties) { gameTimer = 15 * 60; // Reset to 15 seconds for rhythm mode at 60 FPS gameTimeLeft = 15; updateTimerDisplay(15); } } // Play different sound based on which hoop scored if (currentHoop === leftHoop) { LK.getSound('1').play(); } else if (currentHoop === rightHoop) { LK.getSound('3').play(); } else { LK.getSound('2').play(); } if (scoreTxt) { scoreTxt.setText('Score: ' + LK.getScore()); } if (streakTxt) { //{3W_new} streakTxt.setText('Streak: ' + currentStreak); } //{3W_end} // Animate backboard color change var backboard = currentHoop.children[0]; // Get the backboard (first child) if (self.isPerfectShot) { // For perfect shots, use cycling color directly var flashColor = basketColors[currentColorIndex]; // Cycle to next color for next basket currentColorIndex = (currentColorIndex + 1) % basketColors.length; // Track which backboard was scored on and update color tracking var hoopIndex = 0; // Default to center hoop if (currentHoop === leftHoop) hoopIndex = 1; if (currentHoop === rightHoop) hoopIndex = 2; backboardColors[hoopIndex] = flashColor; tween(backboard, { tint: flashColor }, { duration: 300, easing: tween.easeOut }); // Check if all backboards now have same color checkAllBackboardsSameColor(); // Play different sound based on which hoop scored when backboard changes color if (currentHoop === leftHoop) { LK.getSound('1').play(); } else if (currentHoop === rightHoop) { LK.getSound('3').play(); } else { LK.getSound('2').play(); } } else { // For regular shots, use cycling color directly var flashColor = basketColors[currentColorIndex]; // Cycle to next color for next basket currentColorIndex = (currentColorIndex + 1) % basketColors.length; // Track which backboard was scored on and update color tracking var hoopIndex = 0; // Default to center hoop if (currentHoop === leftHoop) hoopIndex = 1; if (currentHoop === rightHoop) hoopIndex = 2; backboardColors[hoopIndex] = flashColor; tween(backboard, { tint: flashColor }, { duration: 300, easing: tween.easeOut }); // Check if all backboards now have same color checkAllBackboardsSameColor(); // Play different sound based on which hoop scored when backboard changes color if (currentHoop === leftHoop) { LK.getSound('1').play(); } else if (currentHoop === rightHoop) { LK.getSound('3').play(); } else { LK.getSound('2').play(); } } return; } // Check if ball is hitting the hoop rim if (relativeX >= -125 && relativeX <= 125 && relativeY >= -25 && relativeY <= 25) { // Determine which side of the hoop was hit if (Math.abs(relativeX) > 90) { // Hit the sides of the rim self.velocityX = -self.velocityX * self.bounceDecay; if (relativeX < 0) { self.x = hoopX - 125; } else { self.x = hoopX + 125; } LK.getSound('bounce').play(); } else if (relativeY >= -25 && relativeY <= 0 && self.velocityY > 0) { // Hit the top of the rim (bouncing up) self.velocityY = -Math.abs(self.velocityY) * self.bounceDecay; self.y = hoopY - 25; self.velocityX *= 0.8; // Reduce horizontal velocity slightly LK.getSound('bounce').play(); } } // Check if ball is resting on the rim (low velocity and on top) if (Math.abs(relativeX) <= 90 && relativeY >= -30 && relativeY <= -20 && Math.abs(self.velocityY) < 2 && Math.abs(self.velocityX) < 3) { // Ball is resting on rim, make it roll into the hoop self.isActive = false; // Stop normal physics self.hasScored = true; // Mark as scored // Set ball to render behind net and hoop ballGraphics.zIndex = -2; // Animate rolling into hoop tween(self, { x: hoopX, y: hoopY + 40, rotation: self.rotation + Math.PI * 2 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { // Animate net pulsate tween(currentHoop.net, { scaleX: 1.8, scaleY: 1.8 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(currentHoop.net, { scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeIn }); } }); // Replace net with onfire asset when streak is beyond 5 if (currentStreak > 5) { // Check if onfire asset doesn't already exist on this net if (!currentHoop.onfire) { // Hide the original net currentHoop.net.visible = false; currentHoop.onfire = currentHoop.addChild(LK.getAsset('Onfire', { anchorX: 0.5, anchorY: 0.5, scaleX: currentHoop.net.scaleX, scaleY: currentHoop.net.scaleY })); currentHoop.onfire.x = currentHoop.net.x; // Same as net currentHoop.onfire.y = currentHoop.net.y + 150; // Move down 150 pixels from net position (down 20 from previous) currentHoop.onfire.zIndex = 3; // Above net currentHoop.onfire.alpha = 1.0; // Play onfire sound when onfire asset replaces net LK.getSound('Onfire').play(); } // Animate onfire asset pulsate when scored if (currentHoop.onfire) { //{4L_new} tween(currentHoop.onfire, { scaleX: 2.0, scaleY: 2.0, alpha: 1.0 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { if (currentHoop.onfire) { //{4T_new} tween(currentHoop.onfire, { scaleX: 1.5, scaleY: 1.5, alpha: 0.9 }, { duration: 200, easing: tween.easeIn }); } //{52_new} } }); } //{53_new} // Animate onfire asset to make it look on fire var _onfireAnimation = function onfireAnimation() { if (!currentHoop.onfire || currentStreak <= 5) return; var fireColors = [0xFFFFFF, 0xFFFF00, 0xFFA500, 0xFF6347, 0xFF4500, 0xFF0000]; var randomColor = fireColors[Math.floor(Math.random() * fireColors.length)]; tween(currentHoop.onfire, { tint: randomColor, scaleX: 1.0 + Math.random() * 0.3, scaleY: 1.0 + Math.random() * 0.3, alpha: 0.9 + Math.random() * 0.1 }, { duration: 100 + Math.random() * 100, easing: tween.easeInOut, onFinish: function onFinish() { if (currentHoop.onfire && currentStreak > 5) { _onfireAnimation(); } else if (currentHoop.onfire && currentStreak <= 5) { // Remove onfire effect when streak is over and show net currentHoop.net.visible = true; currentHoop.onfire.destroy(); currentHoop.onfire = null; } } }); }; _onfireAnimation(); } // Score the basket // Check if this is an AI shot if (self.isAIShot && self.aiOpponent) { // AI scored - increment AI score self.aiOpponent.score += 2; if (aiScoreTxt) { aiScoreTxt.setText('AI: ' + self.aiOpponent.score); } return; // Early return to prevent AI shots from affecting player scores } else { // Player scored - increment player streak currentStreak++; } // Check for streak rewards if (currentStreak === 10 && streakRewardsAwarded.indexOf(10) === -1) { currentMoney += 20.00; storage.money = currentMoney; if (moneyTxt) { moneyTxt.setText('$' + currentMoney.toFixed(2)); } streakRewardsAwarded.push(10); LK.getSound('Cash').play(); // Play cash sound when money is awarded } else if (currentStreak === 20 && streakRewardsAwarded.indexOf(20) === -1) { currentMoney += 50.00; storage.money = currentMoney; if (moneyTxt) { moneyTxt.setText('$' + currentMoney.toFixed(2)); } streakRewardsAwarded.push(20); LK.getSound('Cash').play(); // Play cash sound when money is awarded } else if (currentStreak === 30 && streakRewardsAwarded.indexOf(30) === -1) { currentMoney += 75.00; storage.money = currentMoney; if (moneyTxt) { moneyTxt.setText('$' + currentMoney.toFixed(2)); } streakRewardsAwarded.push(30); LK.getSound('Cash').play(); // Play cash sound when money is awarded } else if (currentStreak === 50 && streakRewardsAwarded.indexOf(50) === -1) { currentMoney += 100.00; storage.money = currentMoney; if (moneyTxt) { moneyTxt.setText('$' + currentMoney.toFixed(2)); } streakRewardsAwarded.push(50); LK.getSound('Cash').play(); // Play cash sound when money is awarded } var points = 2; // 2x multiplier removed - no longer applied when all backboards are same color LK.setScore(LK.getScore() + points); // In rhythm mode, check if score reached multiple of 50 points to reset timer if (gameMode === 'rhythm') { var currentScore = LK.getScore(); var previousScore = currentScore - points; var currentFifties = Math.floor(currentScore / 50); var previousFifties = Math.floor(previousScore / 50); if (currentFifties > previousFifties) { gameTimer = 15 * 60; // Reset to 15 seconds for rhythm mode at 60 FPS gameTimeLeft = 15; updateTimerDisplay(15); } } // Play different sound based on which hoop scored if (currentHoop === leftHoop) { LK.getSound('1').play(); } else if (currentHoop === rightHoop) { LK.getSound('3').play(); } else { LK.getSound('2').play(); } // Update displays if (scoreTxt) { scoreTxt.setText('Score: ' + LK.getScore()); } if (streakTxt) { //{7w_new} streakTxt.setText('Streak: ' + currentStreak); } //{7w_end} // Animate backboard color change var backboard = currentHoop.children[0]; // Get the backboard (first child) var flashColor = basketColors[currentColorIndex]; // Cycle to next color for next basket currentColorIndex = (currentColorIndex + 1) % basketColors.length; // Track which backboard was scored on and update color tracking var hoopIndex = 0; // Default to center hoop if (currentHoop === leftHoop) hoopIndex = 1; if (currentHoop === rightHoop) hoopIndex = 2; backboardColors[hoopIndex] = flashColor; tween(backboard, { tint: flashColor }, { duration: 300, easing: tween.easeOut }); // Check if all backboards now have same color checkAllBackboardsSameColor(); // Play different sound based on which hoop scored when backboard changes color if (currentHoop === leftHoop) { LK.getSound('1').play(); } else if (currentHoop === rightHoop) { LK.getSound('3').play(); } else { LK.getSound('2').play(); } } }); } } } // Ground collision removed - ball can fall through // Remove if off screen - ball is just removed, no streak penalty if (self.x < -100 || self.x > 2148 || self.y > 2800) { self.isActive = false; } }; return self; }); var Hoop = Container.expand(function () { var self = Container.call(this); var backboard = self.attachAsset('backboard', { anchorX: 0.5, anchorY: 1 }); backboard.y = -20; var hoop = self.attachAsset('hoop', { anchorX: 0.5, anchorY: 0.5 }); hoop.y = -350; // Set z-index to render in front of basketball hoop.zIndex = 1; var net = self.attachAsset('net', { anchorX: 0.5, anchorY: 0, scaleX: 1.5, scaleY: 1.5 }); net.y = -325; net.alpha = 0.8; // Set z-index to render in front of basketball net.zIndex = 2; // Store net reference for animation access self.net = net; self.hoopBounds = { left: -90, right: 90, top: -20, bottom: 20 }; // Enable z-index sorting for proper rendering order self.sortableChildren = true; return self; }); var RhythmCircle = Container.expand(function () { var self = Container.call(this); // Create circle graphic using greenBall asset with scale and tint for rhythm indicator var circleGraphics = self.attachAsset('greenBall', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); circleGraphics.tint = 0xFF6B6B; // Pink tint for rhythm circles circleGraphics.alpha = 0.8; // Set z-index to render above most elements circleGraphics.zIndex = 15; self.fallSpeed = 6; self.isActive = true; self.targetShotBar = null; // Which shot bar this circle is aligned with self.wasInGreenZone = false; self.hasPassed = false; self.hasBeenTapped = false; // Track if this circle has already triggered a shot // Store the Y position of the green zone for this circle's target shot bar self.greenZoneY = 0; self.update = function () { if (!self.isActive) return; // Fall downward self.y += self.fallSpeed; // Check if circle has reached the green zone area of target shot bar if (self.targetShotBar && self.targetShotBar.children && self.targetShotBar.children.length > 2) { var greenZone = self.targetShotBar.children[1]; // Second child should be green zone var indicator = self.targetShotBar.children[2]; // Third child is the basketball indicator var shotBarWorldY = self.targetShotBar.y; // Shot bar's world Y position var tolerance = 60; // Match the green zone tolerance // Check if circle is in the green zone area (aligned with shot bar position) var inGreenZone = Math.abs(self.y - shotBarWorldY) <= tolerance; if (inGreenZone && !self.wasInGreenZone) { self.wasInGreenZone = true; // Store the green zone Y position for this circle self.greenZoneY = shotBarWorldY; // Pulse effect when entering green zone tween(circleGraphics, { scaleX: 1.6, scaleY: 1.6, alpha: 1.0 }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { tween(circleGraphics, { scaleX: 1.2, scaleY: 1.2, alpha: 0.8 }, { duration: 150, easing: tween.easeIn }); } }); } // Check if circle has passed the green zone if (self.y > shotBarWorldY + tolerance && !self.hasPassed) { self.hasPassed = true; } } // Remove if off screen if (self.y > 2800) { self.isActive = false; } }; return self; }); var ShotBar = Container.expand(function () { var self = Container.call(this); if (gameMode === 'rhythm') { // In rhythm mode, create horizontal tap zone instead of vertical shot bar var tapZone = self.attachAsset('shotBarBg', { anchorX: 0.5, anchorY: 0.5 }); // Keep horizontal orientation for tap zone tapZone.scaleX = 1.2; // Make it wider for easier tapping tapZone.scaleY = 2.0; // Make it taller for easier tapping tapZone.tint = 0x00FF00; // Green color for tap zone tapZone.alpha = 0.7; // Semi-transparent } else { // Swish mode: vertical shot bar (original implementation) var bgBar = self.attachAsset('shotBarBg', { anchorX: 0.5, anchorY: 0.5 }); bgBar.rotation = Math.PI / 2 + Math.PI; // Rotate 90 degrees + 180 degrees to make vertical and flip // Green zone - rotated to be vertical var greenZone = self.attachAsset('shotBarGreen', { anchorX: 0.5, anchorY: 0.5 }); greenZone.rotation = Math.PI / 2 + Math.PI; // Rotate 90 degrees + 180 degrees to make vertical and flip greenZone.y = 0; // Start at center, will move vertically // Moving basketball indicator var basketballAsset = getBasketballAsset(); var indicator = self.attachAsset(basketballAsset, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6 }); self.greenZone = greenZone; self.indicator = indicator; } self.isActive = false; self.isMoving = false; self.moveDirection = 1; // 1 for right, -1 for left self.moveSpeed = 8; self.maxDistance = 240; // Half of bar width minus indicator size self.perfectShot = false; self.startMoving = function () { if (gameMode === 'rhythm') { // In rhythm mode, tap zone is always active and visible self.isActive = true; self.visible = true; return; } // Swish mode logic self.isActive = true; self.isMoving = true; self.perfectShot = false; // Position green zone randomly vertically if (self.greenZone) { self.greenZone.y = (Math.random() - 0.5) * 360; // Random position within vertical bar } // Reset indicator position vertically - start at top if (self.indicator) { self.indicator.y = -self.maxDistance; } self.moveDirection = 1; // Start moving downward self.visible = true; }; self.stopMoving = function () { if (gameMode === 'rhythm') { // In rhythm mode, always return perfect shot for tap zone self.perfectShot = true; return true; } // Swish mode logic self.isMoving = false; // Check if indicator is within green zone vertically if (self.greenZone && self.indicator) { var greenTop = self.greenZone.y - 60; var greenBottom = self.greenZone.y + 60; self.perfectShot = self.indicator.y >= greenTop && self.indicator.y <= greenBottom; } // Reset streak if player misses the green zone if (!self.perfectShot) { currentStreak = 0; if (streakTxt) { //{9z_new} streakTxt.setText('Streak: ' + currentStreak); } //{9z_end} streakRewardsAwarded = []; // Reset streak rewards // Remove onfire effects from all nets when streak is reset and show nets if (hoop && hoop.onfire) { hoop.net.visible = true; hoop.onfire.destroy(); hoop.onfire = null; } if (leftHoop && leftHoop.onfire) { leftHoop.net.visible = true; leftHoop.onfire.destroy(); leftHoop.onfire = null; } if (rightHoop && rightHoop.onfire) { rightHoop.net.visible = true; rightHoop.onfire.destroy(); rightHoop.onfire = null; } } // Keep shot bar visible and restart movement after a brief pause var self_ref = self; LK.setTimeout(function () { self_ref.startMoving(); }, 200); return self.perfectShot; }; self.update = function () { if (gameMode === 'rhythm' || !self.isMoving) return; // Pause shot bar movement during break in swish mode if (isInBreak && gameMode === 'swish') { return; // Pause all shot bar movement during break } // Speed is now increased by break count instead of score var currentSpeed = self.moveSpeed; // Speed increase based on break count (number of breaks completed) var breakMultiplier = Math.floor(swishModeTimerReduction / 5); // Each break reduces timer by 5 seconds if (breakMultiplier > 0 && (!isInBreak || gameMode !== 'swish')) { currentSpeed = self.moveSpeed * (1 + breakMultiplier * 0.5); // 50% speed increase per break } // Move indicator back and forth vertically if (self.indicator) { self.indicator.y += currentSpeed * self.moveDirection; // Bounce off edges if (self.indicator.y >= self.maxDistance) { self.indicator.y = self.maxDistance; self.moveDirection = -1; } else if (self.indicator.y <= -self.maxDistance) { self.indicator.y = -self.maxDistance; self.moveDirection = 1; } } }; self.visible = true; return self; }); // Title screen is now initialized - gameplay will be initialized when start is pressed var Store = Container.expand(function () { var self = Container.call(this); // Add shop backdrop to the store var shopBackdrop = self.attachAsset('Shopbackdrop', { anchorX: 0, anchorY: 0 }); shopBackdrop.x = 0; shopBackdrop.y = 0; shopBackdrop.width = 2048; shopBackdrop.height = 2732; shopBackdrop.zIndex = -1; // Store items configuration self.items = [{ id: 'pacersball', name: 'Pacers Ball', price: 500.00, asset: 'Bballpacers', unlocked: false }, { id: 'thunderball', name: 'Thunder Ball', price: 750.00, asset: 'Bballthunder', unlocked: false }, { id: '2playvs', name: '2 Player Rhythm Pack', price: 500.00, asset: '2playvs', unlocked: false }, { id: 'swish2playvs', name: '2 Player Swish Pack', price: 500.00, asset: '2playvs', unlocked: false }, { //{aq_new} id: 'aibattle', name: 'AI Battle Pack', price: 500.00, asset: 'Aibattle', unlocked: false }]; // Load unlocked items from storage self.loadUnlockedItems = function () { for (var i = 0; i < self.items.length; i++) { var item = self.items[i]; item.unlocked = storage[item.id + '_unlocked'] || false; } }; // Save unlocked item to storage self.saveUnlockedItem = function (itemId) { storage[itemId + '_unlocked'] = true; }; // Check if player can afford item self.canAfford = function (item) { return currentMoney >= item.price; }; // Purchase item self.purchaseItem = function (item) { if (!self.canAfford(item) || item.unlocked) { return false; } // Deduct money currentMoney -= item.price; storage.money = currentMoney; // Unlock item item.unlocked = true; self.saveUnlockedItem(item.id); // Play purchase sound LK.getSound('Cash').play(); return true; }; // Get item by id self.getItem = function (itemId) { for (var i = 0; i < self.items.length; i++) { if (self.items[i].id === itemId) { return self.items[i]; } } return null; }; // Check if item is unlocked self.isUnlocked = function (itemId) { var item = self.getItem(itemId); return item ? item.unlocked : false; }; // Initialize store self.loadUnlockedItems(); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ // Load saved data from storage or use defaults currentMoney = storage.money || 0; swishBestScore = storage.swishBestScore || 0; rhythmBestScore = storage.rhythmBestScore || 0; // Load saved basketball mode and players var currentBasketballMode = storage.currentBasketballMode || defaultBasketballMode; if (storage.defaultPlayers) { defaultPlayers = storage.defaultPlayers; } // Create global store instance var gameStore = new Store(); function showHowToPlay() { // Create background using TitleBackground asset var background = game.addChild(LK.getAsset('TitleBackground', { anchorX: 0, anchorY: 0 })); background.x = 0; background.y = 0; background.width = 2048; background.height = 2732; background.zIndex = 49; // Create semi-transparent overlay var overlay = game.addChild(LK.getAsset('Player4', { anchorX: 0, anchorY: 0, scaleX: 20.48, scaleY: 27.32 })); overlay.x = 0; overlay.y = 0; overlay.tint = 0x000000; overlay.alpha = 0.6; overlay.zIndex = 50; // Create instructions text var instructionsText = new Text2('HOW TO PLAY\n\n' + 'SWISH MODE:\n' + '• Tap to shoot basketballs\n' + '• Hit perfect timing for swish shots\n' + '• Score baskets to increase streak\n' + '• Match backboard colors for bonus\n' + '• Unlock new players with money\n\n' + 'RHYTHM MODE:\n' + '• Tap falling circles in the green zones\n' + '• Perfect timing gives bonus points\n' + '• Maintain rhythm for multipliers\n\n' + 'TAP TO CLOSE', { size: 80, fill: 0xFFFFFF }); instructionsText.anchor.set(0.5, 0.5); instructionsText.x = 1024; instructionsText.y = 1366; instructionsText.zIndex = 51; game.addChild(instructionsText); // Store references for cleanup game.instructionsBackground = background; game.instructionsOverlay = overlay; game.instructionsText = instructionsText; } function hideHowToPlay() { if (game.instructionsBackground) { game.instructionsBackground.destroy(); game.instructionsBackground = null; } if (game.instructionsOverlay) { game.instructionsOverlay.destroy(); game.instructionsOverlay = null; } if (game.instructionsText) { game.instructionsText.destroy(); game.instructionsText = null; } } function showStore() { // Create store background using Shopbackdrop asset var storeBackground = game.addChild(LK.getAsset('Shopbackdrop', { anchorX: 0, anchorY: 0 })); storeBackground.x = 0; storeBackground.y = 0; storeBackground.width = 2048; storeBackground.height = 2732; storeBackground.zIndex = 49; // Create store title text var storeTitle = new Text2('STORE', { size: 120, fill: 0xFFFFFF }); storeTitle.anchor.set(0.5, 0.5); storeTitle.x = 1024; storeTitle.y = 500; storeTitle.zIndex = 51; game.addChild(storeTitle); // Create money display var storeMoneyText = new Text2('Money: $' + currentMoney.toFixed(2), { size: 80, fill: 0x00FF00 }); storeMoneyText.anchor.set(0.5, 0.5); storeMoneyText.x = 1024; storeMoneyText.y = 600; storeMoneyText.zIndex = 51; game.addChild(storeMoneyText); // Create pacersball item var pacersballItem = gameStore.getItem('pacersball'); if (pacersballItem) { // Create item image var itemImage = game.addChild(LK.getAsset('Bballpacers', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 })); itemImage.x = 354; itemImage.y = 1200; itemImage.zIndex = 51; // Create item name text var itemNameText = new Text2('Team Pack: Pacers', { size: 60, fill: 0xFFFFFF }); itemNameText.anchor.set(0.5, 0.5); itemNameText.x = 354; itemNameText.y = 925; itemNameText.zIndex = 51; game.addChild(itemNameText); // Create price text var priceColor = gameStore.canAfford(pacersballItem) ? 0x00FF00 : 0xFF0000; var priceText = new Text2('$' + pacersballItem.price.toFixed(2), { size: 50, fill: priceColor }); priceText.anchor.set(0.5, 0.5); priceText.x = 354; priceText.y = 1350; priceText.zIndex = 51; game.addChild(priceText); // Create status text var statusText = new Text2(pacersballItem.unlocked ? 'TAP TO SELECT' : 'TAP TO BUY', { size: 40, fill: pacersballItem.unlocked ? 0x00FF00 : 0xFFFFFF }); statusText.anchor.set(0.5, 0.5); statusText.x = 354; statusText.y = 1050; statusText.zIndex = 51; game.addChild(statusText); // Store references for cleanup and purchase handling game.storeItemImage = itemImage; game.storeItemNameText = itemNameText; game.storeItemPriceText = priceText; game.storeItemStatusText = statusText; game.storeItem = pacersballItem; } // Create thunderball item var thunderballItem = gameStore.getItem('thunderball'); if (thunderballItem) { // Create item image var thunderItemImage = game.addChild(LK.getAsset('Bballthunder', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 })); thunderItemImage.x = 1694; thunderItemImage.y = 1200; thunderItemImage.zIndex = 51; // Create item name text var thunderItemNameText = new Text2('Team Pack: Thunder', { size: 60, fill: 0xFFFFFF }); thunderItemNameText.anchor.set(0.5, 0.5); thunderItemNameText.x = 1694; thunderItemNameText.y = 925; thunderItemNameText.zIndex = 51; game.addChild(thunderItemNameText); // Create price text var thunderPriceColor = gameStore.canAfford(thunderballItem) ? 0x00FF00 : 0xFF0000; var thunderPriceText = new Text2('$' + thunderballItem.price.toFixed(2), { size: 50, fill: thunderPriceColor }); thunderPriceText.anchor.set(0.5, 0.5); thunderPriceText.x = 1694; thunderPriceText.y = 1350; thunderPriceText.zIndex = 51; game.addChild(thunderPriceText); // Create status text var thunderStatusText = new Text2(thunderballItem.unlocked ? 'TAP TO SELECT' : 'TAP TO BUY', { size: 40, fill: thunderballItem.unlocked ? 0x00FF00 : 0xFFFFFF }); thunderStatusText.anchor.set(0.5, 0.5); thunderStatusText.x = 1694; thunderStatusText.y = 1050; thunderStatusText.zIndex = 51; game.addChild(thunderStatusText); // Store references for cleanup and purchase handling game.storeThunderItemImage = thunderItemImage; game.storeThunderItemNameText = thunderItemNameText; game.storeThunderItemPriceText = thunderPriceText; game.storeThunderItemStatusText = thunderStatusText; game.storeThunderItem = thunderballItem; } // Create Warriorsball item (default mode) var warriorsballImage = game.addChild(LK.getAsset('basketball', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 })); warriorsballImage.x = 1024; warriorsballImage.y = 1900; warriorsballImage.zIndex = 51; warriorsballImage.tint = 0xFFD700; // Gold tint for Warriors theme // Create item name text var warriorsItemNameText = new Text2('Team Pack: Warriors', { size: 60, fill: 0xFFFFFF }); warriorsItemNameText.anchor.set(0.5, 0.5); warriorsItemNameText.x = 1024; warriorsItemNameText.y = 1625; warriorsItemNameText.zIndex = 51; game.addChild(warriorsItemNameText); // Create status text var warriorsStatusText = new Text2('TAP TO SELECT', { size: 40, fill: 0x00FF00 }); warriorsStatusText.anchor.set(0.5, 0.5); warriorsStatusText.x = 1024; warriorsStatusText.y = 1750; warriorsStatusText.zIndex = 51; game.addChild(warriorsStatusText); // Store references for cleanup and selection handling game.storeWarriorsItemImage = warriorsballImage; game.storeWarriorsItemNameText = warriorsItemNameText; game.storeWarriorsItemStatusText = warriorsStatusText; // Create 2playvs pack item var twoPlayerVsItem = gameStore.getItem('2playvs'); if (twoPlayerVsItem) { // Create item image var twoPlayerVsItemImage = game.addChild(LK.getAsset('2playvs', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 })); twoPlayerVsItemImage.x = 324; twoPlayerVsItemImage.y = 2000; twoPlayerVsItemImage.zIndex = 51; twoPlayerVsItemImage.tint = 0x00FF00; // Green tint to match 2player rhythm mode button // Create item name text var twoPlayerVsItemNameText = new Text2('2 Player Rhythm Pack', { size: 60, fill: 0xFFFFFF }); twoPlayerVsItemNameText.anchor.set(0.5, 0.5); twoPlayerVsItemNameText.x = 324; twoPlayerVsItemNameText.y = 1725; twoPlayerVsItemNameText.zIndex = 51; game.addChild(twoPlayerVsItemNameText); // Create price text var twoPlayerVsPriceColor = gameStore.canAfford(twoPlayerVsItem) ? 0x00FF00 : 0xFF0000; var twoPlayerVsPriceText = new Text2('$' + twoPlayerVsItem.price.toFixed(2), { size: 50, fill: twoPlayerVsPriceColor }); twoPlayerVsPriceText.anchor.set(0.5, 0.5); twoPlayerVsPriceText.x = 324; twoPlayerVsPriceText.y = 2150; twoPlayerVsPriceText.zIndex = 51; game.addChild(twoPlayerVsPriceText); // Create status text var twoPlayerVsStatusText = new Text2(twoPlayerVsItem.unlocked ? 'UNLOCKED' : 'TAP TO BUY', { size: 40, fill: twoPlayerVsItem.unlocked ? 0x00FF00 : 0xFFFFFF }); twoPlayerVsStatusText.anchor.set(0.5, 0.5); twoPlayerVsStatusText.x = 324; twoPlayerVsStatusText.y = 1850; twoPlayerVsStatusText.zIndex = 51; game.addChild(twoPlayerVsStatusText); // Store references for cleanup and purchase handling game.store2PlayerVsItemImage = twoPlayerVsItemImage; game.store2PlayerVsItemNameText = twoPlayerVsItemNameText; game.store2PlayerVsItemPriceText = twoPlayerVsPriceText; game.store2PlayerVsItemStatusText = twoPlayerVsStatusText; game.store2PlayerVsItem = twoPlayerVsItem; } // Create swish2playvs pack item var swishTwoPlayerVsItem = gameStore.getItem('swish2playvs'); if (swishTwoPlayerVsItem) { // Create item image var swishTwoPlayerVsItemImage = game.addChild(LK.getAsset('2playvs', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 })); swishTwoPlayerVsItemImage.x = 1724; swishTwoPlayerVsItemImage.y = 2000; swishTwoPlayerVsItemImage.zIndex = 51; swishTwoPlayerVsItemImage.tint = 0x008080; // Teal and purple tint to match 2player swish mode button // Create item name text var swishTwoPlayerVsItemNameText = new Text2('2 Player Swish Pack', { size: 60, fill: 0xFFFFFF }); swishTwoPlayerVsItemNameText.anchor.set(0.5, 0.5); swishTwoPlayerVsItemNameText.x = 1724; swishTwoPlayerVsItemNameText.y = 1725; swishTwoPlayerVsItemNameText.zIndex = 51; game.addChild(swishTwoPlayerVsItemNameText); // Create price text var swishTwoPlayerVsPriceColor = gameStore.canAfford(swishTwoPlayerVsItem) ? 0x00FF00 : 0xFF0000; var swishTwoPlayerVsPriceText = new Text2('$' + swishTwoPlayerVsItem.price.toFixed(2), { size: 50, fill: swishTwoPlayerVsPriceColor }); swishTwoPlayerVsPriceText.anchor.set(0.5, 0.5); swishTwoPlayerVsPriceText.x = 1724; swishTwoPlayerVsPriceText.y = 2150; swishTwoPlayerVsPriceText.zIndex = 51; game.addChild(swishTwoPlayerVsPriceText); // Create status text var swishTwoPlayerVsStatusText = new Text2(swishTwoPlayerVsItem.unlocked ? 'UNLOCKED' : 'TAP TO BUY', { size: 40, fill: swishTwoPlayerVsItem.unlocked ? 0x00FF00 : 0xFFFFFF }); swishTwoPlayerVsStatusText.anchor.set(0.5, 0.5); swishTwoPlayerVsStatusText.x = 1724; swishTwoPlayerVsStatusText.y = 1850; swishTwoPlayerVsStatusText.zIndex = 51; game.addChild(swishTwoPlayerVsStatusText); // Store references for cleanup game.storeSwish2PlayerVsItemImage = swishTwoPlayerVsItemImage; game.storeSwish2PlayerVsItemNameText = swishTwoPlayerVsItemNameText; game.storeSwish2PlayerVsItemPriceText = swishTwoPlayerVsPriceText; game.storeSwish2PlayerVsItemStatusText = swishTwoPlayerVsStatusText; game.storeSwish2PlayerVsItem = swishTwoPlayerVsItem; } // Create aibattle pack item var aibattleItem = gameStore.getItem('aibattle'); if (aibattleItem) { // Create item image//{cH_new1} var aibattleItemImage = game.addChild(LK.getAsset('Aibattle', { anchorX: 0.5, //{cH_new2} anchorY: 0.5, //{cH_new3} scaleX: 0.6, //{cH_new4} scaleY: 0.6 //{cH_new5} })); //{cH_new6} aibattleItemImage.x = 1024; aibattleItemImage.y = 1200; aibattleItemImage.zIndex = 51; // Create item name text//{cH_new7} var aibattleItemNameText = new Text2('AI Battle Pack', { size: 60, //{cH_new8} fill: 0xFFFFFF //{cH_new9} }); //{cH_new10} aibattleItemNameText.anchor.set(0.5, 0.5); aibattleItemNameText.x = 1024; aibattleItemNameText.y = 925; aibattleItemNameText.zIndex = 51; game.addChild(aibattleItemNameText); // Create price text//{cH_new11} var aibattlePriceColor = gameStore.canAfford(aibattleItem) ? 0x00FF00 : 0xFF0000; var aibattlePriceText = new Text2('$' + aibattleItem.price.toFixed(2), { size: 50, //{cH_new12} fill: aibattlePriceColor }); //{cH_new13} aibattlePriceText.anchor.set(0.5, 0.5); aibattlePriceText.x = 1024; aibattlePriceText.y = 1350; aibattlePriceText.zIndex = 51; game.addChild(aibattlePriceText); // Create status text//{cH_new14} var aibattleStatusText = new Text2(aibattleItem.unlocked ? 'UNLOCKED' : 'TAP TO BUY', { size: 40, //{cH_new15} fill: aibattleItem.unlocked ? 0x00FF00 : 0xFFFFFF }); //{cH_new16} aibattleStatusText.anchor.set(0.5, 0.5); aibattleStatusText.x = 1024; aibattleStatusText.y = 1050; aibattleStatusText.zIndex = 51; game.addChild(aibattleStatusText); // Store references for cleanup and purchase handling//{cH_new17} game.storeAibattleItemImage = aibattleItemImage; game.storeAibattleItemNameText = aibattleItemNameText; game.storeAibattleItemPriceText = aibattlePriceText; game.storeAibattleItemStatusText = aibattleStatusText; game.storeAibattleItem = aibattleItem; } //{cH_new18} // Create close button text var closeButton = new Text2('TAP TO CLOSE', { size: 60, fill: 0xFFFFFF }); closeButton.anchor.set(0.5, 0.5); closeButton.x = 1024; closeButton.y = 2400; closeButton.zIndex = 51; game.addChild(closeButton); // Store references for cleanup game.storeBackground = storeBackground; game.storeTitle = storeTitle; game.storeMoneyText = storeMoneyText; game.storeCloseButton = closeButton; } function hideStore() { if (game.storeBackground) { game.storeBackground.destroy(); game.storeBackground = null; } if (game.storeTitle) { game.storeTitle.destroy(); game.storeTitle = null; } if (game.storeMoneyText) { game.storeMoneyText.destroy(); game.storeMoneyText = null; } if (game.storeCloseButton) { game.storeCloseButton.destroy(); game.storeCloseButton = null; } // Clean up store item elements (itemBg removed as it was never created) if (game.storeItemImage) { game.storeItemImage.destroy(); game.storeItemImage = null; } if (game.storeItemNameText) { game.storeItemNameText.destroy(); game.storeItemNameText = null; } if (game.storeItemPriceText) { game.storeItemPriceText.destroy(); game.storeItemPriceText = null; } if (game.storeItemStatusText) { game.storeItemStatusText.destroy(); game.storeItemStatusText = null; } game.storeItem = null; // Clean up thunder item elements if (game.storeThunderItemImage) { game.storeThunderItemImage.destroy(); game.storeThunderItemImage = null; } if (game.storeThunderItemNameText) { game.storeThunderItemNameText.destroy(); game.storeThunderItemNameText = null; } if (game.storeThunderItemPriceText) { game.storeThunderItemPriceText.destroy(); game.storeThunderItemPriceText = null; } if (game.storeThunderItemStatusText) { game.storeThunderItemStatusText.destroy(); game.storeThunderItemStatusText = null; } game.storeThunderItem = null; // Clean up warriors item elements if (game.storeWarriorsItemImage) { game.storeWarriorsItemImage.destroy(); game.storeWarriorsItemImage = null; } if (game.storeWarriorsItemNameText) { game.storeWarriorsItemNameText.destroy(); game.storeWarriorsItemNameText = null; } if (game.storeWarriorsItemStatusText) { game.storeWarriorsItemStatusText.destroy(); game.storeWarriorsItemStatusText = null; } // Clean up 2playvs pack elements if (game.store2PlayerVsItemImage) { game.store2PlayerVsItemImage.destroy(); game.store2PlayerVsItemImage = null; } if (game.store2PlayerVsItemNameText) { game.store2PlayerVsItemNameText.destroy(); game.store2PlayerVsItemNameText = null; } if (game.store2PlayerVsItemPriceText) { game.store2PlayerVsItemPriceText.destroy(); game.store2PlayerVsItemPriceText = null; } if (game.store2PlayerVsItemStatusText) { game.store2PlayerVsItemStatusText.destroy(); game.store2PlayerVsItemStatusText = null; } game.store2PlayerVsItem = null; // Clean up swish2playvs pack elements if (game.storeSwish2PlayerVsItemImage) { game.storeSwish2PlayerVsItemImage.destroy(); game.storeSwish2PlayerVsItemImage = null; } if (game.storeSwish2PlayerVsItemNameText) { game.storeSwish2PlayerVsItemNameText.destroy(); game.storeSwish2PlayerVsItemNameText = null; } if (game.storeSwish2PlayerVsItemPriceText) { game.storeSwish2PlayerVsItemPriceText.destroy(); game.storeSwish2PlayerVsItemPriceText = null; } if (game.storeSwish2PlayerVsItemStatusText) { game.storeSwish2PlayerVsItemStatusText.destroy(); game.storeSwish2PlayerVsItemStatusText = null; } game.storeSwish2PlayerVsItem = null; // Clean up aibattle pack elements if (game.storeAibattleItemImage) { game.storeAibattleItemImage.destroy(); game.storeAibattleItemImage = null; } //{dm_new1} if (game.storeAibattleItemNameText) { game.storeAibattleItemNameText.destroy(); game.storeAibattleItemNameText = null; } //{dm_new2} if (game.storeAibattleItemPriceText) { //{dm_new3} game.storeAibattleItemPriceText.destroy(); game.storeAibattleItemPriceText = null; } //{dm_new4} if (game.storeAibattleItemStatusText) { //{dm_new5} game.storeAibattleItemStatusText.destroy(); game.storeAibattleItemStatusText = null; } //{dm_new6} game.storeAibattleItem = null; } // Title screen is now initialized - gameplay will be initialized when start is pressed; var gameState = 'title'; // 'title', 'playing', 'modeSelect' var gameMode = 'swish'; // 'swish', 'rhythm', 'ai_vs', or '2player' var aiOpponent = null; // AI opponent instance var aiScoreTxt = null; // AI score display // 2 Player battle mode variables var twoPlayerState = 'player1'; // 'player1', 'transition', 'player2', 'results' var player1Score = 0; var player2Score = 0; var twoPlayerTimer = 90 * 60; // 90 seconds at 60 FPS var twoPlayerTimeLeft = 90; var currentPlayerTxt = null; var player1ScoreTxt = null; var player2ScoreTxt = null; var transitionOverlay = null; var transitionText = null; var transitionTimer = 0; var countdownActive = false; var countdownTimer = 0; var countdownContainer = null; // 2 Player rhythm mode variables var twoPlayerRhythmMode = false; var defaultBasketballMode = 'Warriorsball'; // Default basketball mode var defaultPlayers = ['player1', 'player2', 'player3']; // Default mode players var pacersMode = 'pacersball'; // Pacers mode basketball var pacersPlayers = ['player4', 'player5', 'player6']; // Pacers mode players var thunderMode = 'Thunderball'; // Thunder mode basketball var thunderPlayers = ['player7', 'player8', 'player9']; // Thunder mode players var modeSelectBackground = null; var swishButton = null; var rhythmButton = null; var titleBackground = null; var titleText = null; var startButton = null; var basketballs = []; var ballReflections = []; var hoop = null; var leftHoop = null; var rightHoop = null; var ground = null; var scoreTxt = null; var streakTxt = null; var timerTxt = null; var player1 = null; var player1down = null; var player2 = null; var player2down = null; var player3 = null; var player3down = null; var currentMoney = storage.money || 0; var moneyTxt = null; var multiplierTxt = null; var bestScore = 0; var bestScoreTxt = null; var swishBestScore = 0; var rhythmBestScore = 0; var currentStreak = 0; var streakRewardsAwarded = []; // Track which streak rewards have been given var swipeStartX = 0; var swipeStartY = 0; var swipeStartTime = 0; var isSwipeStarted = false; var lastShotTime = 0; var gameTimer = 60 * 60; // Will be set correctly in initializeGameplay var gameTimeLeft = 60; // Will be set correctly in initializeGameplay var gameEnded = false; var musicNotes = ['note1', 'note2', 'note3', 'note4', 'note5']; var currentNoteIndex = 0; var shotBar = null; var shotBar2 = null; var shotBar3 = null; var isChargingShot = false; // Color cycling system for backboard changes var basketColors = [0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF, 0xFFA500, 0x800080, 0xFFB6C1, 0x90EE90, 0x87CEEB, 0xDDA0DD]; var currentColorIndex = 0; // Track backboard colors for multiplier system var backboardColors = [0xFFFFFF, 0xFFFFFF, 0xFFFFFF]; // [hoop, leftHoop, rightHoop] - start with white var allSameColorMultiplier = false; var moneyAwarded = false; // Track if money has been awarded for current color match var player2Unlocked = true; var player3Unlocked = true; // Rhythm mode variables var beatInterval = 60; // 60 frames = 1 second at 60 FPS var lastBeatTime = 0; var beatTolerance = 10; // frames of tolerance for rhythm timing var rhythmStreak = 0; var beatIndicator = null; var rhythmMultiplier = 1; var rhythmCircles = []; var rhythmCircleSpawnTimer = 0; var rhythmCircleSpawnInterval = 29; // Spawn at 124 BPM (29 frames = ~124 beats per minute) var tapZoneGreenBalls = []; // Array to hold green balls in tap zones var volumeVisualizerBars = []; // Array to hold volume visualizer bars var musicStarted = false; // Track when music has started playing // Global timer variables var timerNumbers = []; // Break system variables for swish mode var isInBreak = false; var breakCountdown = 0; var breakCountdownNumbers = []; var speedIncreaseDelayed = false; var swishModeTimerReduction = 0; // Track how much to reduce timer each break // Function to swap player sprites based on current basketball mode function swapPlayerSprites() { if (!player1 || !player2 || !player3) return; // Safety check var player1Asset, player1downAsset, player2Asset, player2downAsset, player3Asset, player3downAsset; // Determine which assets to use based on current basketball mode if (currentBasketballMode === pacersMode) { // Use Pacers players (Player4, Player5, Player6) player1Asset = 'Player4'; player1downAsset = 'Player4down'; player2Asset = 'Player5'; player2downAsset = 'Player5down'; player3Asset = 'Player6'; player3downAsset = 'Player6down'; } else if (currentBasketballMode === thunderMode) { // Use Thunder players (Player7, Player8, Player9) player1Asset = 'Player7'; player1downAsset = 'Player7down'; player2Asset = 'Player8'; player2downAsset = 'Player8down'; player3Asset = 'Player9'; player3downAsset = 'Player9down'; } else { // Use Warriors players (Player1, Player2, Player3) - default player1Asset = 'Player1'; player1downAsset = 'Player1down'; player2Asset = 'Player2'; player2downAsset = 'Player2down'; player3Asset = 'Player3'; player3downAsset = 'Player3down'; } // Store current visibility states var player1Visible = player1.visible; var player2Visible = player2.visible; var player3Visible = player3.visible; var player1downVisible = player1down.visible; var player2downVisible = player2down.visible; var player3downVisible = player3down.visible; // Store current positions var player1X = player1.x, player1Y = player1.y; var player2X = player2.x, player2Y = player2.y; var player3X = player3.x, player3Y = player3.y; var player1downX = player1down.x, player1downY = player1down.y; var player2downX = player2down.x, player2downY = player2down.y; var player3downX = player3down.x, player3downY = player3down.y; // Remove existing player sprites if (player1) { player1.destroy(); } if (player1down) { player1down.destroy(); } if (player2) { player2.destroy(); } if (player2down) { player2down.destroy(); } if (player3) { player3.destroy(); } if (player3down) { player3down.destroy(); } // Create new player sprites with correct assets player1 = game.addChild(LK.getAsset(player1Asset, { anchorX: 0.5, anchorY: 1 })); player1.x = player1X; player1.y = player1Y; player1.zIndex = 1; player1.visible = player1Visible; player1down = game.addChild(LK.getAsset(player1downAsset, { anchorX: 0.5, anchorY: 1 })); player1down.x = player1downX; player1down.y = player1downY; player1down.zIndex = 1; player1down.visible = player1downVisible; player2 = game.addChild(LK.getAsset(player2Asset, { anchorX: 0.5, anchorY: 1 })); player2.x = player2X; player2.y = player2Y; player2.zIndex = 1; player2.visible = player2Visible; player2down = game.addChild(LK.getAsset(player2downAsset, { anchorX: 0.5, anchorY: 1 })); player2down.x = player2downX; player2down.y = player2downY; player2down.zIndex = 1; player2down.visible = player2downVisible; player3 = game.addChild(LK.getAsset(player3Asset, { anchorX: 0.5, anchorY: 1 })); player3.x = player3X; player3.y = player3Y; player3.zIndex = 1; player3.visible = player3Visible; player3down = game.addChild(LK.getAsset(player3downAsset, { anchorX: 0.5, anchorY: 1 })); player3down.x = player3downX; player3down.y = player3downY; player3down.zIndex = 1; player3down.visible = player3downVisible; } // Function to get basketball asset based on current basketball mode function getBasketballAsset() { if (currentBasketballMode === pacersMode) { return 'Bballpacers'; } else if (currentBasketballMode === thunderMode) { return 'Bballthunder'; } else { return 'basketball'; // Default Warriors mode } } // Function to start break countdown in swish mode function startBreakCountdown() { if (gameMode !== 'swish') return; // Check if this is the first break and player hasn't scored 60 points if (swishModeTimerReduction === 0 && LK.getScore() < 60) { // First break and score is below 60 - game over gameEnded = true; updateTimerDisplay(0); cleanupUIElements(); LK.showGameOver(); return; } // Check if this is the second break and player hasn't scored 120 points if (swishModeTimerReduction === 5 && LK.getScore() < 120) { // Second break and score is below 120 - game over gameEnded = true; updateTimerDisplay(0); cleanupUIElements(); LK.showGameOver(); return; } // Check if this is the third break and player hasn't scored 180 points if (swishModeTimerReduction === 10 && LK.getScore() < 180) { // Third break and score is below 180 - game over gameEnded = true; updateTimerDisplay(0); cleanupUIElements(); LK.showGameOver(); return; } // Check if this is the fourth break and player hasn't scored 240 points if (swishModeTimerReduction === 15 && LK.getScore() < 240) { // Fourth break and score is below 240 - game over gameEnded = true; updateTimerDisplay(0); cleanupUIElements(); LK.showGameOver(); return; } // Check if this is the fifth break and player hasn't scored 300 points if (swishModeTimerReduction === 20 && LK.getScore() < 300) { // Fifth break and score is below 300 - game over gameEnded = true; updateTimerDisplay(0); cleanupUIElements(); LK.showGameOver(); return; } // Check if this is the sixth break and player hasn't scored 360 points if (swishModeTimerReduction === 25 && LK.getScore() < 360) { // Sixth break and score is below 360 - game over gameEnded = true; updateTimerDisplay(0); cleanupUIElements(); LK.showGameOver(); return; } // Check if this is the seventh break and player hasn't scored 420 points if (swishModeTimerReduction === 30 && LK.getScore() < 420) { // Seventh break and score is below 420 - game over gameEnded = true; updateTimerDisplay(0); cleanupUIElements(); LK.showGameOver(); return; } isInBreak = true; breakCountdown = 5; speedIncreaseDelayed = false; // Increase timer reduction for next cycle (5 seconds each break) swishModeTimerReduction += 5; // Play speedup sound when 5-second countdown starts LK.getSound('Speedup').play(); // Create container for break countdown numbers var breakContainer = new Container(); breakContainer.x = 1024; // Center of screen breakContainer.y = 1366; // Middle of screen vertically breakContainer.zIndex = 100; // High z-index to appear on top game.addChild(breakContainer); // Create enlarged countdown numbers (5, 4, 3, 2, 1) updateBreakCountdown(); // Store container reference for cleanup game.breakContainer = breakContainer; } // Function to update break countdown display function updateBreakCountdown() { if (!isInBreak || !game.breakContainer) return; // Clear existing countdown numbers for (var i = 0; i < breakCountdownNumbers.length; i++) { if (breakCountdownNumbers[i]) { game.breakContainer.removeChild(breakCountdownNumbers[i]); breakCountdownNumbers[i].destroy(); } } breakCountdownNumbers = []; if (breakCountdown > 0) { // Create enlarged number asset for current countdown var numberAsset = LK.getAsset(breakCountdown.toString(), { anchorX: 0.5, anchorY: 0.5, scaleX: 3.0, // Enlarged scale scaleY: 3.0 }); numberAsset.x = 0; // Relative to container numberAsset.y = 0; numberAsset.alpha = 0; game.breakContainer.addChild(numberAsset); breakCountdownNumbers.push(numberAsset); // Animate number appearance with scale and fade tween(numberAsset, { alpha: 1.0, scaleX: 4.0, scaleY: 4.0 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Animate number disappearance tween(numberAsset, { alpha: 0, scaleX: 2.0, scaleY: 2.0 }, { duration: 700, easing: tween.easeIn }); } }); } } // Function to end break countdown function endBreakCountdown() { isInBreak = false; breakCountdown = 0; speedIncreaseDelayed = false; // Clean up break countdown display if (game.breakContainer) { for (var i = 0; i < breakCountdownNumbers.length; i++) { if (breakCountdownNumbers[i]) { breakCountdownNumbers[i].destroy(); } } breakCountdownNumbers = []; game.breakContainer.destroy(); game.breakContainer = null; } } // Function to swap basketball assets for existing basketballs function swapBasketballAssets() { var newAssetId = getBasketballAsset(); // Update existing basketballs for (var i = 0; i < basketballs.length; i++) { var ball = basketballs[i]; if (ball && ball.children && ball.children.length > 0) { var ballGraphics = ball.children[0]; // First child should be the basketball graphics if (ballGraphics) { // Store current properties var currentX = ballGraphics.x; var currentY = ballGraphics.y; var currentAnchorX = ballGraphics.anchor.x; var currentAnchorY = ballGraphics.anchor.y; var currentZIndex = ballGraphics.zIndex; var currentTint = ballGraphics.tint; var currentAlpha = ballGraphics.alpha; var currentScaleX = ballGraphics.scaleX; var currentScaleY = ballGraphics.scaleY; var currentRotation = ballGraphics.rotation; // Remove existing graphics ball.removeChild(ballGraphics); ballGraphics.destroy(); // Create new graphics with correct asset var newGraphics = ball.attachAsset(newAssetId, { anchorX: currentAnchorX, anchorY: currentAnchorY }); // Restore properties newGraphics.x = currentX; newGraphics.y = currentY; newGraphics.zIndex = currentZIndex; newGraphics.tint = currentTint; newGraphics.alpha = currentAlpha; newGraphics.scaleX = currentScaleX; newGraphics.scaleY = currentScaleY; newGraphics.rotation = currentRotation; } } } // Update existing ball reflections for (var i = 0; i < ballReflections.length; i++) { var reflection = ballReflections[i]; if (reflection && reflection.children && reflection.children.length > 0) { var reflectionGraphics = reflection.children[0]; // First child should be the reflection graphics if (reflectionGraphics) { // Store current properties var currentX = reflectionGraphics.x; var currentY = reflectionGraphics.y; var currentAnchorX = reflectionGraphics.anchor.x; var currentAnchorY = reflectionGraphics.anchor.y; var currentZIndex = reflectionGraphics.zIndex; var currentTint = reflectionGraphics.tint; var currentAlpha = reflectionGraphics.alpha; var currentScaleX = reflectionGraphics.scaleX; var currentScaleY = reflectionGraphics.scaleY; var currentRotation = reflectionGraphics.rotation; // Remove existing graphics reflection.removeChild(reflectionGraphics); reflectionGraphics.destroy(); // Create new graphics with correct asset var newReflectionGraphics = reflection.attachAsset(newAssetId, { anchorX: currentAnchorX, anchorY: currentAnchorY }); // Restore properties newReflectionGraphics.x = currentX; newReflectionGraphics.y = currentY; newReflectionGraphics.zIndex = currentZIndex; newReflectionGraphics.tint = currentTint; newReflectionGraphics.alpha = currentAlpha; newReflectionGraphics.scaleX = currentScaleX; newReflectionGraphics.scaleY = currentScaleY; newReflectionGraphics.rotation = currentRotation; } } } } // Global function to update timer display with number assets function updateTimerDisplay(timeLeft) { if (timerNumbers.length === 0) return; // Safety check // Display seconds only (2 digits) var digits = [Math.floor(timeLeft / 10), // Tens digit timeLeft % 10 // Units digit ]; for (var i = 0; i < timerNumbers.length && i < digits.length; i++) { var digitValue = digits[i].toString(); var newAsset = LK.getAsset(digitValue, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5 }); // Get the stored container reference var container = timerNumbers[i].parentContainer; if (container) { // Replace the existing number with new asset container.removeChild(timerNumbers[i]); newAsset.x = [-30, 30][i]; newAsset.y = 90; newAsset.parentContainer = container; // Store container reference timerNumbers[i] = newAsset; container.addChild(newAsset); } } } // Initialize title screen initializeTitleScreen(); function createBasketball(startX, startY, velocityX, velocityY) { var ball = new Basketball(); ball.x = startX; ball.y = startY; ball.velocityX = velocityX; ball.velocityY = velocityY; ball.isPerfectShot = false; basketballs.push(ball); game.addChild(ball); // Create reflection for this ball var reflection = new BallReflection(); reflection.parentBall = ball; ballReflections.push(reflection); game.addChild(reflection); return ball; } function checkBasketScore(ball) { // Scoring is now handled in Basketball class update method // This function is kept for compatibility but does nothing return; } // Function to clean up all UI elements from LK.gui function cleanupUIElements() { // Clean up all children from LK.gui containers if (LK.gui.top) { while (LK.gui.top.children.length > 0) { var child = LK.gui.top.children[0]; LK.gui.top.removeChild(child); child.destroy(); } } if (LK.gui.topLeft) { while (LK.gui.topLeft.children.length > 0) { var child = LK.gui.topLeft.children[0]; LK.gui.topLeft.removeChild(child); child.destroy(); } } if (LK.gui.topRight) { while (LK.gui.topRight.children.length > 0) { var child = LK.gui.topRight.children[0]; LK.gui.topRight.removeChild(child); child.destroy(); } } // Reset UI element references to null scoreTxt = null; streakTxt = null; moneyTxt = null; multiplierTxt = null; bestScoreTxt = null; timerNumbers = []; currentPlayerTxt = null; player1ScoreTxt = null; player2ScoreTxt = null; aiScoreTxt = null; } function initializeTitleScreen() { // Stop all music when returning to title LK.stopMusic(); // Reset music started flag musicStarted = false; // Clean up all UI elements from LK.gui cleanupUIElements(); // Clean up tap zone green balls for (var i = 0; i < tapZoneGreenBalls.length; i++) { if (tapZoneGreenBalls[i]) { tapZoneGreenBalls[i].destroy(); } } tapZoneGreenBalls = []; // Clean up volume visualizer bars for (var i = 0; i < volumeVisualizerBars.length; i++) { if (volumeVisualizerBars[i]) { volumeVisualizerBars[i].destroy(); } } volumeVisualizerBars = []; // Create title background titleBackground = game.addChild(LK.getAsset('TitleBackground', { anchorX: 0, anchorY: 0 })); titleBackground.x = 0; titleBackground.y = 0; titleBackground.width = 2048; titleBackground.height = 2732; titleBackground.zIndex = -5; // Create game title using asset titleText = game.addChild(LK.getAsset('Title', { anchorX: 0.5, anchorY: 0.5 })); titleText.x = 1024; titleText.y = 1000; titleText.zIndex = 10; // Create start button using tap to start asset startButton = game.addChild(LK.getAsset('Taptostart', { anchorX: 0.5, anchorY: 0.5 })); startButton.x = 1294; startButton.y = 1150; startButton.zIndex = 10; // Create how to play button using asset var howToPlayButton = game.addChild(LK.getAsset('Howtoplay', { anchorX: 0.5, anchorY: 0.5 })); howToPlayButton.x = 250; howToPlayButton.y = 2550; howToPlayButton.zIndex = 10; // Store reference for cleanup game.howToPlayButton = howToPlayButton; // Create shop button using asset var shopButton = game.addChild(LK.getAsset('Shop', { anchorX: 0.5, anchorY: 0.5 })); shopButton.x = 1848; shopButton.y = 2550; shopButton.zIndex = 10; // Store reference for cleanup game.shopButton = shopButton; // Play make a wish sound when title screen loads LK.getSound('Makeaswish').play(); // Animate start button pulsate continuously function pulsateStartButton() { if (!startButton || gameState !== 'title') return; // Safety check tween(startButton, { scaleX: 1.2, scaleY: 1.2 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { if (!startButton || gameState !== 'title') return; // Safety check // Create continuous pulsating loop tween(startButton, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { if (!startButton || gameState !== 'title') return; // Safety check // Restart the pulsate cycle pulsateStartButton(); } }); } }); } pulsateStartButton(); } function initializeModeSelection() { // Hide title screen elements if (titleBackground) { titleBackground.destroy(); titleBackground = null; } if (titleText) { titleText.destroy(); titleText = null; } if (startButton) { tween.stop(startButton); startButton.destroy(); startButton = null; } if (game.howToPlayButton) { game.howToPlayButton.destroy(); game.howToPlayButton = null; } if (game.shopButton) { game.shopButton.destroy(); game.shopButton = null; } if (game.shopButton) { game.shopButton.destroy(); game.shopButton = null; } // Hide instructions if showing hideHowToPlay(); // Create mode selection background modeSelectBackground = game.addChild(LK.getAsset('TitleBackground', { anchorX: 0, anchorY: 0 })); modeSelectBackground.x = 0; modeSelectBackground.y = 0; modeSelectBackground.width = 2048; modeSelectBackground.height = 2732; modeSelectBackground.zIndex = -5; // Create mode selection title var modeTitle = game.addChild(LK.getAsset('Selectmode', { anchorX: 0.5, anchorY: 0.5 })); modeTitle.x = 1024; modeTitle.y = 700; modeTitle.zIndex = 10; // Create Swish mode button swishButton = game.addChild(LK.getAsset('Swish', { anchorX: 0.5, anchorY: 0.5 })); swishButton.x = 1024; swishButton.y = 1850; swishButton.zIndex = 10; // Create Rhythm mode button rhythmButton = game.addChild(LK.getAsset('Rhythm', { anchorX: 0.5, anchorY: 0.5 })); rhythmButton.x = 1024; rhythmButton.y = 1100; rhythmButton.zIndex = 10; // Create 2 Player battle mode button using 2playvs asset var twoPlayerButton = game.addChild(LK.getAsset('2playvs', { anchorX: 0.5, anchorY: 0.5 })); twoPlayerButton.x = 1024; twoPlayerButton.y = 2100; twoPlayerButton.zIndex = 10; // Create AI vs mode button using Aibattle asset var aiVsButton = game.addChild(LK.getAsset('Aibattle', { anchorX: 0.5, anchorY: 0.5 })); aiVsButton.x = 1024; aiVsButton.y = 2450; aiVsButton.zIndex = 10; // Remove text overlay since Aibattle asset contains the text var aiVsText = null; // Remove text overlay since 2playvs asset contains the text var twoPlayerText = null; // No text overlay needed game.aiVsButton = aiVsButton; game.aiVsText = aiVsText; game.twoPlayerButton = twoPlayerButton; game.twoPlayerText = twoPlayerText; // Change game state to mode selection var twoPlayerRhythmButton = game.addChild(LK.getAsset('2playvs', { anchorX: 0.5, anchorY: 0.5 })); twoPlayerRhythmButton.x = 1024; twoPlayerRhythmButton.y = 1400; twoPlayerRhythmButton.zIndex = 10; twoPlayerRhythmButton.tint = 0xFFFF00; // Start with yellow twoPlayerRhythmButton.alpha = 1.0; // Remove translucent effect // Animate between yellow and blue colors function animateTwoPlayerRhythmButton() { if (gameState !== 'modeSelect') return; tween(twoPlayerRhythmButton, { tint: 0x0000FF // Blue color }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { if (gameState !== 'modeSelect') return; tween(twoPlayerRhythmButton, { tint: 0xFFFF00 // Yellow color }, { duration: 1000, easing: tween.easeInOut, onFinish: animateTwoPlayerRhythmButton }); } }); } animateTwoPlayerRhythmButton(); game.twoPlayerRhythmButton = twoPlayerRhythmButton; game.twoPlayerRhythmText = null; // Create 2 Player Rhythm vs mode button gameState = 'modeSelect'; // Animate buttons function animateModeButtons() { if (gameState !== 'modeSelect') return; // Swish button animation removed - no longer pulsating // Add pulsating animation to rhythm button tween(rhythmButton, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { if (gameState !== 'modeSelect') return; tween(rhythmButton, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { if (gameState !== 'modeSelect') return; // Continue the rhythm button pulsate cycle tween(rhythmButton, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOut, onFinish: arguments.callee.caller }); } }); } }); } animateModeButtons(); } function initializeGameplay() { // Hide title screen elements if (titleBackground) { titleBackground.destroy(); titleBackground = null; } if (titleText) { titleText.destroy(); titleText = null; } if (startButton) { // Stop any active tweens on the start button before destroying tween.stop(startButton); startButton.destroy(); startButton = null; } // Hide mode selection elements if (modeSelectBackground) { modeSelectBackground.destroy(); modeSelectBackground = null; } if (swishButton) { tween.stop(swishButton); swishButton.destroy(); swishButton = null; } if (rhythmButton) { rhythmButton.destroy(); rhythmButton = null; } // Clean up AI vs button if (game.aiVsButton) { game.aiVsButton.destroy(); game.aiVsButton = null; } if (game.aiVsText) { game.aiVsText.destroy(); game.aiVsText = null; } // Clean up 2 Player button if (game.twoPlayerButton) { game.twoPlayerButton.destroy(); game.twoPlayerButton = null; } if (game.twoPlayerText) { game.twoPlayerText.destroy(); game.twoPlayerText = null; } // Clean up 2 Player Rhythm button if (game.twoPlayerRhythmButton) { game.twoPlayerRhythmButton.destroy(); game.twoPlayerRhythmButton = null; } if (game.twoPlayerRhythmText) { game.twoPlayerRhythmText.destroy(); game.twoPlayerRhythmText = null; } // Initialize all game elements (moved from main game code) // Create multiplier indicator text multiplierTxt = new Text2('', { size: 50, fill: 0xFFD700 }); multiplierTxt.anchor.set(0.5, 0); multiplierTxt.y = 180; LK.gui.top.addChild(multiplierTxt); // Enable z-index sorting for proper rendering order game.sortableChildren = true; // Add background with high definition scaling var background = game.addChild(LK.getAsset('Background', { anchorX: 0, anchorY: 0 })); background.x = 0; background.y = 0; background.width = 2048; background.height = 2732; background.zIndex = -10; // Create hoops hoop = game.addChild(new Hoop()); hoop.x = 1024; hoop.y = 1300; leftHoop = game.addChild(new Hoop()); leftHoop.x = 1024 - 375 - 350; leftHoop.y = 1300; rightHoop = game.addChild(new Hoop()); rightHoop.x = 1024 + 375 + 350; rightHoop.y = 1300; // Create UI displays scoreTxt = new Text2('Score: 0', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); streakTxt = new Text2('Streak: 0', { size: 60, fill: 0xFFD700 }); streakTxt.anchor.set(0.5, 0); streakTxt.y = 100; LK.gui.top.addChild(streakTxt); // Create timer using number assets instead of text timerNumbers = []; // Use global variable var timerContainer = new Container(); timerContainer.x = 0; timerContainer.y = 160; LK.gui.top.addChild(timerContainer); // Create shotclock background for timer numbers var timerBg = LK.getAsset('Shotclock', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5 }); timerBg.x = 0; timerBg.y = 140; timerContainer.addChild(timerBg); // Create 2 number positions for seconds only var numberPositions = [-30, 30]; // Positions for tens and units // Initialize number assets for (var i = 0; i < 2; i++) { // 2 number positions for seconds var numberAsset = LK.getAsset('0', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5 }); numberAsset.x = numberPositions[i]; numberAsset.y = 90; numberAsset.parentContainer = timerContainer; // Store container reference timerNumbers.push(numberAsset); timerContainer.addChild(numberAsset); } // Initialize timer display with correct values for each mode if (gameMode === 'rhythm') { gameTimer = 15 * 60; // 15 seconds at 60 FPS gameTimeLeft = 15; updateTimerDisplay(15); } else { gameTimer = 60 * 60; // 60 seconds at 60 FPS gameTimeLeft = 60; updateTimerDisplay(60); } // Separate best scores for each mode swishBestScore = storage.swishBestScore || 0; rhythmBestScore = storage.rhythmBestScore || 0; bestScore = gameMode === 'rhythm' ? rhythmBestScore : swishBestScore; bestScoreTxt = new Text2('Best: ' + bestScore, { size: 60, fill: 0xFFD700 }); bestScoreTxt.anchor.set(1, 0); bestScoreTxt.x = -100; LK.gui.topRight.addChild(bestScoreTxt); // Use already loaded currentMoney value moneyTxt = new Text2('$' + currentMoney.toFixed(2), { size: 50, fill: 0x00FF00 }); moneyTxt.anchor.set(0, 0); moneyTxt.x = 120; moneyTxt.y = 10; LK.gui.topLeft.addChild(moneyTxt); // Add default basketball mode display var basketballModeText = new Text2(currentBasketballMode, { size: 40, fill: 0xFFD700 }); basketballModeText.anchor.set(0, 0); basketballModeText.x = 120; basketballModeText.y = 70; LK.gui.topLeft.addChild(basketballModeText); // Create shot bars only if not in 2 player rhythm mode if (!(gameMode === '2player' && twoPlayerRhythmMode)) { shotBar = game.addChild(new ShotBar()); shotBar.x = 1024; shotBar.y = 1600; shotBar2 = game.addChild(new ShotBar()); shotBar2.x = 300; shotBar2.y = 1600; shotBar3 = game.addChild(new ShotBar()); shotBar3.x = rightHoop.x; shotBar3.y = 1600; } // Add players - always use Player1/2/3 assets (default mode players) var player1Asset = 'Player1'; // Default player1 var player1downAsset = 'Player1down'; var player2Asset = 'Player2'; // Default player2 var player2downAsset = 'Player2down'; var player3Asset = 'Player3'; // Default player3 var player3downAsset = 'Player3down'; // Set default basketball mode to Warriorsball var currentBasketballMode = defaultBasketballMode; player1 = game.addChild(LK.getAsset(player1Asset, { anchorX: 0.5, anchorY: 1 })); player1.x = 1024; player1.y = 2732; player1.zIndex = 1; player1.visible = false; player1down = game.addChild(LK.getAsset(player1downAsset, { anchorX: 0.5, anchorY: 1 })); player1down.x = 1024; player1down.y = 2732; player1down.zIndex = 1; player1down.visible = true; player2 = game.addChild(LK.getAsset(player2Asset, { anchorX: 0.5, anchorY: 1 })); player2.x = 300; player2.y = 2732; player2.zIndex = 1; player2.visible = false; player2down = game.addChild(LK.getAsset(player2downAsset, { anchorX: 0.5, anchorY: 1 })); player2down.x = 300; player2down.y = 2732; player2down.zIndex = 1; player2down.visible = true; player3 = game.addChild(LK.getAsset(player3Asset, { anchorX: 0.5, anchorY: 1 })); player3.x = 1748; player3.y = 2732; player3.zIndex = 1; player3.visible = false; player3down = game.addChild(LK.getAsset(player3downAsset, { anchorX: 0.5, anchorY: 1 })); player3down.x = 1748; player3down.y = 2732; player3down.zIndex = 1; player3down.visible = true; // Apply the selected basketball mode by swapping player sprites swapPlayerSprites(); // Apply the selected basketball mode by swapping basketball assets swapBasketballAssets(); // Lock overlays removed - players are now always unlocked // Default mode players (player1, player2, player3) are always available // Start shot bars only if not in 2 player rhythm mode if (!(gameMode === '2player' && twoPlayerRhythmMode)) { shotBar.startMoving(); shotBar2.startMoving(); shotBar3.startMoving(); } // Initialize AI vs mode elements if in AI vs mode if (gameMode === 'ai_vs') { // Create AI opponent aiOpponent = new AIOpponent(); game.addChild(aiOpponent); // Create AI score display aiScoreTxt = new Text2('AI: 0', { size: 80, fill: 0xFF4444 // Red color for AI }); aiScoreTxt.anchor.set(0.5, 0); aiScoreTxt.x = -500; // Position to the left of player score aiScoreTxt.y = 100; // Move down 100 pixels LK.gui.top.addChild(aiScoreTxt); // Set timer for AI vs mode to 90 seconds gameTimer = 90 * 60; // 90 seconds at 60 FPS gameTimeLeft = 90; updateTimerDisplay(90); // Initialize speed multiplier tracking for shot bars if (shotBar) shotBar.currentSpeedMultiplier = 1; if (shotBar2) shotBar2.currentSpeedMultiplier = 1; if (shotBar3) shotBar3.currentSpeedMultiplier = 1; // Create AI vs mode indicator var modeIndicator = new Text2('AI BATTLE MODE', { size: 50, fill: 0xFF4444 }); modeIndicator.anchor.set(1, 0); modeIndicator.x = -100; modeIndicator.y = 120; LK.gui.topRight.addChild(modeIndicator); game.aiModeIndicator = modeIndicator; } // Initialize 2 Player battle mode elements if in 2 player mode if (gameMode === '2player') { // Initialize 2 player state twoPlayerState = 'player1'; player1Score = 0; player2Score = 0; // Check if this is 2 player rhythm mode if (twoPlayerRhythmMode) { // Set timer for 90 seconds in rhythm mode twoPlayerTimer = 90 * 60; // 90 seconds at 60 FPS twoPlayerTimeLeft = 90; gameTimer = twoPlayerTimer; gameTimeLeft = twoPlayerTimeLeft; updateTimerDisplay(90); } else { // Set timer for 90 seconds in swish mode twoPlayerTimer = 90 * 60; // 90 seconds at 60 FPS twoPlayerTimeLeft = 90; gameTimer = twoPlayerTimer; gameTimeLeft = twoPlayerTimeLeft; updateTimerDisplay(90); } // Create current player indicator var modeText = twoPlayerRhythmMode ? 'RHYTHM' : 'SWISH'; currentPlayerTxt = new Text2('PLAYER 1 - ' + modeText + ' MODE!', { size: 60, fill: 0x44FF44 }); currentPlayerTxt.anchor.set(0.5, 0); currentPlayerTxt.x = 0; currentPlayerTxt.y = 400; LK.gui.top.addChild(currentPlayerTxt); // Create player score displays player1ScoreTxt = new Text2('P1: 0', { size: 70, fill: 0x44FF44 }); player1ScoreTxt.anchor.set(0, 0); player1ScoreTxt.x = -600; player1ScoreTxt.y = 100; LK.gui.top.addChild(player1ScoreTxt); player2ScoreTxt = new Text2('P2: 0', { size: 70, fill: 0xFFFFFF }); player2ScoreTxt.anchor.set(1, 0); player2ScoreTxt.x = 600; player2ScoreTxt.y = 100; LK.gui.top.addChild(player2ScoreTxt); // Start countdown for player 1 createCountdownOverlay('PLAYER 1 GET READY!', 5); gameEnded = true; // Pause game during countdown } // Initialize rhythm mode elements if in rhythm mode or 2 player rhythm mode if (gameMode === 'rhythm' || gameMode === '2player' && twoPlayerRhythmMode) { // Timer already set above, just initialize rhythm-specific elements // Create beat indicator beatIndicator = new Text2('♪', { size: 200, fill: 0xFFD700 }); beatIndicator.anchor.set(0.5, 0.5); beatIndicator.x = 1024; beatIndicator.y = 400; beatIndicator.zIndex = 20; game.addChild(beatIndicator); // Create three green balls for tap zones tapZoneGreenBalls = []; var tapZonePositions = [300, 1024, 1748]; // Left, center, right positions for (var i = 0; i < tapZonePositions.length; i++) { var greenBall = game.addChild(LK.getAsset('greenBall', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 })); greenBall.x = tapZonePositions[i]; greenBall.y = 1600; // Same Y as shot bars greenBall.tint = 0x00FF00; // Green tint greenBall.alpha = 0.8; greenBall.zIndex = 12; tapZoneGreenBalls.push(greenBall); } // Create volume visualizer bars volumeVisualizerBars = []; var barCount = 8; // Number of visualizer bars var barSpacing = 200; var startX = 1024 - (barCount - 1) * barSpacing * 0.5; // Center the bars for (var i = 0; i < barCount; i++) { var visualizerBar = game.addChild(LK.getAsset('Visualisers', { anchorX: 0.5, anchorY: 1, scaleX: 0.3, scaleY: 0.1 })); visualizerBar.x = startX + i * barSpacing; visualizerBar.y = 400; // Position above beat indicator, moved down 100 visualizerBar.tint = 0x00FFFF; // Cyan color visualizerBar.alpha = 0.7; visualizerBar.zIndex = 18; visualizerBar.baseHeight = 0.1; visualizerBar.targetHeight = 0.1; volumeVisualizerBars.push(visualizerBar); } // Start beat timing lastBeatTime = LK.ticks; } // Create volume visualizer bars for swish mode (same as rhythm mode) if (gameMode === 'swish') { //{eF_new1} volumeVisualizerBars = []; //{eF_new2} var barCount = 8; // Number of visualizer bars var barSpacing = 200; var startX = 1024 - (barCount - 1) * barSpacing * 0.5; // Center the bars for (var i = 0; i < barCount; i++) { var visualizerBar = game.addChild(LK.getAsset('Visualisers', { anchorX: 0.5, //{eF_new3} anchorY: 1, scaleX: 0.3, scaleY: 0.1 //{eF_new4} })); //{eF_new5} visualizerBar.x = startX + i * barSpacing; visualizerBar.y = 400; // Position above beat indicator, moved down 100 visualizerBar.tint = 0x00FFFF; // Cyan color visualizerBar.alpha = 0.7; visualizerBar.zIndex = 18; visualizerBar.baseHeight = 0.1; visualizerBar.targetHeight = 0.1; volumeVisualizerBars.push(visualizerBar); } //{eF_new6} } //{eF_new7} // Change game state to playing gameState = 'playing'; } function spawnRhythmCircle() { if (gameMode !== 'rhythm' && !(gameMode === '2player' && twoPlayerRhythmMode)) return; // Randomly choose which shot bar to align with (all players available) var availableShotBars = []; if (shotBar) availableShotBars.push(shotBar); if (shotBar2) { availableShotBars.push(shotBar2); } if (shotBar3) { availableShotBars.push(shotBar3); } // If no shot bars exist (2 player rhythm mode), use predefined positions if (availableShotBars.length === 0) { var positions = [300, 1024, 1748]; // Left, center, right positions var randomPosition = positions[Math.floor(Math.random() * positions.length)]; var circle = new RhythmCircle(); circle.x = randomPosition; circle.y = 200; // Start from top of screen circle.targetShotBar = null; // No shot bar in 2 player rhythm mode rhythmCircles.push(circle); game.addChild(circle); return; } var targetBar = availableShotBars[Math.floor(Math.random() * availableShotBars.length)]; var circle = new RhythmCircle(); circle.x = targetBar.x; circle.y = 200; // Start from top of screen circle.targetShotBar = targetBar; rhythmCircles.push(circle); game.addChild(circle); } function checkRhythmCircleTap(x, y) { if (gameMode !== 'rhythm' && !(gameMode === '2player' && twoPlayerRhythmMode)) return false; var tappedCircle = null; var tappedInGreenZone = false; for (var i = rhythmCircles.length - 1; i >= 0; i--) { var circle = rhythmCircles[i]; if (!circle.isActive || circle.hasBeenTapped) continue; // Skip if already been tapped // Check if tap is within circle bounds var distance = Math.sqrt((x - circle.x) * (x - circle.x) + (y - circle.y) * (y - circle.y)); if (distance <= 120) { // Increased circle tap radius for better sensitivity tappedCircle = circle; // Check if circle is currently in the horizontal tap zone area var tolerance = 120; // Further increased tolerance for horizontal tap zone for better responsiveness if (circle.targetShotBar) { var shotBarY = circle.targetShotBar.y; tappedInGreenZone = Math.abs(circle.y - shotBarY) <= tolerance; } else if (gameMode === '2player' && twoPlayerRhythmMode) { // In 2 player rhythm mode, check if circle is in tap zone area (green ball position) var tapZoneY = 1600; // Same Y as green balls tappedInGreenZone = Math.abs(circle.y - tapZoneY) <= tolerance; } break; } } return { tapped: tappedCircle !== null, circle: tappedCircle, inGreenZone: tappedInGreenZone }; } function checkSimultaneousTap(x, y) { if (gameMode !== 'rhythm' && !(gameMode === '2player' && twoPlayerRhythmMode)) return false; // Check for rhythm circle tap var rhythmResult = checkRhythmCircleTap(x, y); if (!rhythmResult.tapped) return false; // In rhythm mode, if player taps rhythm circle in tap zone, they score a perfect swish if (rhythmResult.tapped && rhythmResult.inGreenZone) { // Mark circle as tapped to prevent reuse rhythmResult.circle.hasBeenTapped = true; // Perfect swish in rhythm mode! rhythmStreak += 1; // Increase rhythm streak rhythmMultiplier = Math.min(3, 1 + Math.floor(rhythmStreak / 5) * 0.5); // Trigger volume visualizer pulse effect for (var v = 0; v < volumeVisualizerBars.length; v++) { var bar = volumeVisualizerBars[v]; var randomHeight = 0.3 + Math.random() * 1.2; // Random height between 0.3 and 1.5 bar.targetHeight = randomHeight; // Cycle through neon colors var neonColors = [0xFF0080, 0x00FF80, 0x8000FF, 0xFF8000, 0x0080FF, 0x80FF00, 0xFF0040, 0x40FF00]; var randomColor = neonColors[Math.floor(Math.random() * neonColors.length)]; // Animate bar to target height and change color tween(bar, { scaleY: randomHeight, tint: randomColor }, { duration: 150, easing: tween.easeOut, onFinish: function () { // Animate back to base height tween(this, { scaleY: 0.1 }, { duration: 500, easing: tween.easeIn }); }.bind(bar) }); } // Remove screen flash to prevent excessive flashing LK.setScore(LK.getScore() + 2); // Same scoring as swish mode if (scoreTxt) { scoreTxt.setText('Score: ' + LK.getScore()); } // Update player scores in 2 player mode if (gameMode === '2player') { if (twoPlayerState === 'player1') { player1Score = LK.getScore(); if (player1ScoreTxt) { player1ScoreTxt.setText('P1: ' + player1Score); } } else if (twoPlayerState === 'player2') { player2Score = LK.getScore(); if (player2ScoreTxt) { player2ScoreTxt.setText('P2: ' + player2Score); } } } // Check and update rhythm mode best score when scoring var currentScore = LK.getScore(); if (currentScore > rhythmBestScore) { rhythmBestScore = currentScore; storage.rhythmBestScore = rhythmBestScore; bestScore = rhythmBestScore; bestScoreTxt.setText('Best: ' + bestScore); } // Increase streak for perfect swish currentStreak++; if (streakTxt) { //{lT_new} streakTxt.setText('Streak: ' + currentStreak); } //{lT_end} // Play swish sound LK.getSound('swish').play(); // Make the player in that row shoot a perfect swish // In 2 player rhythm mode, use tap zone positions since no shot bars exist var targetHoop = hoop; // Default to center hoop var activePlayer = 1; var startX = 1024; var startY = 2000; // Determine which player/hoop based on circle position (for 2 player rhythm mode) if (gameMode === '2player' && twoPlayerRhythmMode) { // Use circle position to determine which hoop to target if (rhythmResult.circle.x <= 600) { // Left position targetHoop = leftHoop; activePlayer = 2; startX = 300; } else if (rhythmResult.circle.x >= 1400) { // Right position targetHoop = rightHoop; activePlayer = 3; startX = 1748; } else { // Center position targetHoop = hoop; activePlayer = 1; startX = 1024; } } else if (rhythmResult.circle && rhythmResult.circle.targetShotBar) { // Regular rhythm mode with shot bars var targetBar = rhythmResult.circle.targetShotBar; // Determine which player/hoop based on target shot bar if (targetBar === shotBar2) { // Left player (Player2) targetHoop = leftHoop; activePlayer = 2; startX = 300; } else if (targetBar === shotBar3) { // Right player (Player3) targetHoop = rightHoop; activePlayer = 3; startX = 1748; } } // Switch player sprites to shooting position if (activePlayer === 1) { player1.visible = true; player1down.visible = false; LK.setTimeout(function () { player1.visible = false; player1down.visible = true; }, 1000); } else if (activePlayer === 2) { player2.visible = true; player2down.visible = false; LK.setTimeout(function () { player2.visible = false; player2down.visible = true; }, 1000); } else if (activePlayer === 3) { player3.visible = true; player3down.visible = false; LK.setTimeout(function () { player3.visible = false; player3down.visible = true; }, 1000); } // Calculate perfect shot trajectory with enhanced precision var targetX = targetHoop.x; var targetY = targetHoop.y - 350; // Aim directly at hoop center var deltaX = targetX - startX; var deltaY = targetY - startY; // Use optimized timing for guaranteed success var time = 45; // Slightly faster for better arc var gravity = 0.5; // Calculate perfect trajectory velocities with downward bias for clean entry var velocityX = deltaX / time; var velocityY = deltaY / time - 0.5 * gravity * time - 1.5; // Extra downward bias // Fine-tune horizontal velocity to ensure center entry var horizontalCorrection = (targetX - startX) * 0.02; // Small correction factor velocityX += horizontalCorrection; // Create perfect swish basketball var ball = createBasketball(startX, startY, velocityX, velocityY); ball.isPerfectShot = true; ball.guaranteedSwish = true; // Set additional properties to ensure scoring ball.hasScored = false; // Ensure it can score ball.isActive = true; // Ensure it's active // Add rotation animation tween(ball, { rotation: ball.rotation + Math.PI * 4 }, { duration: 1500, easing: tween.easeOut }); } else if (rhythmResult.tapped) { // Mark circle as tapped to prevent reuse rhythmResult.circle.hasBeenTapped = true; // Rhythm circle tapped but not in tap zone - reset streaks rhythmStreak = 0; rhythmMultiplier = 1; currentStreak = 0; if (streakTxt) { //{mR_new} streakTxt.setText('Streak: ' + currentStreak); } //{mR_end} streakRewardsAwarded = []; // Reset streak rewards // Remove onfire effects from all nets when streak is reset and show nets if (hoop && hoop.onfire) { hoop.net.visible = true; hoop.onfire.destroy(); hoop.onfire = null; } if (leftHoop && leftHoop.onfire) { leftHoop.net.visible = true; leftHoop.onfire.destroy(); leftHoop.onfire = null; } if (rightHoop && rightHoop.onfire) { rightHoop.net.visible = true; rightHoop.onfire.destroy(); rightHoop.onfire = null; } // Remove red flash to prevent excessive flashing } // Remove tapped circle with animation if (rhythmResult.circle) { tween(rhythmResult.circle, { scaleX: 2.0, scaleY: 2.0, alpha: 0 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { rhythmResult.circle.isActive = false; } }); } return rhythmResult.tapped; } function createCountdownOverlay(message, count) { // Create semi-transparent overlay var countdownOverlay = game.addChild(LK.getAsset('TitleBackground', { anchorX: 0, anchorY: 0 })); countdownOverlay.x = 0; countdownOverlay.y = 0; countdownOverlay.width = 2048; countdownOverlay.height = 2732; countdownOverlay.tint = 0x000000; countdownOverlay.alpha = 0.7; countdownOverlay.zIndex = 100; // Create message text var messageText = new Text2(message, { size: 70, fill: 0xFFFFFF }); messageText.anchor.set(0.5, 0.5); messageText.x = 1024; messageText.y = 1100; messageText.zIndex = 101; game.addChild(messageText); // Create countdown container countdownContainer = new Container(); countdownContainer.x = 1024; countdownContainer.y = 1366; countdownContainer.zIndex = 102; game.addChild(countdownContainer); // Store references for cleanup game.countdownOverlay = countdownOverlay; game.countdownMessage = messageText; // Start countdown animation countdownActive = true; countdownTimer = count; updateCountdownDisplay(); } function updateCountdownDisplay() { if (!countdownActive || !countdownContainer) return; // Clear existing countdown number while (countdownContainer.children.length > 0) { var child = countdownContainer.children[0]; countdownContainer.removeChild(child); child.destroy(); } if (countdownTimer > 0) { // Create enlarged number asset for current countdown var numberAsset = LK.getAsset(countdownTimer.toString(), { anchorX: 0.5, anchorY: 0.5, scaleX: 4.0, scaleY: 4.0 }); numberAsset.x = 0; numberAsset.y = 0; numberAsset.alpha = 0; countdownContainer.addChild(numberAsset); // Animate number appearance tween(numberAsset, { alpha: 1.0, scaleX: 5.0, scaleY: 5.0 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Animate number disappearance tween(numberAsset, { alpha: 0, scaleX: 3.0, scaleY: 3.0 }, { duration: 700, easing: tween.easeIn }); } }); } else { // Show "GO!" message var goText = new Text2('GO!', { size: 120, fill: 0x00FF00 }); goText.anchor.set(0.5, 0.5); goText.x = 0; goText.y = 0; goText.alpha = 0; countdownContainer.addChild(goText); // Animate GO! message tween(goText, { alpha: 1.0, scaleX: 1.5, scaleY: 1.5 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { tween(goText, { alpha: 0, scaleX: 2.0, scaleY: 2.0 }, { duration: 600, easing: tween.easeIn }); } }); } } function hideCountdownOverlay() { countdownActive = false; countdownTimer = 0; if (game.countdownOverlay) { game.countdownOverlay.destroy(); game.countdownOverlay = null; } if (game.countdownMessage) { game.countdownMessage.destroy(); game.countdownMessage = null; } if (countdownContainer) { countdownContainer.destroy(); countdownContainer = null; } } function createTransitionOverlay(message) { // Create semi-transparent overlay transitionOverlay = game.addChild(LK.getAsset('TitleBackground', { anchorX: 0, anchorY: 0 })); transitionOverlay.x = 0; transitionOverlay.y = 0; transitionOverlay.width = 2048; transitionOverlay.height = 2732; transitionOverlay.tint = 0x000000; transitionOverlay.alpha = 0.8; transitionOverlay.zIndex = 100; // Create transition message transitionText = new Text2(message, { size: 80, fill: 0xFFFFFF }); transitionText.anchor.set(0.5, 0.5); transitionText.x = 1024; transitionText.y = 1200; transitionText.zIndex = 101; game.addChild(transitionText); // Create countdown text var countdownText = new Text2('STARTING IN 3...', { size: 60, fill: 0xFF4444 }); countdownText.anchor.set(0.5, 0.5); countdownText.x = 1024; countdownText.y = 1400; countdownText.zIndex = 101; game.addChild(countdownText); game.transitionCountdown = countdownText; // Animate countdown var count = 3; var countdownInterval = LK.setInterval(function () { if (count > 1) { count--; countdownText.setText('STARTING IN ' + count + '...'); } else { countdownText.setText('GO!'); LK.clearInterval(countdownInterval); } }, 60); // Update every second } function hideTransitionOverlay() { if (transitionOverlay) { transitionOverlay.destroy(); transitionOverlay = null; } if (transitionText) { transitionText.destroy(); transitionText = null; } if (game.transitionCountdown) { game.transitionCountdown.destroy(); game.transitionCountdown = null; } } function createWinnerOverlay(title, subtitle) { // Create semi-transparent overlay var winnerOverlay = game.addChild(LK.getAsset('TitleBackground', { anchorX: 0, anchorY: 0 })); winnerOverlay.x = 0; winnerOverlay.y = 0; winnerOverlay.width = 2048; winnerOverlay.height = 2732; winnerOverlay.tint = 0x000000; winnerOverlay.alpha = 0.8; winnerOverlay.zIndex = 100; // Create winner title var winnerTitle = new Text2(title, { size: 100, fill: 0xFFD700 }); winnerTitle.anchor.set(0.5, 0.5); winnerTitle.x = 1024; winnerTitle.y = 1100; winnerTitle.zIndex = 101; game.addChild(winnerTitle); // Create subtitle var winnerSubtitle = new Text2(subtitle, { size: 60, fill: 0xFFFFFF }); winnerSubtitle.anchor.set(0.5, 0.5); winnerSubtitle.x = 1024; winnerSubtitle.y = 1300; winnerSubtitle.zIndex = 101; game.addChild(winnerSubtitle); // Create continue instruction var continueText = new Text2('TAP TO CONTINUE', { size: 50, fill: 0x44FF44 }); continueText.anchor.set(0.5, 0.5); continueText.x = 1024; continueText.y = 1500; continueText.zIndex = 101; game.addChild(continueText); // Store references for cleanup game.winnerOverlay = winnerOverlay; game.winnerTitle = winnerTitle; game.winnerSubtitle = winnerSubtitle; game.winnerContinueText = continueText; // Set the time when winner display was created game.winnerDisplayTime = LK.ticks; // Animate winner title with pulsing effect tween(winnerTitle, { scaleX: 1.2, scaleY: 1.2 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { if (winnerTitle) { tween(winnerTitle, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut, onFinish: arguments.callee }); } } }); } function checkAllBackboardsSameColor() { // Check if all three backboards have the same color var allSame = backboardColors[0] === backboardColors[1] && backboardColors[1] === backboardColors[2]; // Debug logging to see what's happening console.log('Checking colors:', backboardColors, 'All same:', allSame, 'Current multiplier:', allSameColorMultiplier); // Only activate multiplier if colors changed to same (not if already same) // Also ensure we're not comparing the initial white colors if (allSame && !allSameColorMultiplier && backboardColors[0] !== 0xFFFFFF) { allSameColorMultiplier = true; console.log('Activating 2x multiplier!'); multiplierTxt.setText('2X MULTIPLIER ACTIVE!'); // Award $100.00 if not already awarded for this color match if (!moneyAwarded) { currentMoney += 100.00; storage.money = currentMoney; if (moneyTxt) { moneyTxt.setText('$' + currentMoney.toFixed(2)); } moneyAwarded = true; LK.getSound('Cash').play(); // Play cash sound when money is awarded console.log('Awarded $100.00! Total money:', currentMoney); } } else if (!allSame && allSameColorMultiplier) { allSameColorMultiplier = false; moneyAwarded = false; // Reset money award flag when colors no longer match console.log('Deactivating 2x multiplier'); multiplierTxt.setText(''); } } game.down = function (x, y, obj) { // Handle 2 player winner overlay clicks if (gameMode === '2player' && game.winnerOverlay) { // Check if enough time has passed since winner display was shown (3 seconds minimum) var currentTime = LK.ticks; if (!game.winnerDisplayTime) { game.winnerDisplayTime = currentTime; return; // Don't allow dismissal yet } var timeDisplayed = currentTime - game.winnerDisplayTime; var minimumDisplayTime = 3 * 60; // 3 seconds at 60 FPS if (timeDisplayed < minimumDisplayTime) { return; // Don't allow dismissal until minimum time has passed } // Clean up winner overlay if (game.winnerOverlay) { game.winnerOverlay.destroy(); game.winnerOverlay = null; } if (game.winnerTitle) { tween.stop(game.winnerTitle); game.winnerTitle.destroy(); game.winnerTitle = null; } if (game.winnerSubtitle) { game.winnerSubtitle.destroy(); game.winnerSubtitle = null; } if (game.winnerContinueText) { game.winnerContinueText.destroy(); game.winnerContinueText = null; } // Reset winner display time game.winnerDisplayTime = null; // Clean up UI elements before returning to title screen cleanupUIElements(); //{nz_new} // Return to title screen gameState = 'title'; gameMode = 'swish'; twoPlayerRhythmMode = false; // Reset rhythm mode flag initializeTitleScreen(); return; } // Handle title screen clicks if (gameState === 'title') { // Check if store is showing if (game.storeBackground) { // Check if clicked on pacers ball item (expanded click area for better detection) if (game.storeItem && game.storeItemImage) { var itemLeft = game.storeItemImage.x - 250; var itemRight = game.storeItemImage.x + 250; var itemTop = game.storeItemImage.y - 200; var itemBottom = game.storeItemImage.y + 200; if (x >= itemLeft && x <= itemRight && y >= itemTop && y <= itemBottom) { // Try to purchase item or select if owned if (!game.storeItem.unlocked && gameStore.purchaseItem(game.storeItem)) { // Switch to pacers mode when pacers team pack is purchased if (game.storeItem.id === 'pacersball') { currentBasketballMode = pacersMode; // Switch to pacersball // Switch to pacers mode players (player4, player5, player6) defaultPlayers = pacersPlayers.slice(); // Copy pacers players array // Save the current basketball mode to storage storage.currentBasketballMode = currentBasketballMode; storage.defaultPlayers = defaultPlayers; // Mark item as unlocked in storage storage.pacersball_unlocked = true; // Swap player sprites if currently in game if (gameState === 'playing') { swapPlayerSprites(); swapBasketballAssets(); } // Update item status display if (game.storeItemStatusText) { game.storeItemStatusText.setText('SELECTED'); game.storeItemStatusText.tint = 0x00FF00; } // Update item price text color to show it's owned if (game.storeItemPriceText) { game.storeItemPriceText.tint = 0x888888; // Gray out price when owned } } // Update money display if (moneyTxt) { moneyTxt.setText('$' + currentMoney.toFixed(2)); } // Update store money display if (game.storeMoneyText) { game.storeMoneyText.setText('Money: $' + currentMoney.toFixed(2)); } // Update item status display if (game.storeItemStatusText) { game.storeItemStatusText.setText('SELECTED'); game.storeItemStatusText.tint = 0x00FF00; } // Update item price text color to show it's owned if (game.storeItemPriceText) { game.storeItemPriceText.tint = 0x888888; // Gray out price when owned } } else if (game.storeItem.unlocked) { // Item already owned - select it if (game.storeItem.id === 'pacersball') { currentBasketballMode = pacersMode; // Switch to pacersball // Switch to pacers mode players (player4, player5, player6) defaultPlayers = pacersPlayers.slice(); // Copy pacers players array // Save the current basketball mode to storage storage.currentBasketballMode = currentBasketballMode; storage.defaultPlayers = defaultPlayers; // Swap player sprites if currently in game if (gameState === 'playing') { swapPlayerSprites(); swapBasketballAssets(); } // Update item status display if (game.storeItemStatusText) { game.storeItemStatusText.setText('SELECTED'); game.storeItemStatusText.tint = 0x00FF00; } // Update thunder item status to not selected if (game.storeThunderItemStatusText) { game.storeThunderItemStatusText.setText('TAP TO SELECT'); game.storeThunderItemStatusText.tint = 0xFFFFFF; } // Update warriors item status to not selected if (game.storeWarriorsItemStatusText) { game.storeWarriorsItemStatusText.setText('TAP TO SELECT'); game.storeWarriorsItemStatusText.tint = 0xFFFFFF; } // Play selection sound LK.getSound('Cash').play(); } } else if (!gameStore.canAfford(game.storeItem)) { // Not enough money - flash red briefly if (game.storeItemPriceText) { var originalTint = game.storeItemPriceText.tint; game.storeItemPriceText.tint = 0xFF0000; LK.setTimeout(function () { if (game.storeItemPriceText) { game.storeItemPriceText.tint = originalTint; } }, 500); } } return; } } // Check if clicked on thunder ball item if (game.storeThunderItem && game.storeThunderItemImage) { var thunderItemLeft = game.storeThunderItemImage.x - 250; var thunderItemRight = game.storeThunderItemImage.x + 250; var thunderItemTop = game.storeThunderItemImage.y - 200; var thunderItemBottom = game.storeThunderItemImage.y + 200; if (x >= thunderItemLeft && x <= thunderItemRight && y >= thunderItemTop && y <= thunderItemBottom) { // Try to purchase thunder item or select if owned if (!game.storeThunderItem.unlocked && gameStore.purchaseItem(game.storeThunderItem)) { // Switch to thunder mode when thunder team pack is purchased if (game.storeThunderItem.id === 'thunderball') { currentBasketballMode = thunderMode; // Switch to Thunderball // Switch to thunder mode players (player7, player8, player9) defaultPlayers = thunderPlayers.slice(); // Copy thunder players array // Save the current basketball mode to storage storage.currentBasketballMode = currentBasketballMode; storage.defaultPlayers = defaultPlayers; // Swap player sprites if currently in game if (gameState === 'playing') { swapPlayerSprites(); swapBasketballAssets(); } } // Update money display if (moneyTxt) { moneyTxt.setText('$' + currentMoney.toFixed(2)); } // Update store money display if (game.storeMoneyText) { game.storeMoneyText.setText('Money: $' + currentMoney.toFixed(2)); } // Update item status display if (game.storeThunderItemStatusText) { game.storeThunderItemStatusText.setText('SELECTED'); game.storeThunderItemStatusText.tint = 0x00FF00; } // Update item price text color to show it's owned if (game.storeThunderItemPriceText) { game.storeThunderItemPriceText.tint = 0x888888; // Gray out price when owned } } else if (game.storeThunderItem.unlocked) { // Item already owned - select it if (game.storeThunderItem.id === 'thunderball') { currentBasketballMode = thunderMode; // Switch to Thunderball // Switch to thunder mode players (player7, player8, player9) defaultPlayers = thunderPlayers.slice(); // Copy thunder players array // Save the current basketball mode to storage storage.currentBasketballMode = currentBasketballMode; storage.defaultPlayers = defaultPlayers; // Swap player sprites if currently in game if (gameState === 'playing') { swapPlayerSprites(); swapBasketballAssets(); } // Update item status display if (game.storeThunderItemStatusText) { game.storeThunderItemStatusText.setText('SELECTED'); game.storeThunderItemStatusText.tint = 0x00FF00; } // Update pacers item status to not selected if (game.storeItemStatusText) { game.storeItemStatusText.setText('TAP TO SELECT'); game.storeItemStatusText.tint = 0xFFFFFF; } // Update warriors item status to not selected if (game.storeWarriorsItemStatusText) { game.storeWarriorsItemStatusText.setText('TAP TO SELECT'); game.storeWarriorsItemStatusText.tint = 0xFFFFFF; } // Play selection sound LK.getSound('Cash').play(); } } else if (!gameStore.canAfford(game.storeThunderItem)) { // Not enough money - flash red briefly if (game.storeThunderItemPriceText) { var originalThunderTint = game.storeThunderItemPriceText.tint; game.storeThunderItemPriceText.tint = 0xFF0000; LK.setTimeout(function () { if (game.storeThunderItemPriceText) { game.storeThunderItemPriceText.tint = originalThunderTint; } }, 500); } } return; } } // Check if clicked on 2playvs pack item if (game.store2PlayerVsItem && game.store2PlayerVsItemImage) { var twoPlayerVsItemLeft = game.store2PlayerVsItemImage.x - 250; var twoPlayerVsItemRight = game.store2PlayerVsItemImage.x + 250; var twoPlayerVsItemTop = game.store2PlayerVsItemImage.y - 200; var twoPlayerVsItemBottom = game.store2PlayerVsItemImage.y + 200; if (x >= twoPlayerVsItemLeft && x <= twoPlayerVsItemRight && y >= twoPlayerVsItemTop && y <= twoPlayerVsItemBottom) { // Try to purchase 2playvs pack if (!game.store2PlayerVsItem.unlocked && gameStore.purchaseItem(game.store2PlayerVsItem)) { // Successfully purchased 2 Player Rhythm pack storage['2playvs_unlocked'] = true; // Update money display if (moneyTxt) { moneyTxt.setText('$' + currentMoney.toFixed(2)); } // Update store money display if (game.storeMoneyText) { game.storeMoneyText.setText('Money: $' + currentMoney.toFixed(2)); } // Update item status display if (game.store2PlayerVsItemStatusText) { game.store2PlayerVsItemStatusText.setText('UNLOCKED'); game.store2PlayerVsItemStatusText.tint = 0x00FF00; } // Update item price text color to show it's owned if (game.store2PlayerVsItemPriceText) { game.store2PlayerVsItemPriceText.tint = 0x888888; // Gray out price when owned } } else if (!gameStore.canAfford(game.store2PlayerVsItem)) { // Not enough money - flash red briefly if (game.store2PlayerVsItemPriceText) { var originalTint = game.store2PlayerVsItemPriceText.tint; game.store2PlayerVsItemPriceText.tint = 0xFF0000; LK.setTimeout(function () { if (game.store2PlayerVsItemPriceText) { game.store2PlayerVsItemPriceText.tint = originalTint; } }, 500); } } return; } } // Check if clicked on swish2playvs pack item if (game.storeSwish2PlayerVsItem && game.storeSwish2PlayerVsItemImage) { var swishTwoPlayerVsItemLeft = game.storeSwish2PlayerVsItemImage.x - 250; var swishTwoPlayerVsItemRight = game.storeSwish2PlayerVsItemImage.x + 250; var swishTwoPlayerVsItemTop = game.storeSwish2PlayerVsItemImage.y - 200; var swishTwoPlayerVsItemBottom = game.storeSwish2PlayerVsItemImage.y + 200; if (x >= swishTwoPlayerVsItemLeft && x <= swishTwoPlayerVsItemRight && y >= swishTwoPlayerVsItemTop && y <= swishTwoPlayerVsItemBottom) { // Try to purchase swish2playvs pack if (!game.storeSwish2PlayerVsItem.unlocked && gameStore.purchaseItem(game.storeSwish2PlayerVsItem)) { // Successfully purchased 2 Player Swish pack storage['swish2playvs_unlocked'] = true; // Update money display if (moneyTxt) { moneyTxt.setText('$' + currentMoney.toFixed(2)); } // Update store money display if (game.storeMoneyText) { game.storeMoneyText.setText('Money: $' + currentMoney.toFixed(2)); } // Update item status display if (game.storeSwish2PlayerVsItemStatusText) { game.storeSwish2PlayerVsItemStatusText.setText('UNLOCKED'); game.storeSwish2PlayerVsItemStatusText.tint = 0x00FF00; } // Update item price text color to show it's owned if (game.storeSwish2PlayerVsItemPriceText) { game.storeSwish2PlayerVsItemPriceText.tint = 0x888888; // Gray out price when owned } } else if (!gameStore.canAfford(game.storeSwish2PlayerVsItem)) { // Not enough money - flash red briefly if (game.storeSwish2PlayerVsItemPriceText) { var originalTint = game.storeSwish2PlayerVsItemPriceText.tint; game.storeSwish2PlayerVsItemPriceText.tint = 0xFF0000; LK.setTimeout(function () { if (game.storeSwish2PlayerVsItemPriceText) { game.storeSwish2PlayerVsItemPriceText.tint = originalTint; } }, 500); } } return; } } // Check if clicked on aibattle pack item if (game.storeAibattleItem && game.storeAibattleItemImage) { var aibattleItemLeft = game.storeAibattleItemImage.x - 175; var aibattleItemRight = game.storeAibattleItemImage.x + 175; var aibattleItemTop = game.storeAibattleItemImage.y - 175; var aibattleItemBottom = game.storeAibattleItemImage.y + 175; if (x >= aibattleItemLeft && x <= aibattleItemRight && y >= aibattleItemTop && y <= aibattleItemBottom) { // Try to purchase aibattle pack if (!game.storeAibattleItem.unlocked && gameStore.purchaseItem(game.storeAibattleItem)) { // Successfully purchased AI Battle pack storage['aibattle_unlocked'] = true; // Update money display//{tU_new1} if (moneyTxt) { //{tU_new2} moneyTxt.setText('$' + currentMoney.toFixed(2)); //{tU_new3} } //{tU_new4} // Update store money display//{tU_new5} if (game.storeMoneyText) { //{tU_new6} game.storeMoneyText.setText('Money: $' + currentMoney.toFixed(2)); //{tU_new7} } //{tU_new8} // Update item status display//{tU_new9} if (game.storeAibattleItemStatusText) { //{tU_new10} game.storeAibattleItemStatusText.setText('UNLOCKED'); game.storeAibattleItemStatusText.tint = 0x00FF00; } //{tU_new11} // Update item price text color to show it's owned//{tU_new12} if (game.storeAibattleItemPriceText) { //{tU_new13} game.storeAibattleItemPriceText.tint = 0x888888; // Gray out price when owned } //{tU_new14} } else if (!gameStore.canAfford(game.storeAibattleItem)) { // Not enough money - flash red briefly//{tU_new15} if (game.storeAibattleItemPriceText) { //{tU_new16} var originalTint = game.storeAibattleItemPriceText.tint; game.storeAibattleItemPriceText.tint = 0xFF0000; LK.setTimeout(function () { //{tU_new17} if (game.storeAibattleItemPriceText) { //{tU_new18} game.storeAibattleItemPriceText.tint = originalTint; } //{tU_new19} }, 500); //{tU_new20} } //{tU_new21} } //{tU_new22} return; //{tU_new23} } //{tU_new24} } //{tU_new25} // Check if clicked on Warriorsball item (default mode) if (game.storeWarriorsItemImage) { var warriorsItemLeft = game.storeWarriorsItemImage.x - 250; var warriorsItemRight = game.storeWarriorsItemImage.x + 250; var warriorsItemTop = game.storeWarriorsItemImage.y - 200; var warriorsItemBottom = game.storeWarriorsItemImage.y + 200; if (x >= warriorsItemLeft && x <= warriorsItemRight && y >= warriorsItemTop && y <= warriorsItemBottom) { // Switch back to default Warriors mode currentBasketballMode = defaultBasketballMode; // Switch to Warriorsball // Switch back to default mode players (player1, player2, player3) defaultPlayers = ['player1', 'player2', 'player3']; // Reset to default players // Save the current basketball mode to storage storage.currentBasketballMode = currentBasketballMode; storage.defaultPlayers = defaultPlayers; // Swap player sprites if currently in game if (gameState === 'playing') { swapPlayerSprites(); swapBasketballAssets(); } // Update basketball mode display if (game.basketballModeText) { game.basketballModeText.setText(currentBasketballMode); } // Visual feedback if (game.storeWarriorsItemStatusText) { game.storeWarriorsItemStatusText.setText('SELECTED'); game.storeWarriorsItemStatusText.tint = 0x00FF00; } // Update pacers item status to not selected if (game.storeItemStatusText) { game.storeItemStatusText.setText('TAP TO SELECT'); game.storeItemStatusText.tint = 0xFFFFFF; } // Update thunder item status to not selected if (game.storeThunderItemStatusText) { game.storeThunderItemStatusText.setText('TAP TO SELECT'); game.storeThunderItemStatusText.tint = 0xFFFFFF; } // Play selection sound LK.getSound('Cash').play(); return; } } hideStore(); return; } // Check if instructions are showing if (game.instructionsOverlay) { hideHowToPlay(); return; } // Check if clicked on start button area (tap to start button) var buttonLeft = startButton.x - 250; // Half of button width var buttonRight = startButton.x + 250; var buttonTop = startButton.y - 250; // Half of button height var buttonBottom = startButton.y + 250; if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) { initializeModeSelection(); return; } // Check if clicked on how to play button if (game.howToPlayButton) { var howToLeft = game.howToPlayButton.x - 150; var howToRight = game.howToPlayButton.x + 150; var howToTop = game.howToPlayButton.y - 150; var howToBottom = game.howToPlayButton.y + 150; if (x >= howToLeft && x <= howToRight && y >= howToTop && y <= howToBottom) { showHowToPlay(); return; } } // Check if clicked on shop button if (game.shopButton) { var shopLeft = game.shopButton.x - 150; var shopRight = game.shopButton.x + 150; var shopTop = game.shopButton.y - 150; var shopBottom = game.shopButton.y + 150; if (x >= shopLeft && x <= shopRight && y >= shopTop && y <= shopBottom) { showStore(); return; } } return; } // Handle mode selection clicks if (gameState === 'modeSelect') { // Check Swish button var swishLeft = swishButton.x - 200; var swishRight = swishButton.x + 200; var swishTop = swishButton.y - 150; var swishBottom = swishButton.y + 150; if (x >= swishLeft && x <= swishRight && y >= swishTop && y <= swishBottom) { gameMode = 'swish'; LK.playMusic('backgroundMusic'); initializeGameplay(); return; } // Check Rhythm button var rhythmLeft = rhythmButton.x - 200; var rhythmRight = rhythmButton.x + 200; var rhythmTop = rhythmButton.y - 50; var rhythmBottom = rhythmButton.y + 50; if (x >= rhythmLeft && x <= rhythmRight && y >= rhythmTop && y <= rhythmBottom) { gameMode = 'rhythm'; LK.playMusic('Title'); musicStarted = true; // Mark music as started initializeGameplay(); return; } // Check AI vs button if (game.aiVsButton) { var aiVsLeft = game.aiVsButton.x - 150; var aiVsRight = game.aiVsButton.x + 150; var aiVsTop = game.aiVsButton.y - 150; var aiVsBottom = game.aiVsButton.y + 150; if (x >= aiVsLeft && x <= aiVsRight && y >= aiVsTop && y <= aiVsBottom) { // Check if AI Battle pack is unlocked if (storage['aibattle_unlocked']) { gameMode = 'ai_vs'; LK.playMusic('Second'); initializeGameplay(); } else { //{uP_new1} // Show message that pack needs to be purchased//{uP_new2} // Flash the button to indicate it's locked//{uP_new3} tween(game.aiVsButton, { //{uP_new4} tint: 0xFF0000, //{uP_new5} alpha: 0.5 //{uP_new6} }, { //{uP_new7} duration: 200, //{uP_new8} easing: tween.easeOut, //{uP_new9} onFinish: function onFinish() { //{uP_new10} tween(game.aiVsButton, { //{uP_new11} tint: 0xFFFFFF, //{uP_new12} alpha: 1.0 //{uP_new13} }, { //{uP_new14} duration: 200, //{uP_new15} easing: tween.easeIn //{uP_new16} }); //{uP_new17} } //{uP_new18} }); //{uP_new19} } //{uP_new20} return; } } // Check 2 Player vs button if (game.twoPlayerButton) { var twoPlayerLeft = game.twoPlayerButton.x - 150; var twoPlayerRight = game.twoPlayerButton.x + 150; var twoPlayerTop = game.twoPlayerButton.y - 150; var twoPlayerBottom = game.twoPlayerButton.y + 150; if (x >= twoPlayerLeft && x <= twoPlayerRight && y >= twoPlayerTop && y <= twoPlayerBottom) { // Check if 2 Player Swish pack is unlocked if (storage['swish2playvs_unlocked']) { gameMode = '2player'; twoPlayerRhythmMode = false; LK.playMusic('Third'); initializeGameplay(); } else { // Show message that pack needs to be purchased // Flash the button to indicate it's locked tween(game.twoPlayerButton, { tint: 0xFF0000, alpha: 0.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(game.twoPlayerButton, { tint: 0xFFFFFF, alpha: 1.0 }, { duration: 200, easing: tween.easeIn }); } }); } return; } } // Check if clicked on 2 Player Rhythm vs button if (game.twoPlayerRhythmButton) { var twoPlayerRhythmLeft = game.twoPlayerRhythmButton.x - 150; var twoPlayerRhythmRight = game.twoPlayerRhythmButton.x + 150; var twoPlayerRhythmTop = game.twoPlayerRhythmButton.y - 150; var twoPlayerRhythmBottom = game.twoPlayerRhythmButton.y + 150; if (x >= twoPlayerRhythmLeft && x <= twoPlayerRhythmRight && y >= twoPlayerRhythmTop && y <= twoPlayerRhythmBottom) { // Check if 2 Player Rhythm pack is unlocked if (storage['2playvs_unlocked']) { gameMode = '2player'; twoPlayerRhythmMode = true; LK.playMusic('Sunrise'); musicStarted = true; // Mark music as started initializeGameplay(); } else { // Show message that pack needs to be purchased // Flash the button to indicate it's locked tween(game.twoPlayerRhythmButton, { tint: 0xFF0000, alpha: 0.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(game.twoPlayerRhythmButton, { tint: 0xFFFF00, alpha: 1.0 }, { duration: 200, easing: tween.easeIn }); } }); } return; } } return; } // In rhythm mode or 2 player rhythm mode, only process rhythm circle taps, disable shooting if (gameMode === 'rhythm' || gameMode === '2player' && twoPlayerRhythmMode) { checkSimultaneousTap(x, y); return; // Don't process shooting in rhythm mode } // Prevent shooting during countdown in 2player mode if (gameMode === '2player' && countdownActive) { return; } // In AI vs mode, use normal shooting mechanics if (gameMode === 'ai_vs') { // Continue with normal shooting logic } if (LK.ticks - lastShotTime < 30) return; // Reduce cooldown for better responsiveness // Unlock buttons removed - players are now always unlocked // Check if tap is below the top of the backboard (backboards are at y=1300 and extend up ~726 pixels) // Greatly increased tap sensitivity by expanding the detection area further var backboardTopY = 1300 - 1100; // Expanded tap area by 374 pixels above backboard (200) if (y <= backboardTopY) { return; // Don't allow shooting if tapping above the backboard } // Determine which player/hoop to target based on tap position var targetHoop = hoop; var currentShotBar = shotBar; var activePlayer = 1; // Track which player is shooting if (x < 683) { // Left third of screen - Player2's area targetHoop = leftHoop; currentShotBar = shotBar2; activePlayer = 2; } else if (x > 1365) { // Right third of screen - Player3's area targetHoop = rightHoop; currentShotBar = shotBar3; activePlayer = 3; } if (currentShotBar.isActive) { // Stop the shot bar and check for perfect shot var isPerfect = currentShotBar.stopMoving(); isChargingShot = false; // Check rhythm timing if in rhythm mode var onBeat = false; if (gameMode === 'rhythm') { var timeSinceLastBeat = LK.ticks - lastBeatTime; var timeToNextBeat = beatInterval - timeSinceLastBeat; // Check if shot is within beat tolerance if (timeSinceLastBeat <= beatTolerance || timeToNextBeat <= beatTolerance) { onBeat = true; rhythmStreak++; rhythmMultiplier = Math.min(3, 1 + Math.floor(rhythmStreak / 5) * 0.5); // Max 3x multiplier // Remove pink flash to prevent excessive flashing } else { rhythmStreak = 0; rhythmMultiplier = 1; } } // Switch sprites for the appropriate player if (activePlayer === 1) { // Player1 shooting player1.visible = true; player1down.visible = false; // Switch back after 1 second LK.setTimeout(function () { player1.visible = false; player1down.visible = true; }, 1000); } else if (activePlayer === 2) { // Player2 shooting player2.visible = true; player2down.visible = false; // Switch back after 1 second LK.setTimeout(function () { player2.visible = false; player2down.visible = true; }, 1000); } else if (activePlayer === 3) { // Player3 shooting player3.visible = true; player3down.visible = false; // Switch back after 1 second LK.setTimeout(function () { player3.visible = false; player3down.visible = true; }, 1000); } // Calculate shooting parameters based on active player var startX, startY; if (activePlayer === 2) { // Launch from Player2's position (left player) startX = 300; // Player2's x position startY = 2000; } else if (activePlayer === 3) { // Launch from Player3's position (right player) startX = 1748; // Player3's x position startY = 2000; } else { // Launch from Player1's position (center) for main hoop startX = 1024; // Player1's x position startY = 2000; } var velocityX = 0; var velocityY = -20; // Base upward velocity if (isPerfect) { // Perfect shot - guaranteed swish trajectory var targetX = targetHoop.x; var targetY = targetHoop.y - 350; // Aim directly at hoop center for clean entry var deltaX = targetX - startX; var deltaY = targetY - startY; // Calculate perfect parabolic trajectory for guaranteed swish var time = 45; // Optimized timing for better arc var gravity = 0.5; // Match basketball gravity // Calculate initial velocities for perfect arc velocityX = deltaX / time; velocityY = deltaY / time - 0.5 * gravity * time - 1.5; // Enhanced downward bias // Fine-tune for guaranteed swish - ensure ball enters hoop cleanly var horizontalAdjustment = (targetX - startX) * 0.02; // Small correction factor var verticalAdjustment = -1; // Additional downward bias for clean entry velocityX += horizontalAdjustment; velocityY += verticalAdjustment; // Create perfect shot basketball var ball = createBasketball(startX, startY, velocityX, velocityY); ball.isPerfectShot = true; // Ensure ball will score by setting special trajectory flag ball.guaranteedSwish = true; // Set additional properties to ensure scoring ball.hasScored = false; // Ensure it can score ball.isActive = true; // Ensure it's active // Visual feedback for perfect shot removed // Ball color tinting removed to prevent color changes // Add vertical rotation animation tween(ball, { rotation: ball.rotation + Math.PI * 4 }, { duration: 1500, easing: tween.easeOut }); } else { // Regular shot with some randomness velocityX = (Math.random() - 0.5) * 8; velocityY = -16 - Math.random() * 8; var ball = createBasketball(startX, startY, velocityX, velocityY); // Add vertical rotation animation for regular shot tween(ball, { rotation: ball.rotation + Math.PI * 3 }, { duration: 1200, easing: tween.easeOut }); } lastShotTime = LK.ticks; } else { // Start charging shot isChargingShot = true; currentShotBar.startMoving(); swipeStartX = x; swipeStartY = y; swipeStartTime = LK.ticks; } }; game.up = function (x, y, obj) { // Shot bar system handles shooting now, remove swipe-based shooting }; game.update = function () { // Only run gameplay logic when in playing state if (gameState !== 'playing') { return; } // Update basketballs for (var i = basketballs.length - 1; i >= 0; i--) { var ball = basketballs[i]; if (!ball.isActive) { ball.destroy(); basketballs.splice(i, 1); continue; } } // Clean up orphaned reflections for (var i = ballReflections.length - 1; i >= 0; i--) { var reflection = ballReflections[i]; if (!reflection.parentBall || !reflection.parentBall.isActive) { reflection.destroy(); ballReflections.splice(i, 1); } // Check for scoring checkBasketScore(ball); // Check collision with other basketballs for (var j = i + 1; j < basketballs.length; j++) { var otherBall = basketballs[j]; if (!otherBall.isActive) continue; var dx = ball.x - otherBall.x; var dy = ball.y - otherBall.y; var distance = Math.sqrt(dx * dx + dy * dy); var minDistance = 120; // Combined radius of two basketballs if (distance < minDistance && distance > 0) { // Calculate collision normal var normalX = dx / distance; var normalY = dy / distance; // Separate balls to prevent overlap var overlap = minDistance - distance; var separationX = normalX * overlap * 0.5; var separationY = normalY * overlap * 0.5; ball.x += separationX; ball.y += separationY; otherBall.x -= separationX; otherBall.y -= separationY; // Calculate relative velocity var relativeVelX = ball.velocityX - otherBall.velocityX; var relativeVelY = ball.velocityY - otherBall.velocityY; // Calculate relative velocity along collision normal var relativeSpeed = relativeVelX * normalX + relativeVelY * normalY; // Only resolve if objects are moving towards each other if (relativeSpeed > 0) continue; // Calculate impulse scalar (assuming equal mass) var impulse = -2 * relativeSpeed / 2; var impulseX = impulse * normalX; var impulseY = impulse * normalY; // Apply impulse with bounce decay var bounceDecay = 0.8; ball.velocityX += impulseX * bounceDecay; ball.velocityY += impulseY * bounceDecay; otherBall.velocityX -= impulseX * bounceDecay; otherBall.velocityY -= impulseY * bounceDecay; // Play bounce sound LK.getSound('bounce').play(); } } } // Streak is only reset when player misses a shot (handled in Basketball class) // No automatic reset when no balls are active // Handle break countdown in swish mode if (isInBreak && gameMode === 'swish') { // Update break countdown every 60 frames (1 second) if (LK.ticks % 60 === 0 && breakCountdown > 0) { breakCountdown--; if (breakCountdown > 0) { updateBreakCountdown(); } else { // Break is over endBreakCountdown(); } } } // Update timer (pause during break in swish mode) if (!gameEnded && (!isInBreak || gameMode !== 'swish')) { gameTimer--; var newTimeLeft = Math.floor(gameTimer / 60); if (newTimeLeft !== gameTimeLeft && newTimeLeft >= 0) { gameTimeLeft = newTimeLeft; // Update timer display using number assets updateTimerDisplay(gameTimeLeft); } // In swish mode, trigger break every 60 seconds if (gameMode === 'swish' && !isInBreak && gameTimeLeft <= 0) { startBreakCountdown(); // Apply reduced timer (60 seconds minus cumulative reductions) var adjustedTime = Math.max(10, 60 - swishModeTimerReduction); // Minimum 10 seconds gameTimer = adjustedTime * 60; // Convert to frames at 60 FPS gameTimeLeft = adjustedTime; updateTimerDisplay(adjustedTime); } // Check if time is up if (gameTimer <= 0 && !gameEnded) { gameEnded = true; updateTimerDisplay(0); // Check and update best score for current mode var currentScore = LK.getScore(); if (gameMode === '2player') { // 2 Player battle mode time handling if (twoPlayerState === 'player1') { // Player 1's turn is over, record score and transition to player 2 player1Score = currentScore; player1ScoreTxt.setText('P1: ' + player1Score); // Start transition phase twoPlayerState = 'transition'; transitionTimer = 3 * 60; // 3 second transition if (twoPlayerRhythmMode) { createTransitionOverlay('PLAYER 2 RHYTHM - BEAT ' + player1Score + ' POINTS!'); } else { createTransitionOverlay('PLAYER 2 - BEAT ' + player1Score + ' POINTS!'); } } else if (twoPlayerState === 'player2') { // Player 2's turn is over, determine winner player2Score = currentScore; player2ScoreTxt.setText('P2: ' + player2Score); // Determine winner and show results if (player2Score > player1Score) { if (twoPlayerRhythmMode) { createWinnerOverlay('PLAYER 2 WINS RHYTHM BATTLE!', 'Score: ' + player2Score + ' vs ' + player1Score); } else { createWinnerOverlay('PLAYER 2 WINS!', 'Score: ' + player2Score + ' vs ' + player1Score); } } else if (player1Score > player2Score) { if (twoPlayerRhythmMode) { createWinnerOverlay('PLAYER 1 WINS RHYTHM BATTLE!', 'Score: ' + player1Score + ' vs ' + player2Score); } else { createWinnerOverlay('PLAYER 1 WINS!', 'Score: ' + player1Score + ' vs ' + player2Score); } } else { if (twoPlayerRhythmMode) { createWinnerOverlay('RHYTHM BATTLE TIE!', 'Both scored: ' + player1Score); } else { createWinnerOverlay('TIE GAME!', 'Both scored: ' + player1Score); } } } } else if (gameMode === 'ai_vs') { // AI vs mode - determine winner if (aiOpponent && currentScore > aiOpponent.score) { // Player wins cleanupUIElements(); LK.showYouWin(); } else if (aiOpponent && currentScore < aiOpponent.score) { // AI wins cleanupUIElements(); LK.showGameOver(); } else { // Tie game cleanupUIElements(); LK.showGameOver(); // Could be modified to show tie message } } else if (gameMode === 'rhythm') { if (currentScore > rhythmBestScore) { rhythmBestScore = currentScore; storage.rhythmBestScore = rhythmBestScore; bestScore = rhythmBestScore; bestScoreTxt.setText('Best: ' + bestScore); } cleanupUIElements(); LK.showGameOver(); } else { if (currentScore > swishBestScore) { swishBestScore = currentScore; storage.swishBestScore = swishBestScore; bestScore = swishBestScore; bestScoreTxt.setText('Best: ' + bestScore); } cleanupUIElements(); LK.showGameOver(); } } } // Handle countdown timer for 2 player mode if (gameMode === '2player' && countdownActive) { if (LK.ticks % 60 === 0 && countdownTimer > 0) { countdownTimer--; if (countdownTimer > 0) { updateCountdownDisplay(); } else { // Countdown finished updateCountdownDisplay(); // Show "GO!" LK.setTimeout(function () { hideCountdownOverlay(); gameEnded = false; // Resume game }, 1000); } } } // Handle 2 player mode transitions if (gameMode === '2player' && twoPlayerState === 'transition') { transitionTimer--; if (transitionTimer <= 0) { // Transition is over, start player 2's turn hideTransitionOverlay(); twoPlayerState = 'player2'; // Reset game state for player 2 LK.setScore(0); scoreTxt.setText('Score: 0'); currentStreak = 0; if (streakTxt) { //{vi_new} streakTxt.setText('Streak: 0'); } //{vi_end} streakRewardsAwarded = []; // Reset rhythm mode specific variables if in rhythm mode if (twoPlayerRhythmMode) { rhythmStreak = 0; rhythmMultiplier = 1; // Clear existing rhythm circles for (var rc = 0; rc < rhythmCircles.length; rc++) { if (rhythmCircles[rc]) { rhythmCircles[rc].destroy(); } } rhythmCircles = []; rhythmCircleSpawnTimer = 0; // Keep music playing for player 2 in rhythm mode musicStarted = true; } // Reset timer for player 2 if (twoPlayerRhythmMode) { // 90 seconds for rhythm mode twoPlayerTimer = 90 * 60; twoPlayerTimeLeft = 90; updateTimerDisplay(90); } else { // 90 seconds for swish mode twoPlayerTimer = 90 * 60; twoPlayerTimeLeft = 90; updateTimerDisplay(90); } gameTimer = twoPlayerTimer; gameTimeLeft = twoPlayerTimeLeft; // Ensure timer variables are properly synchronized for 2 player rhythm mode if (twoPlayerRhythmMode) { gameTimer = 90 * 60; // 90 seconds at 60 FPS gameTimeLeft = 90; twoPlayerTimer = gameTimer; twoPlayerTimeLeft = gameTimeLeft; } // Reset shot bar speed to default for player 2's turn (only if shot bars exist) if (shotBar) { shotBar.moveSpeed = 8; } if (shotBar2) { shotBar2.moveSpeed = 8; } if (shotBar3) { shotBar3.moveSpeed = 8; } // Update current player display var modeText = twoPlayerRhythmMode ? 'RHYTHM' : 'SWISH'; currentPlayerTxt.setText('PLAYER 2 - ' + modeText + ' - BEAT ' + player1Score + '!'); currentPlayerTxt.tint = 0xFF4444; // Red for player 2 player2ScoreTxt.tint = 0xFF4444; // Highlight player 2 score // Start countdown for player 2 createCountdownOverlay('PLAYER 2 GET READY!', 5); gameEnded = true; // Pause game during countdown } } // Handle shot bar speed increase every 30 seconds in 2 player mode (only if not rhythm mode) if (gameMode === '2player' && !gameEnded && !twoPlayerRhythmMode) { var elapsedSeconds = Math.floor(90 - gameTimeLeft); var speedMultiplier = 1 + Math.floor(elapsedSeconds / 30) * 0.5; // Increase speed by 50% every 30 seconds // Apply speed multiplier to all shot bars if (shotBar && speedMultiplier > 1) { shotBar.moveSpeed = 8 * speedMultiplier; } if (shotBar2 && speedMultiplier > 1) { shotBar2.moveSpeed = 8 * speedMultiplier; } if (shotBar3 && speedMultiplier > 1) { shotBar3.moveSpeed = 8 * speedMultiplier; } } // Handle shot bar speed increase every 20 seconds in AI battle mode if (gameMode === 'ai_vs' && !gameEnded) { var aiElapsedSeconds = Math.floor(90 - gameTimeLeft); var aiSpeedMultiplier = 1 + Math.floor(aiElapsedSeconds / 20) * 0.3; // Increase speed by 30% every 20 seconds // Apply speed multiplier to all shot bars using tween for smooth transition if (shotBar && aiSpeedMultiplier > shotBar.currentSpeedMultiplier) { shotBar.currentSpeedMultiplier = aiSpeedMultiplier; tween(shotBar, { moveSpeed: 8 * aiSpeedMultiplier }, { duration: 500, easing: tween.easeOut }); } if (shotBar2 && aiSpeedMultiplier > shotBar2.currentSpeedMultiplier) { shotBar2.currentSpeedMultiplier = aiSpeedMultiplier; tween(shotBar2, { moveSpeed: 8 * aiSpeedMultiplier }, { duration: 500, easing: tween.easeOut }); } if (shotBar3 && aiSpeedMultiplier > shotBar3.currentSpeedMultiplier) { shotBar3.currentSpeedMultiplier = aiSpeedMultiplier; tween(shotBar3, { moveSpeed: 8 * aiSpeedMultiplier }, { duration: 500, easing: tween.easeOut }); } } // Rhythm mode beat system if ((gameMode === 'rhythm' || gameMode === '2player' && twoPlayerRhythmMode) && beatIndicator) { // Check for beat timing if (LK.ticks - lastBeatTime >= beatInterval) { lastBeatTime = LK.ticks; // Animate beat indicator tween(beatIndicator, { scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(beatIndicator, { scaleX: 1.0, scaleY: 1.0 }, { duration: 400, easing: tween.easeIn }); } }); // Play beat sound LK.getSound('1').play(); } // Rhythm circle spawning and management if ((gameMode === 'rhythm' || gameMode === '2player' && twoPlayerRhythmMode) && musicStarted) { rhythmCircleSpawnTimer++; if (rhythmCircleSpawnTimer >= rhythmCircleSpawnInterval) { rhythmCircleSpawnTimer = 0; spawnRhythmCircle(); } // Update and cleanup rhythm circles for (var i = rhythmCircles.length - 1; i >= 0; i--) { var circle = rhythmCircles[i]; if (!circle.isActive) { circle.destroy(); rhythmCircles.splice(i, 1); } else { // Check if circle has passed the tap zone without being tapped correctly if (circle.targetShotBar && circle.hasPassed && circle.wasInGreenZone) { // Circle was in green zone but wasn't tapped correctly - reset streak currentStreak = 0; if (streakTxt) { //{we_new} streakTxt.setText('Streak: ' + currentStreak); } //{we_end} streakRewardsAwarded = []; // Reset streak rewards rhythmStreak = 0; rhythmMultiplier = 1; // Remove onfire effects from all nets when streak is reset and show nets if (hoop && hoop.onfire) { hoop.net.visible = true; hoop.onfire.destroy(); hoop.onfire = null; } if (leftHoop && leftHoop.onfire) { leftHoop.net.visible = true; leftHoop.onfire.destroy(); leftHoop.onfire = null; } if (rightHoop && rightHoop.onfire) { rightHoop.net.visible = true; rightHoop.onfire.destroy(); rightHoop.onfire = null; } // Mark as inactive to prevent multiple resets circle.isActive = false; } } } } } // Swish mode visualizer beat system at 125bpm if (gameMode === 'swish' && volumeVisualizerBars.length > 0) { //{lR_new1} var swishBeatInterval = 29; // 29 frames = ~125 BPM at 60 FPS var lastSwishBeatTime = lastSwishBeatTime || 0; // Check for beat timing at 125bpm if (LK.ticks - lastSwishBeatTime >= swishBeatInterval) { lastSwishBeatTime = LK.ticks; //{lR_new2} // Trigger volume visualizer pulse effect for (var v = 0; v < volumeVisualizerBars.length; v++) { var bar = volumeVisualizerBars[v]; var randomHeight = 0.5 + Math.random() * 2.0; // Random height between 0.5 and 2.5 for heavy response bar.targetHeight = randomHeight; // Cycle through neon colors var neonColors = [0xFF0080, 0x00FF80, 0x8000FF, 0xFF8000, 0x0080FF, 0x80FF00, 0xFF0040, 0x40FF00]; var randomColor = neonColors[Math.floor(Math.random() * neonColors.length)]; // Animate bar to target height and change color tween(bar, { scaleY: randomHeight * 1.5, tint: randomColor }, { //{lR_new3} duration: 300, //{lR_new4} easing: tween.easeOut, //{lR_new5} onFinish: function () { // Animate back to base height tween(this, { scaleY: 0.1 //{lR_new6} }, { //{lR_new7} duration: 800, //{lR_new8} easing: tween.easeIn //{lR_new9} }); //{lR_new10} }.bind(bar) }); //{lR_new11} } //{lR_new12} } //{lR_new13} } //{lR_new14} // Win condition removed - no score target };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
money: 0,
swishBestScore: 0,
rhythmBestScore: 0,
currentBasketballMode: "Warriorsball",
defaultPlayers: ["player1", "player2", "player3"]
});
/****
* Classes
****/
var AIOpponent = Container.expand(function () {
var self = Container.call(this);
//{7j_ai}
self.isActive = true;
self.score = 0;
self.difficulty = 1.8; // Difficulty multiplier - much harder base difficulty
self.shotTimer = 0;
self.shotInterval = 80; // Frames between AI shots (1.33 seconds at 60fps) - shoot much more frequently
self.targetHoop = null; // Which hoop AI is targeting
self.accuracy = 0.95; // Base accuracy percentage - near perfect accuracy
self.lastShotTime = 0;
self.perfectShotChance = 0.8; // 80% chance for perfect shots - extremely high
self.adaptiveTimer = 0; // Timer for adaptive difficulty
self.playerScoreWhenLastShot = 0; // Track player score for adaptive difficulty
self.update = function () {
if (!self.isActive || gameMode !== 'ai_vs') return;
// Adaptive difficulty - AI gets extremely aggressive if player is ahead
var scoreDifference = LK.getScore() - self.score;
if (scoreDifference > 4) {
self.difficulty = 3.0; // Massive difficulty increase
self.shotInterval = 60; // Shoot extremely frequently (1 second)
self.accuracy = 0.98; // Nearly perfect accuracy
self.perfectShotChance = 0.95; // Almost all shots are perfect
} else if (scoreDifference > 2) {
self.difficulty = 2.5; // Very high difficulty
self.shotInterval = 70; // 1.17 seconds
self.accuracy = 0.96;
self.perfectShotChance = 0.9;
} else if (scoreDifference > 0) {
self.difficulty = 2.0; // High difficulty
self.shotInterval = 80; // 1.33 seconds
self.accuracy = 0.94;
self.perfectShotChance = 0.85;
} else if (scoreDifference < -2) {
// AI is ahead, reduce difficulty slightly but still very challenging
self.difficulty = 1.5;
self.shotInterval = 100; // 1.67 seconds
self.accuracy = 0.9;
self.perfectShotChance = 0.7;
} else {
// Normal difficulty - much harder than before
self.difficulty = 1.8;
self.shotInterval = 80; // 1.33 seconds
self.accuracy = 0.95;
self.perfectShotChance = 0.8;
}
self.shotTimer++;
if (self.shotTimer >= self.shotInterval) {
self.takeShot();
self.shotTimer = 0;
}
};
self.takeShot = function () {
// Randomly choose a hoop to target
var availableHoops = [hoop, leftHoop, rightHoop];
self.targetHoop = availableHoops[Math.floor(Math.random() * availableHoops.length)];
// Determine shot position based on target hoop
var startX, startY;
if (self.targetHoop === leftHoop) {
startX = 300 + (Math.random() - 0.5) * 100; // Some randomness
startY = 2000;
} else if (self.targetHoop === rightHoop) {
startX = 1748 + (Math.random() - 0.5) * 100;
startY = 2000;
} else {
startX = 1024 + (Math.random() - 0.5) * 100;
startY = 2000;
}
// Determine if this will be a perfect shot
var isPerfectShot = Math.random() < self.perfectShotChance;
var ball = new Basketball();
ball.x = startX;
ball.y = startY;
ball.isAIShot = true; // Mark as AI shot
ball.aiOpponent = self; // Reference to AI for scoring
if (isPerfectShot || Math.random() < self.accuracy) {
// Accurate shot
var targetX = self.targetHoop.x;
var targetY = self.targetHoop.y - 350;
var deltaX = targetX - startX;
var deltaY = targetY - startY;
var time = 45;
var gravity = 0.5;
ball.velocityX = deltaX / time + (Math.random() - 0.5) * 2; // Small randomness
ball.velocityY = deltaY / time - 0.5 * gravity * time - 1.5;
if (isPerfectShot) {
ball.guaranteedSwish = true;
ball.isPerfectShot = true;
}
} else {
// Inaccurate shot
ball.velocityX = (self.targetHoop.x - startX) / 50 + (Math.random() - 0.5) * 8;
ball.velocityY = -16 - Math.random() * 8;
}
basketballs.push(ball);
game.addChild(ball);
// Create reflection
var reflection = new BallReflection();
reflection.parentBall = ball;
ballReflections.push(reflection);
game.addChild(reflection);
// Add rotation
tween(ball, {
rotation: ball.rotation + Math.PI * 3
}, {
duration: 1200,
easing: tween.easeOut
});
self.lastShotTime = LK.ticks;
};
return self;
});
var BallReflection = Container.expand(function () {
var self = Container.call(this);
var basketballAsset = getBasketballAsset();
var reflectionGraphics = self.attachAsset(basketballAsset, {
anchorX: 0.5,
anchorY: 0.5
});
// Make reflection more transparent and darker
reflectionGraphics.alpha = 0.3;
reflectionGraphics.tint = 0x666666;
// Flip reflection vertically
reflectionGraphics.scaleY = -0.8; // Flipped and slightly smaller
reflectionGraphics.scaleX = 0.8;
// Set z-index to render on floor
reflectionGraphics.zIndex = -3;
self.parentBall = null;
self.floorY = 1832; // Move floor up 900 pixels (700 + 200)
self.update = function () {
if (!self.parentBall || !self.parentBall.isActive) {
self.destroy();
return;
}
// Position reflection below the ball
self.x = self.parentBall.x;
self.y = self.floorY - (self.floorY - self.parentBall.y) * 0.2; // Reflection distance from floor
// Match parent ball rotation
self.rotation = self.parentBall.rotation;
// Fade reflection based on ball height
var heightFactor = Math.max(0, (self.floorY - self.parentBall.y) / 1000);
reflectionGraphics.alpha = 0.3 * heightFactor;
};
return self;
});
var Basketball = Container.expand(function () {
var self = Container.call(this);
var basketballAsset = getBasketballAsset();
var ballGraphics = self.attachAsset(basketballAsset, {
anchorX: 0.5,
anchorY: 0.5
});
// Set z-index to render in front of player1
ballGraphics.zIndex = 2;
self.velocityX = 0;
self.velocityY = 0;
self.gravity = 0.5;
self.bounceDecay = 0.7;
self.hasScored = false;
self.isActive = true;
self.guaranteedSwish = false;
self.update = function () {
if (!self.isActive) return;
// Add fire effect when streak is beyond 5
if (currentStreak > 5 && !self.fireEffect) {
self.fireEffect = true;
// Create fire-like effect with orange/red tinting and scaling
var _fireAnimation = function fireAnimation() {
if (!self.isActive) return;
var fireColors = [0xFF4500, 0xFF6347, 0xFF8C00, 0xFFD700, 0xFF0000];
var randomColor = fireColors[Math.floor(Math.random() * fireColors.length)];
tween(ballGraphics, {
tint: randomColor,
scaleX: 1.1 + Math.random() * 0.2,
scaleY: 1.1 + Math.random() * 0.2
}, {
duration: 100 + Math.random() * 100,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (self.isActive && currentStreak > 5) {
_fireAnimation();
} else {
// Reset to normal appearance when streak drops
tween(ballGraphics, {
tint: 0xFFFFFF,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200,
easing: tween.easeOut
});
self.fireEffect = false;
}
}
});
};
_fireAnimation();
}
self.velocityY += self.gravity;
self.x += self.velocityX;
self.y += self.velocityY;
// Check hoop collision for all hoops
var hoopsToCheck = [hoop];
if (typeof leftHoop !== 'undefined') {
hoopsToCheck.push(leftHoop);
}
if (typeof rightHoop !== 'undefined') {
hoopsToCheck.push(rightHoop);
}
for (var hoopIndex = 0; hoopIndex < hoopsToCheck.length; hoopIndex++) {
var currentHoop = hoopsToCheck[hoopIndex];
if (currentHoop) {
var hoopX = currentHoop.x;
var hoopY = currentHoop.y - 350; // Adjust for hoop position within container
var relativeX = self.x - hoopX;
var relativeY = self.y - hoopY;
// Check for scoring through hoop first (ball going through net area)
// For guaranteed swish shots, use much more lenient detection
var hoopDetectionWidth = self.guaranteedSwish ? 120 : 60;
var hoopDetectionTop = self.guaranteedSwish ? -35 : -10;
var hoopDetectionBottom = self.guaranteedSwish ? 80 : 50;
if (Math.abs(relativeX) <= hoopDetectionWidth && relativeY >= hoopDetectionTop && relativeY <= hoopDetectionBottom && self.velocityY > 0 && !self.hasScored) {
// Ball is going through hoop - animate net and score
self.hasScored = true;
self.isActive = false;
// Set ball to render behind net and hoop
ballGraphics.zIndex = -2;
// Animate ball going through and down
tween(self, {
y: self.y + 100,
x: hoopX + (Math.random() - 0.5) * 20
}, {
duration: 500,
easing: tween.easeIn
});
// Animate net pulsate
tween(currentHoop.net, {
scaleX: 1.8,
scaleY: 1.8
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(currentHoop.net, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeIn
});
}
});
// Replace net with onfire asset when streak is beyond 5
if (currentStreak > 5) {
// Check if onfire asset doesn't already exist on this net
if (!currentHoop.onfire) {
// Hide the original net
currentHoop.net.visible = false;
currentHoop.onfire = currentHoop.addChild(LK.getAsset('Onfire', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: currentHoop.net.scaleX,
scaleY: currentHoop.net.scaleY
}));
currentHoop.onfire.x = currentHoop.net.x; // Same as net
currentHoop.onfire.y = currentHoop.net.y + 150; // Move down 150 pixels from net position (down 20 from previous)
currentHoop.onfire.zIndex = 3; // Above net
currentHoop.onfire.alpha = 1.0;
// Play onfire sound when onfire asset replaces net
LK.getSound('Onfire').play();
}
// Animate onfire asset pulsate when scored
if (currentHoop.onfire) {
//{1u_new}
tween(currentHoop.onfire, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 1.0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
if (currentHoop.onfire) {
//{1C_new}
tween(currentHoop.onfire, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.9
}, {
duration: 200,
easing: tween.easeIn
});
} //{1L_new}
}
});
} //{1M_new}
// Animate onfire asset to make it look on fire
var _onfireAnimation = function onfireAnimation() {
if (!currentHoop.onfire || currentStreak <= 5) return;
var fireColors = [0xFFFFFF, 0xFFFF00, 0xFFA500, 0xFF6347, 0xFF4500, 0xFF0000];
var randomColor = fireColors[Math.floor(Math.random() * fireColors.length)];
tween(currentHoop.onfire, {
tint: randomColor,
scaleX: 1.0 + Math.random() * 0.3,
scaleY: 1.0 + Math.random() * 0.3,
alpha: 0.9 + Math.random() * 0.1
}, {
duration: 100 + Math.random() * 100,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (currentHoop.onfire && currentStreak > 5) {
_onfireAnimation();
} else if (currentHoop.onfire && currentStreak <= 5) {
// Remove onfire effect when streak is over and show net
currentHoop.net.visible = true;
currentHoop.onfire.destroy();
currentHoop.onfire = null;
}
}
});
};
_onfireAnimation();
}
// Score the basket
// Check if this is an AI shot
if (self.isAIShot && self.aiOpponent) {
// AI scored - increment AI score
self.aiOpponent.score += 2;
if (aiScoreTxt) {
aiScoreTxt.setText('AI: ' + self.aiOpponent.score);
}
// Early return to prevent AI shots from affecting player scores
return;
} else {
// Player scored - increment player streak
currentStreak++;
}
// Check for streak rewards
var moneyEarned = 0;
if (currentStreak === 10 && streakRewardsAwarded.indexOf(10) === -1) {
moneyEarned = 20.00;
streakRewardsAwarded.push(10);
} else if (currentStreak === 20 && streakRewardsAwarded.indexOf(20) === -1) {
moneyEarned = 50.00;
streakRewardsAwarded.push(20);
} else if (currentStreak === 30 && streakRewardsAwarded.indexOf(30) === -1) {
moneyEarned = 75.00;
streakRewardsAwarded.push(30);
} else if (currentStreak === 50 && streakRewardsAwarded.indexOf(50) === -1) {
moneyEarned = 100.00;
streakRewardsAwarded.push(50);
}
if (moneyEarned > 0) {
currentMoney += moneyEarned;
storage.money = currentMoney;
if (moneyTxt) {
moneyTxt.setText('$' + currentMoney.toFixed(2));
}
LK.getSound('Cash').play(); // Play cash sound when money is awarded
}
var points = 2;
if (self.isPerfectShot) {
// Use cycling color for perfect shot
var flashColor = basketColors[currentColorIndex];
}
// 2x multiplier removed - no longer applied when all backboards are same color
// Apply rhythm multiplier if in rhythm mode
if (typeof rhythmMultiplier !== 'undefined' && rhythmMultiplier > 1) {
points = Math.floor(points * rhythmMultiplier);
}
LK.setScore(LK.getScore() + points);
// In rhythm mode, check if score reached multiple of 50 points to reset timer
if (gameMode === 'rhythm') {
var currentScore = LK.getScore();
var previousScore = currentScore - points;
var currentFifties = Math.floor(currentScore / 50);
var previousFifties = Math.floor(previousScore / 50);
if (currentFifties > previousFifties) {
gameTimer = 15 * 60; // Reset to 15 seconds for rhythm mode at 60 FPS
gameTimeLeft = 15;
updateTimerDisplay(15);
}
}
// Play different sound based on which hoop scored
if (currentHoop === leftHoop) {
LK.getSound('1').play();
} else if (currentHoop === rightHoop) {
LK.getSound('3').play();
} else {
LK.getSound('2').play();
}
if (scoreTxt) {
scoreTxt.setText('Score: ' + LK.getScore());
}
if (streakTxt) {
//{3W_new}
streakTxt.setText('Streak: ' + currentStreak);
} //{3W_end}
// Animate backboard color change
var backboard = currentHoop.children[0]; // Get the backboard (first child)
if (self.isPerfectShot) {
// For perfect shots, use cycling color directly
var flashColor = basketColors[currentColorIndex];
// Cycle to next color for next basket
currentColorIndex = (currentColorIndex + 1) % basketColors.length;
// Track which backboard was scored on and update color tracking
var hoopIndex = 0; // Default to center hoop
if (currentHoop === leftHoop) hoopIndex = 1;
if (currentHoop === rightHoop) hoopIndex = 2;
backboardColors[hoopIndex] = flashColor;
tween(backboard, {
tint: flashColor
}, {
duration: 300,
easing: tween.easeOut
});
// Check if all backboards now have same color
checkAllBackboardsSameColor();
// Play different sound based on which hoop scored when backboard changes color
if (currentHoop === leftHoop) {
LK.getSound('1').play();
} else if (currentHoop === rightHoop) {
LK.getSound('3').play();
} else {
LK.getSound('2').play();
}
} else {
// For regular shots, use cycling color directly
var flashColor = basketColors[currentColorIndex];
// Cycle to next color for next basket
currentColorIndex = (currentColorIndex + 1) % basketColors.length;
// Track which backboard was scored on and update color tracking
var hoopIndex = 0; // Default to center hoop
if (currentHoop === leftHoop) hoopIndex = 1;
if (currentHoop === rightHoop) hoopIndex = 2;
backboardColors[hoopIndex] = flashColor;
tween(backboard, {
tint: flashColor
}, {
duration: 300,
easing: tween.easeOut
});
// Check if all backboards now have same color
checkAllBackboardsSameColor();
// Play different sound based on which hoop scored when backboard changes color
if (currentHoop === leftHoop) {
LK.getSound('1').play();
} else if (currentHoop === rightHoop) {
LK.getSound('3').play();
} else {
LK.getSound('2').play();
}
}
return;
}
// Check if ball is hitting the hoop rim
if (relativeX >= -125 && relativeX <= 125 && relativeY >= -25 && relativeY <= 25) {
// Determine which side of the hoop was hit
if (Math.abs(relativeX) > 90) {
// Hit the sides of the rim
self.velocityX = -self.velocityX * self.bounceDecay;
if (relativeX < 0) {
self.x = hoopX - 125;
} else {
self.x = hoopX + 125;
}
LK.getSound('bounce').play();
} else if (relativeY >= -25 && relativeY <= 0 && self.velocityY > 0) {
// Hit the top of the rim (bouncing up)
self.velocityY = -Math.abs(self.velocityY) * self.bounceDecay;
self.y = hoopY - 25;
self.velocityX *= 0.8; // Reduce horizontal velocity slightly
LK.getSound('bounce').play();
}
}
// Check if ball is resting on the rim (low velocity and on top)
if (Math.abs(relativeX) <= 90 && relativeY >= -30 && relativeY <= -20 && Math.abs(self.velocityY) < 2 && Math.abs(self.velocityX) < 3) {
// Ball is resting on rim, make it roll into the hoop
self.isActive = false; // Stop normal physics
self.hasScored = true; // Mark as scored
// Set ball to render behind net and hoop
ballGraphics.zIndex = -2;
// Animate rolling into hoop
tween(self, {
x: hoopX,
y: hoopY + 40,
rotation: self.rotation + Math.PI * 2
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
// Animate net pulsate
tween(currentHoop.net, {
scaleX: 1.8,
scaleY: 1.8
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(currentHoop.net, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeIn
});
}
});
// Replace net with onfire asset when streak is beyond 5
if (currentStreak > 5) {
// Check if onfire asset doesn't already exist on this net
if (!currentHoop.onfire) {
// Hide the original net
currentHoop.net.visible = false;
currentHoop.onfire = currentHoop.addChild(LK.getAsset('Onfire', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: currentHoop.net.scaleX,
scaleY: currentHoop.net.scaleY
}));
currentHoop.onfire.x = currentHoop.net.x; // Same as net
currentHoop.onfire.y = currentHoop.net.y + 150; // Move down 150 pixels from net position (down 20 from previous)
currentHoop.onfire.zIndex = 3; // Above net
currentHoop.onfire.alpha = 1.0;
// Play onfire sound when onfire asset replaces net
LK.getSound('Onfire').play();
}
// Animate onfire asset pulsate when scored
if (currentHoop.onfire) {
//{4L_new}
tween(currentHoop.onfire, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 1.0
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
if (currentHoop.onfire) {
//{4T_new}
tween(currentHoop.onfire, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.9
}, {
duration: 200,
easing: tween.easeIn
});
} //{52_new}
}
});
} //{53_new}
// Animate onfire asset to make it look on fire
var _onfireAnimation = function onfireAnimation() {
if (!currentHoop.onfire || currentStreak <= 5) return;
var fireColors = [0xFFFFFF, 0xFFFF00, 0xFFA500, 0xFF6347, 0xFF4500, 0xFF0000];
var randomColor = fireColors[Math.floor(Math.random() * fireColors.length)];
tween(currentHoop.onfire, {
tint: randomColor,
scaleX: 1.0 + Math.random() * 0.3,
scaleY: 1.0 + Math.random() * 0.3,
alpha: 0.9 + Math.random() * 0.1
}, {
duration: 100 + Math.random() * 100,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (currentHoop.onfire && currentStreak > 5) {
_onfireAnimation();
} else if (currentHoop.onfire && currentStreak <= 5) {
// Remove onfire effect when streak is over and show net
currentHoop.net.visible = true;
currentHoop.onfire.destroy();
currentHoop.onfire = null;
}
}
});
};
_onfireAnimation();
}
// Score the basket
// Check if this is an AI shot
if (self.isAIShot && self.aiOpponent) {
// AI scored - increment AI score
self.aiOpponent.score += 2;
if (aiScoreTxt) {
aiScoreTxt.setText('AI: ' + self.aiOpponent.score);
}
return; // Early return to prevent AI shots from affecting player scores
} else {
// Player scored - increment player streak
currentStreak++;
}
// Check for streak rewards
if (currentStreak === 10 && streakRewardsAwarded.indexOf(10) === -1) {
currentMoney += 20.00;
storage.money = currentMoney;
if (moneyTxt) {
moneyTxt.setText('$' + currentMoney.toFixed(2));
}
streakRewardsAwarded.push(10);
LK.getSound('Cash').play(); // Play cash sound when money is awarded
} else if (currentStreak === 20 && streakRewardsAwarded.indexOf(20) === -1) {
currentMoney += 50.00;
storage.money = currentMoney;
if (moneyTxt) {
moneyTxt.setText('$' + currentMoney.toFixed(2));
}
streakRewardsAwarded.push(20);
LK.getSound('Cash').play(); // Play cash sound when money is awarded
} else if (currentStreak === 30 && streakRewardsAwarded.indexOf(30) === -1) {
currentMoney += 75.00;
storage.money = currentMoney;
if (moneyTxt) {
moneyTxt.setText('$' + currentMoney.toFixed(2));
}
streakRewardsAwarded.push(30);
LK.getSound('Cash').play(); // Play cash sound when money is awarded
} else if (currentStreak === 50 && streakRewardsAwarded.indexOf(50) === -1) {
currentMoney += 100.00;
storage.money = currentMoney;
if (moneyTxt) {
moneyTxt.setText('$' + currentMoney.toFixed(2));
}
streakRewardsAwarded.push(50);
LK.getSound('Cash').play(); // Play cash sound when money is awarded
}
var points = 2;
// 2x multiplier removed - no longer applied when all backboards are same color
LK.setScore(LK.getScore() + points);
// In rhythm mode, check if score reached multiple of 50 points to reset timer
if (gameMode === 'rhythm') {
var currentScore = LK.getScore();
var previousScore = currentScore - points;
var currentFifties = Math.floor(currentScore / 50);
var previousFifties = Math.floor(previousScore / 50);
if (currentFifties > previousFifties) {
gameTimer = 15 * 60; // Reset to 15 seconds for rhythm mode at 60 FPS
gameTimeLeft = 15;
updateTimerDisplay(15);
}
}
// Play different sound based on which hoop scored
if (currentHoop === leftHoop) {
LK.getSound('1').play();
} else if (currentHoop === rightHoop) {
LK.getSound('3').play();
} else {
LK.getSound('2').play();
}
// Update displays
if (scoreTxt) {
scoreTxt.setText('Score: ' + LK.getScore());
}
if (streakTxt) {
//{7w_new}
streakTxt.setText('Streak: ' + currentStreak);
} //{7w_end}
// Animate backboard color change
var backboard = currentHoop.children[0]; // Get the backboard (first child)
var flashColor = basketColors[currentColorIndex];
// Cycle to next color for next basket
currentColorIndex = (currentColorIndex + 1) % basketColors.length;
// Track which backboard was scored on and update color tracking
var hoopIndex = 0; // Default to center hoop
if (currentHoop === leftHoop) hoopIndex = 1;
if (currentHoop === rightHoop) hoopIndex = 2;
backboardColors[hoopIndex] = flashColor;
tween(backboard, {
tint: flashColor
}, {
duration: 300,
easing: tween.easeOut
});
// Check if all backboards now have same color
checkAllBackboardsSameColor();
// Play different sound based on which hoop scored when backboard changes color
if (currentHoop === leftHoop) {
LK.getSound('1').play();
} else if (currentHoop === rightHoop) {
LK.getSound('3').play();
} else {
LK.getSound('2').play();
}
}
});
}
}
}
// Ground collision removed - ball can fall through
// Remove if off screen - ball is just removed, no streak penalty
if (self.x < -100 || self.x > 2148 || self.y > 2800) {
self.isActive = false;
}
};
return self;
});
var Hoop = Container.expand(function () {
var self = Container.call(this);
var backboard = self.attachAsset('backboard', {
anchorX: 0.5,
anchorY: 1
});
backboard.y = -20;
var hoop = self.attachAsset('hoop', {
anchorX: 0.5,
anchorY: 0.5
});
hoop.y = -350;
// Set z-index to render in front of basketball
hoop.zIndex = 1;
var net = self.attachAsset('net', {
anchorX: 0.5,
anchorY: 0,
scaleX: 1.5,
scaleY: 1.5
});
net.y = -325;
net.alpha = 0.8;
// Set z-index to render in front of basketball
net.zIndex = 2;
// Store net reference for animation access
self.net = net;
self.hoopBounds = {
left: -90,
right: 90,
top: -20,
bottom: 20
};
// Enable z-index sorting for proper rendering order
self.sortableChildren = true;
return self;
});
var RhythmCircle = Container.expand(function () {
var self = Container.call(this);
// Create circle graphic using greenBall asset with scale and tint for rhythm indicator
var circleGraphics = self.attachAsset('greenBall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
circleGraphics.tint = 0xFF6B6B; // Pink tint for rhythm circles
circleGraphics.alpha = 0.8;
// Set z-index to render above most elements
circleGraphics.zIndex = 15;
self.fallSpeed = 6;
self.isActive = true;
self.targetShotBar = null; // Which shot bar this circle is aligned with
self.wasInGreenZone = false;
self.hasPassed = false;
self.hasBeenTapped = false; // Track if this circle has already triggered a shot
// Store the Y position of the green zone for this circle's target shot bar
self.greenZoneY = 0;
self.update = function () {
if (!self.isActive) return;
// Fall downward
self.y += self.fallSpeed;
// Check if circle has reached the green zone area of target shot bar
if (self.targetShotBar && self.targetShotBar.children && self.targetShotBar.children.length > 2) {
var greenZone = self.targetShotBar.children[1]; // Second child should be green zone
var indicator = self.targetShotBar.children[2]; // Third child is the basketball indicator
var shotBarWorldY = self.targetShotBar.y; // Shot bar's world Y position
var tolerance = 60; // Match the green zone tolerance
// Check if circle is in the green zone area (aligned with shot bar position)
var inGreenZone = Math.abs(self.y - shotBarWorldY) <= tolerance;
if (inGreenZone && !self.wasInGreenZone) {
self.wasInGreenZone = true;
// Store the green zone Y position for this circle
self.greenZoneY = shotBarWorldY;
// Pulse effect when entering green zone
tween(circleGraphics, {
scaleX: 1.6,
scaleY: 1.6,
alpha: 1.0
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(circleGraphics, {
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.8
}, {
duration: 150,
easing: tween.easeIn
});
}
});
}
// Check if circle has passed the green zone
if (self.y > shotBarWorldY + tolerance && !self.hasPassed) {
self.hasPassed = true;
}
}
// Remove if off screen
if (self.y > 2800) {
self.isActive = false;
}
};
return self;
});
var ShotBar = Container.expand(function () {
var self = Container.call(this);
if (gameMode === 'rhythm') {
// In rhythm mode, create horizontal tap zone instead of vertical shot bar
var tapZone = self.attachAsset('shotBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
// Keep horizontal orientation for tap zone
tapZone.scaleX = 1.2; // Make it wider for easier tapping
tapZone.scaleY = 2.0; // Make it taller for easier tapping
tapZone.tint = 0x00FF00; // Green color for tap zone
tapZone.alpha = 0.7; // Semi-transparent
} else {
// Swish mode: vertical shot bar (original implementation)
var bgBar = self.attachAsset('shotBarBg', {
anchorX: 0.5,
anchorY: 0.5
});
bgBar.rotation = Math.PI / 2 + Math.PI; // Rotate 90 degrees + 180 degrees to make vertical and flip
// Green zone - rotated to be vertical
var greenZone = self.attachAsset('shotBarGreen', {
anchorX: 0.5,
anchorY: 0.5
});
greenZone.rotation = Math.PI / 2 + Math.PI; // Rotate 90 degrees + 180 degrees to make vertical and flip
greenZone.y = 0; // Start at center, will move vertically
// Moving basketball indicator
var basketballAsset = getBasketballAsset();
var indicator = self.attachAsset(basketballAsset, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
self.greenZone = greenZone;
self.indicator = indicator;
}
self.isActive = false;
self.isMoving = false;
self.moveDirection = 1; // 1 for right, -1 for left
self.moveSpeed = 8;
self.maxDistance = 240; // Half of bar width minus indicator size
self.perfectShot = false;
self.startMoving = function () {
if (gameMode === 'rhythm') {
// In rhythm mode, tap zone is always active and visible
self.isActive = true;
self.visible = true;
return;
}
// Swish mode logic
self.isActive = true;
self.isMoving = true;
self.perfectShot = false;
// Position green zone randomly vertically
if (self.greenZone) {
self.greenZone.y = (Math.random() - 0.5) * 360; // Random position within vertical bar
}
// Reset indicator position vertically - start at top
if (self.indicator) {
self.indicator.y = -self.maxDistance;
}
self.moveDirection = 1; // Start moving downward
self.visible = true;
};
self.stopMoving = function () {
if (gameMode === 'rhythm') {
// In rhythm mode, always return perfect shot for tap zone
self.perfectShot = true;
return true;
}
// Swish mode logic
self.isMoving = false;
// Check if indicator is within green zone vertically
if (self.greenZone && self.indicator) {
var greenTop = self.greenZone.y - 60;
var greenBottom = self.greenZone.y + 60;
self.perfectShot = self.indicator.y >= greenTop && self.indicator.y <= greenBottom;
}
// Reset streak if player misses the green zone
if (!self.perfectShot) {
currentStreak = 0;
if (streakTxt) {
//{9z_new}
streakTxt.setText('Streak: ' + currentStreak);
} //{9z_end}
streakRewardsAwarded = []; // Reset streak rewards
// Remove onfire effects from all nets when streak is reset and show nets
if (hoop && hoop.onfire) {
hoop.net.visible = true;
hoop.onfire.destroy();
hoop.onfire = null;
}
if (leftHoop && leftHoop.onfire) {
leftHoop.net.visible = true;
leftHoop.onfire.destroy();
leftHoop.onfire = null;
}
if (rightHoop && rightHoop.onfire) {
rightHoop.net.visible = true;
rightHoop.onfire.destroy();
rightHoop.onfire = null;
}
}
// Keep shot bar visible and restart movement after a brief pause
var self_ref = self;
LK.setTimeout(function () {
self_ref.startMoving();
}, 200);
return self.perfectShot;
};
self.update = function () {
if (gameMode === 'rhythm' || !self.isMoving) return;
// Pause shot bar movement during break in swish mode
if (isInBreak && gameMode === 'swish') {
return; // Pause all shot bar movement during break
}
// Speed is now increased by break count instead of score
var currentSpeed = self.moveSpeed;
// Speed increase based on break count (number of breaks completed)
var breakMultiplier = Math.floor(swishModeTimerReduction / 5); // Each break reduces timer by 5 seconds
if (breakMultiplier > 0 && (!isInBreak || gameMode !== 'swish')) {
currentSpeed = self.moveSpeed * (1 + breakMultiplier * 0.5); // 50% speed increase per break
}
// Move indicator back and forth vertically
if (self.indicator) {
self.indicator.y += currentSpeed * self.moveDirection;
// Bounce off edges
if (self.indicator.y >= self.maxDistance) {
self.indicator.y = self.maxDistance;
self.moveDirection = -1;
} else if (self.indicator.y <= -self.maxDistance) {
self.indicator.y = -self.maxDistance;
self.moveDirection = 1;
}
}
};
self.visible = true;
return self;
});
// Title screen is now initialized - gameplay will be initialized when start is pressed
var Store = Container.expand(function () {
var self = Container.call(this);
// Add shop backdrop to the store
var shopBackdrop = self.attachAsset('Shopbackdrop', {
anchorX: 0,
anchorY: 0
});
shopBackdrop.x = 0;
shopBackdrop.y = 0;
shopBackdrop.width = 2048;
shopBackdrop.height = 2732;
shopBackdrop.zIndex = -1;
// Store items configuration
self.items = [{
id: 'pacersball',
name: 'Pacers Ball',
price: 500.00,
asset: 'Bballpacers',
unlocked: false
}, {
id: 'thunderball',
name: 'Thunder Ball',
price: 750.00,
asset: 'Bballthunder',
unlocked: false
}, {
id: '2playvs',
name: '2 Player Rhythm Pack',
price: 500.00,
asset: '2playvs',
unlocked: false
}, {
id: 'swish2playvs',
name: '2 Player Swish Pack',
price: 500.00,
asset: '2playvs',
unlocked: false
}, {
//{aq_new}
id: 'aibattle',
name: 'AI Battle Pack',
price: 500.00,
asset: 'Aibattle',
unlocked: false
}];
// Load unlocked items from storage
self.loadUnlockedItems = function () {
for (var i = 0; i < self.items.length; i++) {
var item = self.items[i];
item.unlocked = storage[item.id + '_unlocked'] || false;
}
};
// Save unlocked item to storage
self.saveUnlockedItem = function (itemId) {
storage[itemId + '_unlocked'] = true;
};
// Check if player can afford item
self.canAfford = function (item) {
return currentMoney >= item.price;
};
// Purchase item
self.purchaseItem = function (item) {
if (!self.canAfford(item) || item.unlocked) {
return false;
}
// Deduct money
currentMoney -= item.price;
storage.money = currentMoney;
// Unlock item
item.unlocked = true;
self.saveUnlockedItem(item.id);
// Play purchase sound
LK.getSound('Cash').play();
return true;
};
// Get item by id
self.getItem = function (itemId) {
for (var i = 0; i < self.items.length; i++) {
if (self.items[i].id === itemId) {
return self.items[i];
}
}
return null;
};
// Check if item is unlocked
self.isUnlocked = function (itemId) {
var item = self.getItem(itemId);
return item ? item.unlocked : false;
};
// Initialize store
self.loadUnlockedItems();
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Load saved data from storage or use defaults
currentMoney = storage.money || 0;
swishBestScore = storage.swishBestScore || 0;
rhythmBestScore = storage.rhythmBestScore || 0;
// Load saved basketball mode and players
var currentBasketballMode = storage.currentBasketballMode || defaultBasketballMode;
if (storage.defaultPlayers) {
defaultPlayers = storage.defaultPlayers;
}
// Create global store instance
var gameStore = new Store();
function showHowToPlay() {
// Create background using TitleBackground asset
var background = game.addChild(LK.getAsset('TitleBackground', {
anchorX: 0,
anchorY: 0
}));
background.x = 0;
background.y = 0;
background.width = 2048;
background.height = 2732;
background.zIndex = 49;
// Create semi-transparent overlay
var overlay = game.addChild(LK.getAsset('Player4', {
anchorX: 0,
anchorY: 0,
scaleX: 20.48,
scaleY: 27.32
}));
overlay.x = 0;
overlay.y = 0;
overlay.tint = 0x000000;
overlay.alpha = 0.6;
overlay.zIndex = 50;
// Create instructions text
var instructionsText = new Text2('HOW TO PLAY\n\n' + 'SWISH MODE:\n' + '• Tap to shoot basketballs\n' + '• Hit perfect timing for swish shots\n' + '• Score baskets to increase streak\n' + '• Match backboard colors for bonus\n' + '• Unlock new players with money\n\n' + 'RHYTHM MODE:\n' + '• Tap falling circles in the green zones\n' + '• Perfect timing gives bonus points\n' + '• Maintain rhythm for multipliers\n\n' + 'TAP TO CLOSE', {
size: 80,
fill: 0xFFFFFF
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = 1024;
instructionsText.y = 1366;
instructionsText.zIndex = 51;
game.addChild(instructionsText);
// Store references for cleanup
game.instructionsBackground = background;
game.instructionsOverlay = overlay;
game.instructionsText = instructionsText;
}
function hideHowToPlay() {
if (game.instructionsBackground) {
game.instructionsBackground.destroy();
game.instructionsBackground = null;
}
if (game.instructionsOverlay) {
game.instructionsOverlay.destroy();
game.instructionsOverlay = null;
}
if (game.instructionsText) {
game.instructionsText.destroy();
game.instructionsText = null;
}
}
function showStore() {
// Create store background using Shopbackdrop asset
var storeBackground = game.addChild(LK.getAsset('Shopbackdrop', {
anchorX: 0,
anchorY: 0
}));
storeBackground.x = 0;
storeBackground.y = 0;
storeBackground.width = 2048;
storeBackground.height = 2732;
storeBackground.zIndex = 49;
// Create store title text
var storeTitle = new Text2('STORE', {
size: 120,
fill: 0xFFFFFF
});
storeTitle.anchor.set(0.5, 0.5);
storeTitle.x = 1024;
storeTitle.y = 500;
storeTitle.zIndex = 51;
game.addChild(storeTitle);
// Create money display
var storeMoneyText = new Text2('Money: $' + currentMoney.toFixed(2), {
size: 80,
fill: 0x00FF00
});
storeMoneyText.anchor.set(0.5, 0.5);
storeMoneyText.x = 1024;
storeMoneyText.y = 600;
storeMoneyText.zIndex = 51;
game.addChild(storeMoneyText);
// Create pacersball item
var pacersballItem = gameStore.getItem('pacersball');
if (pacersballItem) {
// Create item image
var itemImage = game.addChild(LK.getAsset('Bballpacers', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
}));
itemImage.x = 354;
itemImage.y = 1200;
itemImage.zIndex = 51;
// Create item name text
var itemNameText = new Text2('Team Pack: Pacers', {
size: 60,
fill: 0xFFFFFF
});
itemNameText.anchor.set(0.5, 0.5);
itemNameText.x = 354;
itemNameText.y = 925;
itemNameText.zIndex = 51;
game.addChild(itemNameText);
// Create price text
var priceColor = gameStore.canAfford(pacersballItem) ? 0x00FF00 : 0xFF0000;
var priceText = new Text2('$' + pacersballItem.price.toFixed(2), {
size: 50,
fill: priceColor
});
priceText.anchor.set(0.5, 0.5);
priceText.x = 354;
priceText.y = 1350;
priceText.zIndex = 51;
game.addChild(priceText);
// Create status text
var statusText = new Text2(pacersballItem.unlocked ? 'TAP TO SELECT' : 'TAP TO BUY', {
size: 40,
fill: pacersballItem.unlocked ? 0x00FF00 : 0xFFFFFF
});
statusText.anchor.set(0.5, 0.5);
statusText.x = 354;
statusText.y = 1050;
statusText.zIndex = 51;
game.addChild(statusText);
// Store references for cleanup and purchase handling
game.storeItemImage = itemImage;
game.storeItemNameText = itemNameText;
game.storeItemPriceText = priceText;
game.storeItemStatusText = statusText;
game.storeItem = pacersballItem;
}
// Create thunderball item
var thunderballItem = gameStore.getItem('thunderball');
if (thunderballItem) {
// Create item image
var thunderItemImage = game.addChild(LK.getAsset('Bballthunder', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
}));
thunderItemImage.x = 1694;
thunderItemImage.y = 1200;
thunderItemImage.zIndex = 51;
// Create item name text
var thunderItemNameText = new Text2('Team Pack: Thunder', {
size: 60,
fill: 0xFFFFFF
});
thunderItemNameText.anchor.set(0.5, 0.5);
thunderItemNameText.x = 1694;
thunderItemNameText.y = 925;
thunderItemNameText.zIndex = 51;
game.addChild(thunderItemNameText);
// Create price text
var thunderPriceColor = gameStore.canAfford(thunderballItem) ? 0x00FF00 : 0xFF0000;
var thunderPriceText = new Text2('$' + thunderballItem.price.toFixed(2), {
size: 50,
fill: thunderPriceColor
});
thunderPriceText.anchor.set(0.5, 0.5);
thunderPriceText.x = 1694;
thunderPriceText.y = 1350;
thunderPriceText.zIndex = 51;
game.addChild(thunderPriceText);
// Create status text
var thunderStatusText = new Text2(thunderballItem.unlocked ? 'TAP TO SELECT' : 'TAP TO BUY', {
size: 40,
fill: thunderballItem.unlocked ? 0x00FF00 : 0xFFFFFF
});
thunderStatusText.anchor.set(0.5, 0.5);
thunderStatusText.x = 1694;
thunderStatusText.y = 1050;
thunderStatusText.zIndex = 51;
game.addChild(thunderStatusText);
// Store references for cleanup and purchase handling
game.storeThunderItemImage = thunderItemImage;
game.storeThunderItemNameText = thunderItemNameText;
game.storeThunderItemPriceText = thunderPriceText;
game.storeThunderItemStatusText = thunderStatusText;
game.storeThunderItem = thunderballItem;
}
// Create Warriorsball item (default mode)
var warriorsballImage = game.addChild(LK.getAsset('basketball', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
}));
warriorsballImage.x = 1024;
warriorsballImage.y = 1900;
warriorsballImage.zIndex = 51;
warriorsballImage.tint = 0xFFD700; // Gold tint for Warriors theme
// Create item name text
var warriorsItemNameText = new Text2('Team Pack: Warriors', {
size: 60,
fill: 0xFFFFFF
});
warriorsItemNameText.anchor.set(0.5, 0.5);
warriorsItemNameText.x = 1024;
warriorsItemNameText.y = 1625;
warriorsItemNameText.zIndex = 51;
game.addChild(warriorsItemNameText);
// Create status text
var warriorsStatusText = new Text2('TAP TO SELECT', {
size: 40,
fill: 0x00FF00
});
warriorsStatusText.anchor.set(0.5, 0.5);
warriorsStatusText.x = 1024;
warriorsStatusText.y = 1750;
warriorsStatusText.zIndex = 51;
game.addChild(warriorsStatusText);
// Store references for cleanup and selection handling
game.storeWarriorsItemImage = warriorsballImage;
game.storeWarriorsItemNameText = warriorsItemNameText;
game.storeWarriorsItemStatusText = warriorsStatusText;
// Create 2playvs pack item
var twoPlayerVsItem = gameStore.getItem('2playvs');
if (twoPlayerVsItem) {
// Create item image
var twoPlayerVsItemImage = game.addChild(LK.getAsset('2playvs', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
}));
twoPlayerVsItemImage.x = 324;
twoPlayerVsItemImage.y = 2000;
twoPlayerVsItemImage.zIndex = 51;
twoPlayerVsItemImage.tint = 0x00FF00; // Green tint to match 2player rhythm mode button
// Create item name text
var twoPlayerVsItemNameText = new Text2('2 Player Rhythm Pack', {
size: 60,
fill: 0xFFFFFF
});
twoPlayerVsItemNameText.anchor.set(0.5, 0.5);
twoPlayerVsItemNameText.x = 324;
twoPlayerVsItemNameText.y = 1725;
twoPlayerVsItemNameText.zIndex = 51;
game.addChild(twoPlayerVsItemNameText);
// Create price text
var twoPlayerVsPriceColor = gameStore.canAfford(twoPlayerVsItem) ? 0x00FF00 : 0xFF0000;
var twoPlayerVsPriceText = new Text2('$' + twoPlayerVsItem.price.toFixed(2), {
size: 50,
fill: twoPlayerVsPriceColor
});
twoPlayerVsPriceText.anchor.set(0.5, 0.5);
twoPlayerVsPriceText.x = 324;
twoPlayerVsPriceText.y = 2150;
twoPlayerVsPriceText.zIndex = 51;
game.addChild(twoPlayerVsPriceText);
// Create status text
var twoPlayerVsStatusText = new Text2(twoPlayerVsItem.unlocked ? 'UNLOCKED' : 'TAP TO BUY', {
size: 40,
fill: twoPlayerVsItem.unlocked ? 0x00FF00 : 0xFFFFFF
});
twoPlayerVsStatusText.anchor.set(0.5, 0.5);
twoPlayerVsStatusText.x = 324;
twoPlayerVsStatusText.y = 1850;
twoPlayerVsStatusText.zIndex = 51;
game.addChild(twoPlayerVsStatusText);
// Store references for cleanup and purchase handling
game.store2PlayerVsItemImage = twoPlayerVsItemImage;
game.store2PlayerVsItemNameText = twoPlayerVsItemNameText;
game.store2PlayerVsItemPriceText = twoPlayerVsPriceText;
game.store2PlayerVsItemStatusText = twoPlayerVsStatusText;
game.store2PlayerVsItem = twoPlayerVsItem;
}
// Create swish2playvs pack item
var swishTwoPlayerVsItem = gameStore.getItem('swish2playvs');
if (swishTwoPlayerVsItem) {
// Create item image
var swishTwoPlayerVsItemImage = game.addChild(LK.getAsset('2playvs', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
}));
swishTwoPlayerVsItemImage.x = 1724;
swishTwoPlayerVsItemImage.y = 2000;
swishTwoPlayerVsItemImage.zIndex = 51;
swishTwoPlayerVsItemImage.tint = 0x008080; // Teal and purple tint to match 2player swish mode button
// Create item name text
var swishTwoPlayerVsItemNameText = new Text2('2 Player Swish Pack', {
size: 60,
fill: 0xFFFFFF
});
swishTwoPlayerVsItemNameText.anchor.set(0.5, 0.5);
swishTwoPlayerVsItemNameText.x = 1724;
swishTwoPlayerVsItemNameText.y = 1725;
swishTwoPlayerVsItemNameText.zIndex = 51;
game.addChild(swishTwoPlayerVsItemNameText);
// Create price text
var swishTwoPlayerVsPriceColor = gameStore.canAfford(swishTwoPlayerVsItem) ? 0x00FF00 : 0xFF0000;
var swishTwoPlayerVsPriceText = new Text2('$' + swishTwoPlayerVsItem.price.toFixed(2), {
size: 50,
fill: swishTwoPlayerVsPriceColor
});
swishTwoPlayerVsPriceText.anchor.set(0.5, 0.5);
swishTwoPlayerVsPriceText.x = 1724;
swishTwoPlayerVsPriceText.y = 2150;
swishTwoPlayerVsPriceText.zIndex = 51;
game.addChild(swishTwoPlayerVsPriceText);
// Create status text
var swishTwoPlayerVsStatusText = new Text2(swishTwoPlayerVsItem.unlocked ? 'UNLOCKED' : 'TAP TO BUY', {
size: 40,
fill: swishTwoPlayerVsItem.unlocked ? 0x00FF00 : 0xFFFFFF
});
swishTwoPlayerVsStatusText.anchor.set(0.5, 0.5);
swishTwoPlayerVsStatusText.x = 1724;
swishTwoPlayerVsStatusText.y = 1850;
swishTwoPlayerVsStatusText.zIndex = 51;
game.addChild(swishTwoPlayerVsStatusText);
// Store references for cleanup
game.storeSwish2PlayerVsItemImage = swishTwoPlayerVsItemImage;
game.storeSwish2PlayerVsItemNameText = swishTwoPlayerVsItemNameText;
game.storeSwish2PlayerVsItemPriceText = swishTwoPlayerVsPriceText;
game.storeSwish2PlayerVsItemStatusText = swishTwoPlayerVsStatusText;
game.storeSwish2PlayerVsItem = swishTwoPlayerVsItem;
}
// Create aibattle pack item
var aibattleItem = gameStore.getItem('aibattle');
if (aibattleItem) {
// Create item image//{cH_new1}
var aibattleItemImage = game.addChild(LK.getAsset('Aibattle', {
anchorX: 0.5,
//{cH_new2}
anchorY: 0.5,
//{cH_new3}
scaleX: 0.6,
//{cH_new4}
scaleY: 0.6 //{cH_new5}
})); //{cH_new6}
aibattleItemImage.x = 1024;
aibattleItemImage.y = 1200;
aibattleItemImage.zIndex = 51;
// Create item name text//{cH_new7}
var aibattleItemNameText = new Text2('AI Battle Pack', {
size: 60,
//{cH_new8}
fill: 0xFFFFFF //{cH_new9}
}); //{cH_new10}
aibattleItemNameText.anchor.set(0.5, 0.5);
aibattleItemNameText.x = 1024;
aibattleItemNameText.y = 925;
aibattleItemNameText.zIndex = 51;
game.addChild(aibattleItemNameText);
// Create price text//{cH_new11}
var aibattlePriceColor = gameStore.canAfford(aibattleItem) ? 0x00FF00 : 0xFF0000;
var aibattlePriceText = new Text2('$' + aibattleItem.price.toFixed(2), {
size: 50,
//{cH_new12}
fill: aibattlePriceColor
}); //{cH_new13}
aibattlePriceText.anchor.set(0.5, 0.5);
aibattlePriceText.x = 1024;
aibattlePriceText.y = 1350;
aibattlePriceText.zIndex = 51;
game.addChild(aibattlePriceText);
// Create status text//{cH_new14}
var aibattleStatusText = new Text2(aibattleItem.unlocked ? 'UNLOCKED' : 'TAP TO BUY', {
size: 40,
//{cH_new15}
fill: aibattleItem.unlocked ? 0x00FF00 : 0xFFFFFF
}); //{cH_new16}
aibattleStatusText.anchor.set(0.5, 0.5);
aibattleStatusText.x = 1024;
aibattleStatusText.y = 1050;
aibattleStatusText.zIndex = 51;
game.addChild(aibattleStatusText);
// Store references for cleanup and purchase handling//{cH_new17}
game.storeAibattleItemImage = aibattleItemImage;
game.storeAibattleItemNameText = aibattleItemNameText;
game.storeAibattleItemPriceText = aibattlePriceText;
game.storeAibattleItemStatusText = aibattleStatusText;
game.storeAibattleItem = aibattleItem;
} //{cH_new18}
// Create close button text
var closeButton = new Text2('TAP TO CLOSE', {
size: 60,
fill: 0xFFFFFF
});
closeButton.anchor.set(0.5, 0.5);
closeButton.x = 1024;
closeButton.y = 2400;
closeButton.zIndex = 51;
game.addChild(closeButton);
// Store references for cleanup
game.storeBackground = storeBackground;
game.storeTitle = storeTitle;
game.storeMoneyText = storeMoneyText;
game.storeCloseButton = closeButton;
}
function hideStore() {
if (game.storeBackground) {
game.storeBackground.destroy();
game.storeBackground = null;
}
if (game.storeTitle) {
game.storeTitle.destroy();
game.storeTitle = null;
}
if (game.storeMoneyText) {
game.storeMoneyText.destroy();
game.storeMoneyText = null;
}
if (game.storeCloseButton) {
game.storeCloseButton.destroy();
game.storeCloseButton = null;
}
// Clean up store item elements (itemBg removed as it was never created)
if (game.storeItemImage) {
game.storeItemImage.destroy();
game.storeItemImage = null;
}
if (game.storeItemNameText) {
game.storeItemNameText.destroy();
game.storeItemNameText = null;
}
if (game.storeItemPriceText) {
game.storeItemPriceText.destroy();
game.storeItemPriceText = null;
}
if (game.storeItemStatusText) {
game.storeItemStatusText.destroy();
game.storeItemStatusText = null;
}
game.storeItem = null;
// Clean up thunder item elements
if (game.storeThunderItemImage) {
game.storeThunderItemImage.destroy();
game.storeThunderItemImage = null;
}
if (game.storeThunderItemNameText) {
game.storeThunderItemNameText.destroy();
game.storeThunderItemNameText = null;
}
if (game.storeThunderItemPriceText) {
game.storeThunderItemPriceText.destroy();
game.storeThunderItemPriceText = null;
}
if (game.storeThunderItemStatusText) {
game.storeThunderItemStatusText.destroy();
game.storeThunderItemStatusText = null;
}
game.storeThunderItem = null;
// Clean up warriors item elements
if (game.storeWarriorsItemImage) {
game.storeWarriorsItemImage.destroy();
game.storeWarriorsItemImage = null;
}
if (game.storeWarriorsItemNameText) {
game.storeWarriorsItemNameText.destroy();
game.storeWarriorsItemNameText = null;
}
if (game.storeWarriorsItemStatusText) {
game.storeWarriorsItemStatusText.destroy();
game.storeWarriorsItemStatusText = null;
}
// Clean up 2playvs pack elements
if (game.store2PlayerVsItemImage) {
game.store2PlayerVsItemImage.destroy();
game.store2PlayerVsItemImage = null;
}
if (game.store2PlayerVsItemNameText) {
game.store2PlayerVsItemNameText.destroy();
game.store2PlayerVsItemNameText = null;
}
if (game.store2PlayerVsItemPriceText) {
game.store2PlayerVsItemPriceText.destroy();
game.store2PlayerVsItemPriceText = null;
}
if (game.store2PlayerVsItemStatusText) {
game.store2PlayerVsItemStatusText.destroy();
game.store2PlayerVsItemStatusText = null;
}
game.store2PlayerVsItem = null;
// Clean up swish2playvs pack elements
if (game.storeSwish2PlayerVsItemImage) {
game.storeSwish2PlayerVsItemImage.destroy();
game.storeSwish2PlayerVsItemImage = null;
}
if (game.storeSwish2PlayerVsItemNameText) {
game.storeSwish2PlayerVsItemNameText.destroy();
game.storeSwish2PlayerVsItemNameText = null;
}
if (game.storeSwish2PlayerVsItemPriceText) {
game.storeSwish2PlayerVsItemPriceText.destroy();
game.storeSwish2PlayerVsItemPriceText = null;
}
if (game.storeSwish2PlayerVsItemStatusText) {
game.storeSwish2PlayerVsItemStatusText.destroy();
game.storeSwish2PlayerVsItemStatusText = null;
}
game.storeSwish2PlayerVsItem = null;
// Clean up aibattle pack elements
if (game.storeAibattleItemImage) {
game.storeAibattleItemImage.destroy();
game.storeAibattleItemImage = null;
} //{dm_new1}
if (game.storeAibattleItemNameText) {
game.storeAibattleItemNameText.destroy();
game.storeAibattleItemNameText = null;
} //{dm_new2}
if (game.storeAibattleItemPriceText) {
//{dm_new3}
game.storeAibattleItemPriceText.destroy();
game.storeAibattleItemPriceText = null;
} //{dm_new4}
if (game.storeAibattleItemStatusText) {
//{dm_new5}
game.storeAibattleItemStatusText.destroy();
game.storeAibattleItemStatusText = null;
} //{dm_new6}
game.storeAibattleItem = null;
}
// Title screen is now initialized - gameplay will be initialized when start is pressed;
var gameState = 'title'; // 'title', 'playing', 'modeSelect'
var gameMode = 'swish'; // 'swish', 'rhythm', 'ai_vs', or '2player'
var aiOpponent = null; // AI opponent instance
var aiScoreTxt = null; // AI score display
// 2 Player battle mode variables
var twoPlayerState = 'player1'; // 'player1', 'transition', 'player2', 'results'
var player1Score = 0;
var player2Score = 0;
var twoPlayerTimer = 90 * 60; // 90 seconds at 60 FPS
var twoPlayerTimeLeft = 90;
var currentPlayerTxt = null;
var player1ScoreTxt = null;
var player2ScoreTxt = null;
var transitionOverlay = null;
var transitionText = null;
var transitionTimer = 0;
var countdownActive = false;
var countdownTimer = 0;
var countdownContainer = null;
// 2 Player rhythm mode variables
var twoPlayerRhythmMode = false;
var defaultBasketballMode = 'Warriorsball'; // Default basketball mode
var defaultPlayers = ['player1', 'player2', 'player3']; // Default mode players
var pacersMode = 'pacersball'; // Pacers mode basketball
var pacersPlayers = ['player4', 'player5', 'player6']; // Pacers mode players
var thunderMode = 'Thunderball'; // Thunder mode basketball
var thunderPlayers = ['player7', 'player8', 'player9']; // Thunder mode players
var modeSelectBackground = null;
var swishButton = null;
var rhythmButton = null;
var titleBackground = null;
var titleText = null;
var startButton = null;
var basketballs = [];
var ballReflections = [];
var hoop = null;
var leftHoop = null;
var rightHoop = null;
var ground = null;
var scoreTxt = null;
var streakTxt = null;
var timerTxt = null;
var player1 = null;
var player1down = null;
var player2 = null;
var player2down = null;
var player3 = null;
var player3down = null;
var currentMoney = storage.money || 0;
var moneyTxt = null;
var multiplierTxt = null;
var bestScore = 0;
var bestScoreTxt = null;
var swishBestScore = 0;
var rhythmBestScore = 0;
var currentStreak = 0;
var streakRewardsAwarded = []; // Track which streak rewards have been given
var swipeStartX = 0;
var swipeStartY = 0;
var swipeStartTime = 0;
var isSwipeStarted = false;
var lastShotTime = 0;
var gameTimer = 60 * 60; // Will be set correctly in initializeGameplay
var gameTimeLeft = 60; // Will be set correctly in initializeGameplay
var gameEnded = false;
var musicNotes = ['note1', 'note2', 'note3', 'note4', 'note5'];
var currentNoteIndex = 0;
var shotBar = null;
var shotBar2 = null;
var shotBar3 = null;
var isChargingShot = false;
// Color cycling system for backboard changes
var basketColors = [0xFF0000, 0x00FF00, 0x0000FF, 0xFFFF00, 0xFF00FF, 0x00FFFF, 0xFFA500, 0x800080, 0xFFB6C1, 0x90EE90, 0x87CEEB, 0xDDA0DD];
var currentColorIndex = 0;
// Track backboard colors for multiplier system
var backboardColors = [0xFFFFFF, 0xFFFFFF, 0xFFFFFF]; // [hoop, leftHoop, rightHoop] - start with white
var allSameColorMultiplier = false;
var moneyAwarded = false; // Track if money has been awarded for current color match
var player2Unlocked = true;
var player3Unlocked = true;
// Rhythm mode variables
var beatInterval = 60; // 60 frames = 1 second at 60 FPS
var lastBeatTime = 0;
var beatTolerance = 10; // frames of tolerance for rhythm timing
var rhythmStreak = 0;
var beatIndicator = null;
var rhythmMultiplier = 1;
var rhythmCircles = [];
var rhythmCircleSpawnTimer = 0;
var rhythmCircleSpawnInterval = 29; // Spawn at 124 BPM (29 frames = ~124 beats per minute)
var tapZoneGreenBalls = []; // Array to hold green balls in tap zones
var volumeVisualizerBars = []; // Array to hold volume visualizer bars
var musicStarted = false; // Track when music has started playing
// Global timer variables
var timerNumbers = [];
// Break system variables for swish mode
var isInBreak = false;
var breakCountdown = 0;
var breakCountdownNumbers = [];
var speedIncreaseDelayed = false;
var swishModeTimerReduction = 0; // Track how much to reduce timer each break
// Function to swap player sprites based on current basketball mode
function swapPlayerSprites() {
if (!player1 || !player2 || !player3) return; // Safety check
var player1Asset, player1downAsset, player2Asset, player2downAsset, player3Asset, player3downAsset;
// Determine which assets to use based on current basketball mode
if (currentBasketballMode === pacersMode) {
// Use Pacers players (Player4, Player5, Player6)
player1Asset = 'Player4';
player1downAsset = 'Player4down';
player2Asset = 'Player5';
player2downAsset = 'Player5down';
player3Asset = 'Player6';
player3downAsset = 'Player6down';
} else if (currentBasketballMode === thunderMode) {
// Use Thunder players (Player7, Player8, Player9)
player1Asset = 'Player7';
player1downAsset = 'Player7down';
player2Asset = 'Player8';
player2downAsset = 'Player8down';
player3Asset = 'Player9';
player3downAsset = 'Player9down';
} else {
// Use Warriors players (Player1, Player2, Player3) - default
player1Asset = 'Player1';
player1downAsset = 'Player1down';
player2Asset = 'Player2';
player2downAsset = 'Player2down';
player3Asset = 'Player3';
player3downAsset = 'Player3down';
}
// Store current visibility states
var player1Visible = player1.visible;
var player2Visible = player2.visible;
var player3Visible = player3.visible;
var player1downVisible = player1down.visible;
var player2downVisible = player2down.visible;
var player3downVisible = player3down.visible;
// Store current positions
var player1X = player1.x,
player1Y = player1.y;
var player2X = player2.x,
player2Y = player2.y;
var player3X = player3.x,
player3Y = player3.y;
var player1downX = player1down.x,
player1downY = player1down.y;
var player2downX = player2down.x,
player2downY = player2down.y;
var player3downX = player3down.x,
player3downY = player3down.y;
// Remove existing player sprites
if (player1) {
player1.destroy();
}
if (player1down) {
player1down.destroy();
}
if (player2) {
player2.destroy();
}
if (player2down) {
player2down.destroy();
}
if (player3) {
player3.destroy();
}
if (player3down) {
player3down.destroy();
}
// Create new player sprites with correct assets
player1 = game.addChild(LK.getAsset(player1Asset, {
anchorX: 0.5,
anchorY: 1
}));
player1.x = player1X;
player1.y = player1Y;
player1.zIndex = 1;
player1.visible = player1Visible;
player1down = game.addChild(LK.getAsset(player1downAsset, {
anchorX: 0.5,
anchorY: 1
}));
player1down.x = player1downX;
player1down.y = player1downY;
player1down.zIndex = 1;
player1down.visible = player1downVisible;
player2 = game.addChild(LK.getAsset(player2Asset, {
anchorX: 0.5,
anchorY: 1
}));
player2.x = player2X;
player2.y = player2Y;
player2.zIndex = 1;
player2.visible = player2Visible;
player2down = game.addChild(LK.getAsset(player2downAsset, {
anchorX: 0.5,
anchorY: 1
}));
player2down.x = player2downX;
player2down.y = player2downY;
player2down.zIndex = 1;
player2down.visible = player2downVisible;
player3 = game.addChild(LK.getAsset(player3Asset, {
anchorX: 0.5,
anchorY: 1
}));
player3.x = player3X;
player3.y = player3Y;
player3.zIndex = 1;
player3.visible = player3Visible;
player3down = game.addChild(LK.getAsset(player3downAsset, {
anchorX: 0.5,
anchorY: 1
}));
player3down.x = player3downX;
player3down.y = player3downY;
player3down.zIndex = 1;
player3down.visible = player3downVisible;
}
// Function to get basketball asset based on current basketball mode
function getBasketballAsset() {
if (currentBasketballMode === pacersMode) {
return 'Bballpacers';
} else if (currentBasketballMode === thunderMode) {
return 'Bballthunder';
} else {
return 'basketball'; // Default Warriors mode
}
}
// Function to start break countdown in swish mode
function startBreakCountdown() {
if (gameMode !== 'swish') return;
// Check if this is the first break and player hasn't scored 60 points
if (swishModeTimerReduction === 0 && LK.getScore() < 60) {
// First break and score is below 60 - game over
gameEnded = true;
updateTimerDisplay(0);
cleanupUIElements();
LK.showGameOver();
return;
}
// Check if this is the second break and player hasn't scored 120 points
if (swishModeTimerReduction === 5 && LK.getScore() < 120) {
// Second break and score is below 120 - game over
gameEnded = true;
updateTimerDisplay(0);
cleanupUIElements();
LK.showGameOver();
return;
}
// Check if this is the third break and player hasn't scored 180 points
if (swishModeTimerReduction === 10 && LK.getScore() < 180) {
// Third break and score is below 180 - game over
gameEnded = true;
updateTimerDisplay(0);
cleanupUIElements();
LK.showGameOver();
return;
}
// Check if this is the fourth break and player hasn't scored 240 points
if (swishModeTimerReduction === 15 && LK.getScore() < 240) {
// Fourth break and score is below 240 - game over
gameEnded = true;
updateTimerDisplay(0);
cleanupUIElements();
LK.showGameOver();
return;
}
// Check if this is the fifth break and player hasn't scored 300 points
if (swishModeTimerReduction === 20 && LK.getScore() < 300) {
// Fifth break and score is below 300 - game over
gameEnded = true;
updateTimerDisplay(0);
cleanupUIElements();
LK.showGameOver();
return;
}
// Check if this is the sixth break and player hasn't scored 360 points
if (swishModeTimerReduction === 25 && LK.getScore() < 360) {
// Sixth break and score is below 360 - game over
gameEnded = true;
updateTimerDisplay(0);
cleanupUIElements();
LK.showGameOver();
return;
}
// Check if this is the seventh break and player hasn't scored 420 points
if (swishModeTimerReduction === 30 && LK.getScore() < 420) {
// Seventh break and score is below 420 - game over
gameEnded = true;
updateTimerDisplay(0);
cleanupUIElements();
LK.showGameOver();
return;
}
isInBreak = true;
breakCountdown = 5;
speedIncreaseDelayed = false;
// Increase timer reduction for next cycle (5 seconds each break)
swishModeTimerReduction += 5;
// Play speedup sound when 5-second countdown starts
LK.getSound('Speedup').play();
// Create container for break countdown numbers
var breakContainer = new Container();
breakContainer.x = 1024; // Center of screen
breakContainer.y = 1366; // Middle of screen vertically
breakContainer.zIndex = 100; // High z-index to appear on top
game.addChild(breakContainer);
// Create enlarged countdown numbers (5, 4, 3, 2, 1)
updateBreakCountdown();
// Store container reference for cleanup
game.breakContainer = breakContainer;
}
// Function to update break countdown display
function updateBreakCountdown() {
if (!isInBreak || !game.breakContainer) return;
// Clear existing countdown numbers
for (var i = 0; i < breakCountdownNumbers.length; i++) {
if (breakCountdownNumbers[i]) {
game.breakContainer.removeChild(breakCountdownNumbers[i]);
breakCountdownNumbers[i].destroy();
}
}
breakCountdownNumbers = [];
if (breakCountdown > 0) {
// Create enlarged number asset for current countdown
var numberAsset = LK.getAsset(breakCountdown.toString(), {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.0,
// Enlarged scale
scaleY: 3.0
});
numberAsset.x = 0; // Relative to container
numberAsset.y = 0;
numberAsset.alpha = 0;
game.breakContainer.addChild(numberAsset);
breakCountdownNumbers.push(numberAsset);
// Animate number appearance with scale and fade
tween(numberAsset, {
alpha: 1.0,
scaleX: 4.0,
scaleY: 4.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Animate number disappearance
tween(numberAsset, {
alpha: 0,
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 700,
easing: tween.easeIn
});
}
});
}
}
// Function to end break countdown
function endBreakCountdown() {
isInBreak = false;
breakCountdown = 0;
speedIncreaseDelayed = false;
// Clean up break countdown display
if (game.breakContainer) {
for (var i = 0; i < breakCountdownNumbers.length; i++) {
if (breakCountdownNumbers[i]) {
breakCountdownNumbers[i].destroy();
}
}
breakCountdownNumbers = [];
game.breakContainer.destroy();
game.breakContainer = null;
}
}
// Function to swap basketball assets for existing basketballs
function swapBasketballAssets() {
var newAssetId = getBasketballAsset();
// Update existing basketballs
for (var i = 0; i < basketballs.length; i++) {
var ball = basketballs[i];
if (ball && ball.children && ball.children.length > 0) {
var ballGraphics = ball.children[0]; // First child should be the basketball graphics
if (ballGraphics) {
// Store current properties
var currentX = ballGraphics.x;
var currentY = ballGraphics.y;
var currentAnchorX = ballGraphics.anchor.x;
var currentAnchorY = ballGraphics.anchor.y;
var currentZIndex = ballGraphics.zIndex;
var currentTint = ballGraphics.tint;
var currentAlpha = ballGraphics.alpha;
var currentScaleX = ballGraphics.scaleX;
var currentScaleY = ballGraphics.scaleY;
var currentRotation = ballGraphics.rotation;
// Remove existing graphics
ball.removeChild(ballGraphics);
ballGraphics.destroy();
// Create new graphics with correct asset
var newGraphics = ball.attachAsset(newAssetId, {
anchorX: currentAnchorX,
anchorY: currentAnchorY
});
// Restore properties
newGraphics.x = currentX;
newGraphics.y = currentY;
newGraphics.zIndex = currentZIndex;
newGraphics.tint = currentTint;
newGraphics.alpha = currentAlpha;
newGraphics.scaleX = currentScaleX;
newGraphics.scaleY = currentScaleY;
newGraphics.rotation = currentRotation;
}
}
}
// Update existing ball reflections
for (var i = 0; i < ballReflections.length; i++) {
var reflection = ballReflections[i];
if (reflection && reflection.children && reflection.children.length > 0) {
var reflectionGraphics = reflection.children[0]; // First child should be the reflection graphics
if (reflectionGraphics) {
// Store current properties
var currentX = reflectionGraphics.x;
var currentY = reflectionGraphics.y;
var currentAnchorX = reflectionGraphics.anchor.x;
var currentAnchorY = reflectionGraphics.anchor.y;
var currentZIndex = reflectionGraphics.zIndex;
var currentTint = reflectionGraphics.tint;
var currentAlpha = reflectionGraphics.alpha;
var currentScaleX = reflectionGraphics.scaleX;
var currentScaleY = reflectionGraphics.scaleY;
var currentRotation = reflectionGraphics.rotation;
// Remove existing graphics
reflection.removeChild(reflectionGraphics);
reflectionGraphics.destroy();
// Create new graphics with correct asset
var newReflectionGraphics = reflection.attachAsset(newAssetId, {
anchorX: currentAnchorX,
anchorY: currentAnchorY
});
// Restore properties
newReflectionGraphics.x = currentX;
newReflectionGraphics.y = currentY;
newReflectionGraphics.zIndex = currentZIndex;
newReflectionGraphics.tint = currentTint;
newReflectionGraphics.alpha = currentAlpha;
newReflectionGraphics.scaleX = currentScaleX;
newReflectionGraphics.scaleY = currentScaleY;
newReflectionGraphics.rotation = currentRotation;
}
}
}
}
// Global function to update timer display with number assets
function updateTimerDisplay(timeLeft) {
if (timerNumbers.length === 0) return; // Safety check
// Display seconds only (2 digits)
var digits = [Math.floor(timeLeft / 10),
// Tens digit
timeLeft % 10 // Units digit
];
for (var i = 0; i < timerNumbers.length && i < digits.length; i++) {
var digitValue = digits[i].toString();
var newAsset = LK.getAsset(digitValue, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
// Get the stored container reference
var container = timerNumbers[i].parentContainer;
if (container) {
// Replace the existing number with new asset
container.removeChild(timerNumbers[i]);
newAsset.x = [-30, 30][i];
newAsset.y = 90;
newAsset.parentContainer = container; // Store container reference
timerNumbers[i] = newAsset;
container.addChild(newAsset);
}
}
}
// Initialize title screen
initializeTitleScreen();
function createBasketball(startX, startY, velocityX, velocityY) {
var ball = new Basketball();
ball.x = startX;
ball.y = startY;
ball.velocityX = velocityX;
ball.velocityY = velocityY;
ball.isPerfectShot = false;
basketballs.push(ball);
game.addChild(ball);
// Create reflection for this ball
var reflection = new BallReflection();
reflection.parentBall = ball;
ballReflections.push(reflection);
game.addChild(reflection);
return ball;
}
function checkBasketScore(ball) {
// Scoring is now handled in Basketball class update method
// This function is kept for compatibility but does nothing
return;
}
// Function to clean up all UI elements from LK.gui
function cleanupUIElements() {
// Clean up all children from LK.gui containers
if (LK.gui.top) {
while (LK.gui.top.children.length > 0) {
var child = LK.gui.top.children[0];
LK.gui.top.removeChild(child);
child.destroy();
}
}
if (LK.gui.topLeft) {
while (LK.gui.topLeft.children.length > 0) {
var child = LK.gui.topLeft.children[0];
LK.gui.topLeft.removeChild(child);
child.destroy();
}
}
if (LK.gui.topRight) {
while (LK.gui.topRight.children.length > 0) {
var child = LK.gui.topRight.children[0];
LK.gui.topRight.removeChild(child);
child.destroy();
}
}
// Reset UI element references to null
scoreTxt = null;
streakTxt = null;
moneyTxt = null;
multiplierTxt = null;
bestScoreTxt = null;
timerNumbers = [];
currentPlayerTxt = null;
player1ScoreTxt = null;
player2ScoreTxt = null;
aiScoreTxt = null;
}
function initializeTitleScreen() {
// Stop all music when returning to title
LK.stopMusic();
// Reset music started flag
musicStarted = false;
// Clean up all UI elements from LK.gui
cleanupUIElements();
// Clean up tap zone green balls
for (var i = 0; i < tapZoneGreenBalls.length; i++) {
if (tapZoneGreenBalls[i]) {
tapZoneGreenBalls[i].destroy();
}
}
tapZoneGreenBalls = [];
// Clean up volume visualizer bars
for (var i = 0; i < volumeVisualizerBars.length; i++) {
if (volumeVisualizerBars[i]) {
volumeVisualizerBars[i].destroy();
}
}
volumeVisualizerBars = [];
// Create title background
titleBackground = game.addChild(LK.getAsset('TitleBackground', {
anchorX: 0,
anchorY: 0
}));
titleBackground.x = 0;
titleBackground.y = 0;
titleBackground.width = 2048;
titleBackground.height = 2732;
titleBackground.zIndex = -5;
// Create game title using asset
titleText = game.addChild(LK.getAsset('Title', {
anchorX: 0.5,
anchorY: 0.5
}));
titleText.x = 1024;
titleText.y = 1000;
titleText.zIndex = 10;
// Create start button using tap to start asset
startButton = game.addChild(LK.getAsset('Taptostart', {
anchorX: 0.5,
anchorY: 0.5
}));
startButton.x = 1294;
startButton.y = 1150;
startButton.zIndex = 10;
// Create how to play button using asset
var howToPlayButton = game.addChild(LK.getAsset('Howtoplay', {
anchorX: 0.5,
anchorY: 0.5
}));
howToPlayButton.x = 250;
howToPlayButton.y = 2550;
howToPlayButton.zIndex = 10;
// Store reference for cleanup
game.howToPlayButton = howToPlayButton;
// Create shop button using asset
var shopButton = game.addChild(LK.getAsset('Shop', {
anchorX: 0.5,
anchorY: 0.5
}));
shopButton.x = 1848;
shopButton.y = 2550;
shopButton.zIndex = 10;
// Store reference for cleanup
game.shopButton = shopButton;
// Play make a wish sound when title screen loads
LK.getSound('Makeaswish').play();
// Animate start button pulsate continuously
function pulsateStartButton() {
if (!startButton || gameState !== 'title') return; // Safety check
tween(startButton, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (!startButton || gameState !== 'title') return; // Safety check
// Create continuous pulsating loop
tween(startButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (!startButton || gameState !== 'title') return; // Safety check
// Restart the pulsate cycle
pulsateStartButton();
}
});
}
});
}
pulsateStartButton();
}
function initializeModeSelection() {
// Hide title screen elements
if (titleBackground) {
titleBackground.destroy();
titleBackground = null;
}
if (titleText) {
titleText.destroy();
titleText = null;
}
if (startButton) {
tween.stop(startButton);
startButton.destroy();
startButton = null;
}
if (game.howToPlayButton) {
game.howToPlayButton.destroy();
game.howToPlayButton = null;
}
if (game.shopButton) {
game.shopButton.destroy();
game.shopButton = null;
}
if (game.shopButton) {
game.shopButton.destroy();
game.shopButton = null;
}
// Hide instructions if showing
hideHowToPlay();
// Create mode selection background
modeSelectBackground = game.addChild(LK.getAsset('TitleBackground', {
anchorX: 0,
anchorY: 0
}));
modeSelectBackground.x = 0;
modeSelectBackground.y = 0;
modeSelectBackground.width = 2048;
modeSelectBackground.height = 2732;
modeSelectBackground.zIndex = -5;
// Create mode selection title
var modeTitle = game.addChild(LK.getAsset('Selectmode', {
anchorX: 0.5,
anchorY: 0.5
}));
modeTitle.x = 1024;
modeTitle.y = 700;
modeTitle.zIndex = 10;
// Create Swish mode button
swishButton = game.addChild(LK.getAsset('Swish', {
anchorX: 0.5,
anchorY: 0.5
}));
swishButton.x = 1024;
swishButton.y = 1850;
swishButton.zIndex = 10;
// Create Rhythm mode button
rhythmButton = game.addChild(LK.getAsset('Rhythm', {
anchorX: 0.5,
anchorY: 0.5
}));
rhythmButton.x = 1024;
rhythmButton.y = 1100;
rhythmButton.zIndex = 10;
// Create 2 Player battle mode button using 2playvs asset
var twoPlayerButton = game.addChild(LK.getAsset('2playvs', {
anchorX: 0.5,
anchorY: 0.5
}));
twoPlayerButton.x = 1024;
twoPlayerButton.y = 2100;
twoPlayerButton.zIndex = 10;
// Create AI vs mode button using Aibattle asset
var aiVsButton = game.addChild(LK.getAsset('Aibattle', {
anchorX: 0.5,
anchorY: 0.5
}));
aiVsButton.x = 1024;
aiVsButton.y = 2450;
aiVsButton.zIndex = 10;
// Remove text overlay since Aibattle asset contains the text
var aiVsText = null;
// Remove text overlay since 2playvs asset contains the text
var twoPlayerText = null; // No text overlay needed
game.aiVsButton = aiVsButton;
game.aiVsText = aiVsText;
game.twoPlayerButton = twoPlayerButton;
game.twoPlayerText = twoPlayerText;
// Change game state to mode selection
var twoPlayerRhythmButton = game.addChild(LK.getAsset('2playvs', {
anchorX: 0.5,
anchorY: 0.5
}));
twoPlayerRhythmButton.x = 1024;
twoPlayerRhythmButton.y = 1400;
twoPlayerRhythmButton.zIndex = 10;
twoPlayerRhythmButton.tint = 0xFFFF00; // Start with yellow
twoPlayerRhythmButton.alpha = 1.0; // Remove translucent effect
// Animate between yellow and blue colors
function animateTwoPlayerRhythmButton() {
if (gameState !== 'modeSelect') return;
tween(twoPlayerRhythmButton, {
tint: 0x0000FF // Blue color
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (gameState !== 'modeSelect') return;
tween(twoPlayerRhythmButton, {
tint: 0xFFFF00 // Yellow color
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: animateTwoPlayerRhythmButton
});
}
});
}
animateTwoPlayerRhythmButton();
game.twoPlayerRhythmButton = twoPlayerRhythmButton;
game.twoPlayerRhythmText = null;
// Create 2 Player Rhythm vs mode button
gameState = 'modeSelect';
// Animate buttons
function animateModeButtons() {
if (gameState !== 'modeSelect') return;
// Swish button animation removed - no longer pulsating
// Add pulsating animation to rhythm button
tween(rhythmButton, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (gameState !== 'modeSelect') return;
tween(rhythmButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (gameState !== 'modeSelect') return;
// Continue the rhythm button pulsate cycle
tween(rhythmButton, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: arguments.callee.caller
});
}
});
}
});
}
animateModeButtons();
}
function initializeGameplay() {
// Hide title screen elements
if (titleBackground) {
titleBackground.destroy();
titleBackground = null;
}
if (titleText) {
titleText.destroy();
titleText = null;
}
if (startButton) {
// Stop any active tweens on the start button before destroying
tween.stop(startButton);
startButton.destroy();
startButton = null;
}
// Hide mode selection elements
if (modeSelectBackground) {
modeSelectBackground.destroy();
modeSelectBackground = null;
}
if (swishButton) {
tween.stop(swishButton);
swishButton.destroy();
swishButton = null;
}
if (rhythmButton) {
rhythmButton.destroy();
rhythmButton = null;
}
// Clean up AI vs button
if (game.aiVsButton) {
game.aiVsButton.destroy();
game.aiVsButton = null;
}
if (game.aiVsText) {
game.aiVsText.destroy();
game.aiVsText = null;
}
// Clean up 2 Player button
if (game.twoPlayerButton) {
game.twoPlayerButton.destroy();
game.twoPlayerButton = null;
}
if (game.twoPlayerText) {
game.twoPlayerText.destroy();
game.twoPlayerText = null;
}
// Clean up 2 Player Rhythm button
if (game.twoPlayerRhythmButton) {
game.twoPlayerRhythmButton.destroy();
game.twoPlayerRhythmButton = null;
}
if (game.twoPlayerRhythmText) {
game.twoPlayerRhythmText.destroy();
game.twoPlayerRhythmText = null;
}
// Initialize all game elements (moved from main game code)
// Create multiplier indicator text
multiplierTxt = new Text2('', {
size: 50,
fill: 0xFFD700
});
multiplierTxt.anchor.set(0.5, 0);
multiplierTxt.y = 180;
LK.gui.top.addChild(multiplierTxt);
// Enable z-index sorting for proper rendering order
game.sortableChildren = true;
// Add background with high definition scaling
var background = game.addChild(LK.getAsset('Background', {
anchorX: 0,
anchorY: 0
}));
background.x = 0;
background.y = 0;
background.width = 2048;
background.height = 2732;
background.zIndex = -10;
// Create hoops
hoop = game.addChild(new Hoop());
hoop.x = 1024;
hoop.y = 1300;
leftHoop = game.addChild(new Hoop());
leftHoop.x = 1024 - 375 - 350;
leftHoop.y = 1300;
rightHoop = game.addChild(new Hoop());
rightHoop.x = 1024 + 375 + 350;
rightHoop.y = 1300;
// Create UI displays
scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
streakTxt = new Text2('Streak: 0', {
size: 60,
fill: 0xFFD700
});
streakTxt.anchor.set(0.5, 0);
streakTxt.y = 100;
LK.gui.top.addChild(streakTxt);
// Create timer using number assets instead of text
timerNumbers = []; // Use global variable
var timerContainer = new Container();
timerContainer.x = 0;
timerContainer.y = 160;
LK.gui.top.addChild(timerContainer);
// Create shotclock background for timer numbers
var timerBg = LK.getAsset('Shotclock', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
timerBg.x = 0;
timerBg.y = 140;
timerContainer.addChild(timerBg);
// Create 2 number positions for seconds only
var numberPositions = [-30, 30]; // Positions for tens and units
// Initialize number assets
for (var i = 0; i < 2; i++) {
// 2 number positions for seconds
var numberAsset = LK.getAsset('0', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5
});
numberAsset.x = numberPositions[i];
numberAsset.y = 90;
numberAsset.parentContainer = timerContainer; // Store container reference
timerNumbers.push(numberAsset);
timerContainer.addChild(numberAsset);
}
// Initialize timer display with correct values for each mode
if (gameMode === 'rhythm') {
gameTimer = 15 * 60; // 15 seconds at 60 FPS
gameTimeLeft = 15;
updateTimerDisplay(15);
} else {
gameTimer = 60 * 60; // 60 seconds at 60 FPS
gameTimeLeft = 60;
updateTimerDisplay(60);
}
// Separate best scores for each mode
swishBestScore = storage.swishBestScore || 0;
rhythmBestScore = storage.rhythmBestScore || 0;
bestScore = gameMode === 'rhythm' ? rhythmBestScore : swishBestScore;
bestScoreTxt = new Text2('Best: ' + bestScore, {
size: 60,
fill: 0xFFD700
});
bestScoreTxt.anchor.set(1, 0);
bestScoreTxt.x = -100;
LK.gui.topRight.addChild(bestScoreTxt);
// Use already loaded currentMoney value
moneyTxt = new Text2('$' + currentMoney.toFixed(2), {
size: 50,
fill: 0x00FF00
});
moneyTxt.anchor.set(0, 0);
moneyTxt.x = 120;
moneyTxt.y = 10;
LK.gui.topLeft.addChild(moneyTxt);
// Add default basketball mode display
var basketballModeText = new Text2(currentBasketballMode, {
size: 40,
fill: 0xFFD700
});
basketballModeText.anchor.set(0, 0);
basketballModeText.x = 120;
basketballModeText.y = 70;
LK.gui.topLeft.addChild(basketballModeText);
// Create shot bars only if not in 2 player rhythm mode
if (!(gameMode === '2player' && twoPlayerRhythmMode)) {
shotBar = game.addChild(new ShotBar());
shotBar.x = 1024;
shotBar.y = 1600;
shotBar2 = game.addChild(new ShotBar());
shotBar2.x = 300;
shotBar2.y = 1600;
shotBar3 = game.addChild(new ShotBar());
shotBar3.x = rightHoop.x;
shotBar3.y = 1600;
}
// Add players - always use Player1/2/3 assets (default mode players)
var player1Asset = 'Player1'; // Default player1
var player1downAsset = 'Player1down';
var player2Asset = 'Player2'; // Default player2
var player2downAsset = 'Player2down';
var player3Asset = 'Player3'; // Default player3
var player3downAsset = 'Player3down';
// Set default basketball mode to Warriorsball
var currentBasketballMode = defaultBasketballMode;
player1 = game.addChild(LK.getAsset(player1Asset, {
anchorX: 0.5,
anchorY: 1
}));
player1.x = 1024;
player1.y = 2732;
player1.zIndex = 1;
player1.visible = false;
player1down = game.addChild(LK.getAsset(player1downAsset, {
anchorX: 0.5,
anchorY: 1
}));
player1down.x = 1024;
player1down.y = 2732;
player1down.zIndex = 1;
player1down.visible = true;
player2 = game.addChild(LK.getAsset(player2Asset, {
anchorX: 0.5,
anchorY: 1
}));
player2.x = 300;
player2.y = 2732;
player2.zIndex = 1;
player2.visible = false;
player2down = game.addChild(LK.getAsset(player2downAsset, {
anchorX: 0.5,
anchorY: 1
}));
player2down.x = 300;
player2down.y = 2732;
player2down.zIndex = 1;
player2down.visible = true;
player3 = game.addChild(LK.getAsset(player3Asset, {
anchorX: 0.5,
anchorY: 1
}));
player3.x = 1748;
player3.y = 2732;
player3.zIndex = 1;
player3.visible = false;
player3down = game.addChild(LK.getAsset(player3downAsset, {
anchorX: 0.5,
anchorY: 1
}));
player3down.x = 1748;
player3down.y = 2732;
player3down.zIndex = 1;
player3down.visible = true;
// Apply the selected basketball mode by swapping player sprites
swapPlayerSprites();
// Apply the selected basketball mode by swapping basketball assets
swapBasketballAssets();
// Lock overlays removed - players are now always unlocked
// Default mode players (player1, player2, player3) are always available
// Start shot bars only if not in 2 player rhythm mode
if (!(gameMode === '2player' && twoPlayerRhythmMode)) {
shotBar.startMoving();
shotBar2.startMoving();
shotBar3.startMoving();
}
// Initialize AI vs mode elements if in AI vs mode
if (gameMode === 'ai_vs') {
// Create AI opponent
aiOpponent = new AIOpponent();
game.addChild(aiOpponent);
// Create AI score display
aiScoreTxt = new Text2('AI: 0', {
size: 80,
fill: 0xFF4444 // Red color for AI
});
aiScoreTxt.anchor.set(0.5, 0);
aiScoreTxt.x = -500; // Position to the left of player score
aiScoreTxt.y = 100; // Move down 100 pixels
LK.gui.top.addChild(aiScoreTxt);
// Set timer for AI vs mode to 90 seconds
gameTimer = 90 * 60; // 90 seconds at 60 FPS
gameTimeLeft = 90;
updateTimerDisplay(90);
// Initialize speed multiplier tracking for shot bars
if (shotBar) shotBar.currentSpeedMultiplier = 1;
if (shotBar2) shotBar2.currentSpeedMultiplier = 1;
if (shotBar3) shotBar3.currentSpeedMultiplier = 1;
// Create AI vs mode indicator
var modeIndicator = new Text2('AI BATTLE MODE', {
size: 50,
fill: 0xFF4444
});
modeIndicator.anchor.set(1, 0);
modeIndicator.x = -100;
modeIndicator.y = 120;
LK.gui.topRight.addChild(modeIndicator);
game.aiModeIndicator = modeIndicator;
}
// Initialize 2 Player battle mode elements if in 2 player mode
if (gameMode === '2player') {
// Initialize 2 player state
twoPlayerState = 'player1';
player1Score = 0;
player2Score = 0;
// Check if this is 2 player rhythm mode
if (twoPlayerRhythmMode) {
// Set timer for 90 seconds in rhythm mode
twoPlayerTimer = 90 * 60; // 90 seconds at 60 FPS
twoPlayerTimeLeft = 90;
gameTimer = twoPlayerTimer;
gameTimeLeft = twoPlayerTimeLeft;
updateTimerDisplay(90);
} else {
// Set timer for 90 seconds in swish mode
twoPlayerTimer = 90 * 60; // 90 seconds at 60 FPS
twoPlayerTimeLeft = 90;
gameTimer = twoPlayerTimer;
gameTimeLeft = twoPlayerTimeLeft;
updateTimerDisplay(90);
}
// Create current player indicator
var modeText = twoPlayerRhythmMode ? 'RHYTHM' : 'SWISH';
currentPlayerTxt = new Text2('PLAYER 1 - ' + modeText + ' MODE!', {
size: 60,
fill: 0x44FF44
});
currentPlayerTxt.anchor.set(0.5, 0);
currentPlayerTxt.x = 0;
currentPlayerTxt.y = 400;
LK.gui.top.addChild(currentPlayerTxt);
// Create player score displays
player1ScoreTxt = new Text2('P1: 0', {
size: 70,
fill: 0x44FF44
});
player1ScoreTxt.anchor.set(0, 0);
player1ScoreTxt.x = -600;
player1ScoreTxt.y = 100;
LK.gui.top.addChild(player1ScoreTxt);
player2ScoreTxt = new Text2('P2: 0', {
size: 70,
fill: 0xFFFFFF
});
player2ScoreTxt.anchor.set(1, 0);
player2ScoreTxt.x = 600;
player2ScoreTxt.y = 100;
LK.gui.top.addChild(player2ScoreTxt);
// Start countdown for player 1
createCountdownOverlay('PLAYER 1 GET READY!', 5);
gameEnded = true; // Pause game during countdown
}
// Initialize rhythm mode elements if in rhythm mode or 2 player rhythm mode
if (gameMode === 'rhythm' || gameMode === '2player' && twoPlayerRhythmMode) {
// Timer already set above, just initialize rhythm-specific elements
// Create beat indicator
beatIndicator = new Text2('♪', {
size: 200,
fill: 0xFFD700
});
beatIndicator.anchor.set(0.5, 0.5);
beatIndicator.x = 1024;
beatIndicator.y = 400;
beatIndicator.zIndex = 20;
game.addChild(beatIndicator);
// Create three green balls for tap zones
tapZoneGreenBalls = [];
var tapZonePositions = [300, 1024, 1748]; // Left, center, right positions
for (var i = 0; i < tapZonePositions.length; i++) {
var greenBall = game.addChild(LK.getAsset('greenBall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
}));
greenBall.x = tapZonePositions[i];
greenBall.y = 1600; // Same Y as shot bars
greenBall.tint = 0x00FF00; // Green tint
greenBall.alpha = 0.8;
greenBall.zIndex = 12;
tapZoneGreenBalls.push(greenBall);
}
// Create volume visualizer bars
volumeVisualizerBars = [];
var barCount = 8; // Number of visualizer bars
var barSpacing = 200;
var startX = 1024 - (barCount - 1) * barSpacing * 0.5; // Center the bars
for (var i = 0; i < barCount; i++) {
var visualizerBar = game.addChild(LK.getAsset('Visualisers', {
anchorX: 0.5,
anchorY: 1,
scaleX: 0.3,
scaleY: 0.1
}));
visualizerBar.x = startX + i * barSpacing;
visualizerBar.y = 400; // Position above beat indicator, moved down 100
visualizerBar.tint = 0x00FFFF; // Cyan color
visualizerBar.alpha = 0.7;
visualizerBar.zIndex = 18;
visualizerBar.baseHeight = 0.1;
visualizerBar.targetHeight = 0.1;
volumeVisualizerBars.push(visualizerBar);
}
// Start beat timing
lastBeatTime = LK.ticks;
}
// Create volume visualizer bars for swish mode (same as rhythm mode)
if (gameMode === 'swish') {
//{eF_new1}
volumeVisualizerBars = []; //{eF_new2}
var barCount = 8; // Number of visualizer bars
var barSpacing = 200;
var startX = 1024 - (barCount - 1) * barSpacing * 0.5; // Center the bars
for (var i = 0; i < barCount; i++) {
var visualizerBar = game.addChild(LK.getAsset('Visualisers', {
anchorX: 0.5,
//{eF_new3}
anchorY: 1,
scaleX: 0.3,
scaleY: 0.1 //{eF_new4}
})); //{eF_new5}
visualizerBar.x = startX + i * barSpacing;
visualizerBar.y = 400; // Position above beat indicator, moved down 100
visualizerBar.tint = 0x00FFFF; // Cyan color
visualizerBar.alpha = 0.7;
visualizerBar.zIndex = 18;
visualizerBar.baseHeight = 0.1;
visualizerBar.targetHeight = 0.1;
volumeVisualizerBars.push(visualizerBar);
} //{eF_new6}
} //{eF_new7}
// Change game state to playing
gameState = 'playing';
}
function spawnRhythmCircle() {
if (gameMode !== 'rhythm' && !(gameMode === '2player' && twoPlayerRhythmMode)) return;
// Randomly choose which shot bar to align with (all players available)
var availableShotBars = [];
if (shotBar) availableShotBars.push(shotBar);
if (shotBar2) {
availableShotBars.push(shotBar2);
}
if (shotBar3) {
availableShotBars.push(shotBar3);
}
// If no shot bars exist (2 player rhythm mode), use predefined positions
if (availableShotBars.length === 0) {
var positions = [300, 1024, 1748]; // Left, center, right positions
var randomPosition = positions[Math.floor(Math.random() * positions.length)];
var circle = new RhythmCircle();
circle.x = randomPosition;
circle.y = 200; // Start from top of screen
circle.targetShotBar = null; // No shot bar in 2 player rhythm mode
rhythmCircles.push(circle);
game.addChild(circle);
return;
}
var targetBar = availableShotBars[Math.floor(Math.random() * availableShotBars.length)];
var circle = new RhythmCircle();
circle.x = targetBar.x;
circle.y = 200; // Start from top of screen
circle.targetShotBar = targetBar;
rhythmCircles.push(circle);
game.addChild(circle);
}
function checkRhythmCircleTap(x, y) {
if (gameMode !== 'rhythm' && !(gameMode === '2player' && twoPlayerRhythmMode)) return false;
var tappedCircle = null;
var tappedInGreenZone = false;
for (var i = rhythmCircles.length - 1; i >= 0; i--) {
var circle = rhythmCircles[i];
if (!circle.isActive || circle.hasBeenTapped) continue; // Skip if already been tapped
// Check if tap is within circle bounds
var distance = Math.sqrt((x - circle.x) * (x - circle.x) + (y - circle.y) * (y - circle.y));
if (distance <= 120) {
// Increased circle tap radius for better sensitivity
tappedCircle = circle;
// Check if circle is currently in the horizontal tap zone area
var tolerance = 120; // Further increased tolerance for horizontal tap zone for better responsiveness
if (circle.targetShotBar) {
var shotBarY = circle.targetShotBar.y;
tappedInGreenZone = Math.abs(circle.y - shotBarY) <= tolerance;
} else if (gameMode === '2player' && twoPlayerRhythmMode) {
// In 2 player rhythm mode, check if circle is in tap zone area (green ball position)
var tapZoneY = 1600; // Same Y as green balls
tappedInGreenZone = Math.abs(circle.y - tapZoneY) <= tolerance;
}
break;
}
}
return {
tapped: tappedCircle !== null,
circle: tappedCircle,
inGreenZone: tappedInGreenZone
};
}
function checkSimultaneousTap(x, y) {
if (gameMode !== 'rhythm' && !(gameMode === '2player' && twoPlayerRhythmMode)) return false;
// Check for rhythm circle tap
var rhythmResult = checkRhythmCircleTap(x, y);
if (!rhythmResult.tapped) return false;
// In rhythm mode, if player taps rhythm circle in tap zone, they score a perfect swish
if (rhythmResult.tapped && rhythmResult.inGreenZone) {
// Mark circle as tapped to prevent reuse
rhythmResult.circle.hasBeenTapped = true;
// Perfect swish in rhythm mode!
rhythmStreak += 1; // Increase rhythm streak
rhythmMultiplier = Math.min(3, 1 + Math.floor(rhythmStreak / 5) * 0.5);
// Trigger volume visualizer pulse effect
for (var v = 0; v < volumeVisualizerBars.length; v++) {
var bar = volumeVisualizerBars[v];
var randomHeight = 0.3 + Math.random() * 1.2; // Random height between 0.3 and 1.5
bar.targetHeight = randomHeight;
// Cycle through neon colors
var neonColors = [0xFF0080, 0x00FF80, 0x8000FF, 0xFF8000, 0x0080FF, 0x80FF00, 0xFF0040, 0x40FF00];
var randomColor = neonColors[Math.floor(Math.random() * neonColors.length)];
// Animate bar to target height and change color
tween(bar, {
scaleY: randomHeight,
tint: randomColor
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function () {
// Animate back to base height
tween(this, {
scaleY: 0.1
}, {
duration: 500,
easing: tween.easeIn
});
}.bind(bar)
});
}
// Remove screen flash to prevent excessive flashing
LK.setScore(LK.getScore() + 2); // Same scoring as swish mode
if (scoreTxt) {
scoreTxt.setText('Score: ' + LK.getScore());
}
// Update player scores in 2 player mode
if (gameMode === '2player') {
if (twoPlayerState === 'player1') {
player1Score = LK.getScore();
if (player1ScoreTxt) {
player1ScoreTxt.setText('P1: ' + player1Score);
}
} else if (twoPlayerState === 'player2') {
player2Score = LK.getScore();
if (player2ScoreTxt) {
player2ScoreTxt.setText('P2: ' + player2Score);
}
}
}
// Check and update rhythm mode best score when scoring
var currentScore = LK.getScore();
if (currentScore > rhythmBestScore) {
rhythmBestScore = currentScore;
storage.rhythmBestScore = rhythmBestScore;
bestScore = rhythmBestScore;
bestScoreTxt.setText('Best: ' + bestScore);
}
// Increase streak for perfect swish
currentStreak++;
if (streakTxt) {
//{lT_new}
streakTxt.setText('Streak: ' + currentStreak);
} //{lT_end}
// Play swish sound
LK.getSound('swish').play();
// Make the player in that row shoot a perfect swish
// In 2 player rhythm mode, use tap zone positions since no shot bars exist
var targetHoop = hoop; // Default to center hoop
var activePlayer = 1;
var startX = 1024;
var startY = 2000;
// Determine which player/hoop based on circle position (for 2 player rhythm mode)
if (gameMode === '2player' && twoPlayerRhythmMode) {
// Use circle position to determine which hoop to target
if (rhythmResult.circle.x <= 600) {
// Left position
targetHoop = leftHoop;
activePlayer = 2;
startX = 300;
} else if (rhythmResult.circle.x >= 1400) {
// Right position
targetHoop = rightHoop;
activePlayer = 3;
startX = 1748;
} else {
// Center position
targetHoop = hoop;
activePlayer = 1;
startX = 1024;
}
} else if (rhythmResult.circle && rhythmResult.circle.targetShotBar) {
// Regular rhythm mode with shot bars
var targetBar = rhythmResult.circle.targetShotBar;
// Determine which player/hoop based on target shot bar
if (targetBar === shotBar2) {
// Left player (Player2)
targetHoop = leftHoop;
activePlayer = 2;
startX = 300;
} else if (targetBar === shotBar3) {
// Right player (Player3)
targetHoop = rightHoop;
activePlayer = 3;
startX = 1748;
}
}
// Switch player sprites to shooting position
if (activePlayer === 1) {
player1.visible = true;
player1down.visible = false;
LK.setTimeout(function () {
player1.visible = false;
player1down.visible = true;
}, 1000);
} else if (activePlayer === 2) {
player2.visible = true;
player2down.visible = false;
LK.setTimeout(function () {
player2.visible = false;
player2down.visible = true;
}, 1000);
} else if (activePlayer === 3) {
player3.visible = true;
player3down.visible = false;
LK.setTimeout(function () {
player3.visible = false;
player3down.visible = true;
}, 1000);
}
// Calculate perfect shot trajectory with enhanced precision
var targetX = targetHoop.x;
var targetY = targetHoop.y - 350; // Aim directly at hoop center
var deltaX = targetX - startX;
var deltaY = targetY - startY;
// Use optimized timing for guaranteed success
var time = 45; // Slightly faster for better arc
var gravity = 0.5;
// Calculate perfect trajectory velocities with downward bias for clean entry
var velocityX = deltaX / time;
var velocityY = deltaY / time - 0.5 * gravity * time - 1.5; // Extra downward bias
// Fine-tune horizontal velocity to ensure center entry
var horizontalCorrection = (targetX - startX) * 0.02; // Small correction factor
velocityX += horizontalCorrection;
// Create perfect swish basketball
var ball = createBasketball(startX, startY, velocityX, velocityY);
ball.isPerfectShot = true;
ball.guaranteedSwish = true;
// Set additional properties to ensure scoring
ball.hasScored = false; // Ensure it can score
ball.isActive = true; // Ensure it's active
// Add rotation animation
tween(ball, {
rotation: ball.rotation + Math.PI * 4
}, {
duration: 1500,
easing: tween.easeOut
});
} else if (rhythmResult.tapped) {
// Mark circle as tapped to prevent reuse
rhythmResult.circle.hasBeenTapped = true;
// Rhythm circle tapped but not in tap zone - reset streaks
rhythmStreak = 0;
rhythmMultiplier = 1;
currentStreak = 0;
if (streakTxt) {
//{mR_new}
streakTxt.setText('Streak: ' + currentStreak);
} //{mR_end}
streakRewardsAwarded = []; // Reset streak rewards
// Remove onfire effects from all nets when streak is reset and show nets
if (hoop && hoop.onfire) {
hoop.net.visible = true;
hoop.onfire.destroy();
hoop.onfire = null;
}
if (leftHoop && leftHoop.onfire) {
leftHoop.net.visible = true;
leftHoop.onfire.destroy();
leftHoop.onfire = null;
}
if (rightHoop && rightHoop.onfire) {
rightHoop.net.visible = true;
rightHoop.onfire.destroy();
rightHoop.onfire = null;
}
// Remove red flash to prevent excessive flashing
}
// Remove tapped circle with animation
if (rhythmResult.circle) {
tween(rhythmResult.circle, {
scaleX: 2.0,
scaleY: 2.0,
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
rhythmResult.circle.isActive = false;
}
});
}
return rhythmResult.tapped;
}
function createCountdownOverlay(message, count) {
// Create semi-transparent overlay
var countdownOverlay = game.addChild(LK.getAsset('TitleBackground', {
anchorX: 0,
anchorY: 0
}));
countdownOverlay.x = 0;
countdownOverlay.y = 0;
countdownOverlay.width = 2048;
countdownOverlay.height = 2732;
countdownOverlay.tint = 0x000000;
countdownOverlay.alpha = 0.7;
countdownOverlay.zIndex = 100;
// Create message text
var messageText = new Text2(message, {
size: 70,
fill: 0xFFFFFF
});
messageText.anchor.set(0.5, 0.5);
messageText.x = 1024;
messageText.y = 1100;
messageText.zIndex = 101;
game.addChild(messageText);
// Create countdown container
countdownContainer = new Container();
countdownContainer.x = 1024;
countdownContainer.y = 1366;
countdownContainer.zIndex = 102;
game.addChild(countdownContainer);
// Store references for cleanup
game.countdownOverlay = countdownOverlay;
game.countdownMessage = messageText;
// Start countdown animation
countdownActive = true;
countdownTimer = count;
updateCountdownDisplay();
}
function updateCountdownDisplay() {
if (!countdownActive || !countdownContainer) return;
// Clear existing countdown number
while (countdownContainer.children.length > 0) {
var child = countdownContainer.children[0];
countdownContainer.removeChild(child);
child.destroy();
}
if (countdownTimer > 0) {
// Create enlarged number asset for current countdown
var numberAsset = LK.getAsset(countdownTimer.toString(), {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4.0,
scaleY: 4.0
});
numberAsset.x = 0;
numberAsset.y = 0;
numberAsset.alpha = 0;
countdownContainer.addChild(numberAsset);
// Animate number appearance
tween(numberAsset, {
alpha: 1.0,
scaleX: 5.0,
scaleY: 5.0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// Animate number disappearance
tween(numberAsset, {
alpha: 0,
scaleX: 3.0,
scaleY: 3.0
}, {
duration: 700,
easing: tween.easeIn
});
}
});
} else {
// Show "GO!" message
var goText = new Text2('GO!', {
size: 120,
fill: 0x00FF00
});
goText.anchor.set(0.5, 0.5);
goText.x = 0;
goText.y = 0;
goText.alpha = 0;
countdownContainer.addChild(goText);
// Animate GO! message
tween(goText, {
alpha: 1.0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(goText, {
alpha: 0,
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 600,
easing: tween.easeIn
});
}
});
}
}
function hideCountdownOverlay() {
countdownActive = false;
countdownTimer = 0;
if (game.countdownOverlay) {
game.countdownOverlay.destroy();
game.countdownOverlay = null;
}
if (game.countdownMessage) {
game.countdownMessage.destroy();
game.countdownMessage = null;
}
if (countdownContainer) {
countdownContainer.destroy();
countdownContainer = null;
}
}
function createTransitionOverlay(message) {
// Create semi-transparent overlay
transitionOverlay = game.addChild(LK.getAsset('TitleBackground', {
anchorX: 0,
anchorY: 0
}));
transitionOverlay.x = 0;
transitionOverlay.y = 0;
transitionOverlay.width = 2048;
transitionOverlay.height = 2732;
transitionOverlay.tint = 0x000000;
transitionOverlay.alpha = 0.8;
transitionOverlay.zIndex = 100;
// Create transition message
transitionText = new Text2(message, {
size: 80,
fill: 0xFFFFFF
});
transitionText.anchor.set(0.5, 0.5);
transitionText.x = 1024;
transitionText.y = 1200;
transitionText.zIndex = 101;
game.addChild(transitionText);
// Create countdown text
var countdownText = new Text2('STARTING IN 3...', {
size: 60,
fill: 0xFF4444
});
countdownText.anchor.set(0.5, 0.5);
countdownText.x = 1024;
countdownText.y = 1400;
countdownText.zIndex = 101;
game.addChild(countdownText);
game.transitionCountdown = countdownText;
// Animate countdown
var count = 3;
var countdownInterval = LK.setInterval(function () {
if (count > 1) {
count--;
countdownText.setText('STARTING IN ' + count + '...');
} else {
countdownText.setText('GO!');
LK.clearInterval(countdownInterval);
}
}, 60); // Update every second
}
function hideTransitionOverlay() {
if (transitionOverlay) {
transitionOverlay.destroy();
transitionOverlay = null;
}
if (transitionText) {
transitionText.destroy();
transitionText = null;
}
if (game.transitionCountdown) {
game.transitionCountdown.destroy();
game.transitionCountdown = null;
}
}
function createWinnerOverlay(title, subtitle) {
// Create semi-transparent overlay
var winnerOverlay = game.addChild(LK.getAsset('TitleBackground', {
anchorX: 0,
anchorY: 0
}));
winnerOverlay.x = 0;
winnerOverlay.y = 0;
winnerOverlay.width = 2048;
winnerOverlay.height = 2732;
winnerOverlay.tint = 0x000000;
winnerOverlay.alpha = 0.8;
winnerOverlay.zIndex = 100;
// Create winner title
var winnerTitle = new Text2(title, {
size: 100,
fill: 0xFFD700
});
winnerTitle.anchor.set(0.5, 0.5);
winnerTitle.x = 1024;
winnerTitle.y = 1100;
winnerTitle.zIndex = 101;
game.addChild(winnerTitle);
// Create subtitle
var winnerSubtitle = new Text2(subtitle, {
size: 60,
fill: 0xFFFFFF
});
winnerSubtitle.anchor.set(0.5, 0.5);
winnerSubtitle.x = 1024;
winnerSubtitle.y = 1300;
winnerSubtitle.zIndex = 101;
game.addChild(winnerSubtitle);
// Create continue instruction
var continueText = new Text2('TAP TO CONTINUE', {
size: 50,
fill: 0x44FF44
});
continueText.anchor.set(0.5, 0.5);
continueText.x = 1024;
continueText.y = 1500;
continueText.zIndex = 101;
game.addChild(continueText);
// Store references for cleanup
game.winnerOverlay = winnerOverlay;
game.winnerTitle = winnerTitle;
game.winnerSubtitle = winnerSubtitle;
game.winnerContinueText = continueText;
// Set the time when winner display was created
game.winnerDisplayTime = LK.ticks;
// Animate winner title with pulsing effect
tween(winnerTitle, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (winnerTitle) {
tween(winnerTitle, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: arguments.callee
});
}
}
});
}
function checkAllBackboardsSameColor() {
// Check if all three backboards have the same color
var allSame = backboardColors[0] === backboardColors[1] && backboardColors[1] === backboardColors[2];
// Debug logging to see what's happening
console.log('Checking colors:', backboardColors, 'All same:', allSame, 'Current multiplier:', allSameColorMultiplier);
// Only activate multiplier if colors changed to same (not if already same)
// Also ensure we're not comparing the initial white colors
if (allSame && !allSameColorMultiplier && backboardColors[0] !== 0xFFFFFF) {
allSameColorMultiplier = true;
console.log('Activating 2x multiplier!');
multiplierTxt.setText('2X MULTIPLIER ACTIVE!');
// Award $100.00 if not already awarded for this color match
if (!moneyAwarded) {
currentMoney += 100.00;
storage.money = currentMoney;
if (moneyTxt) {
moneyTxt.setText('$' + currentMoney.toFixed(2));
}
moneyAwarded = true;
LK.getSound('Cash').play(); // Play cash sound when money is awarded
console.log('Awarded $100.00! Total money:', currentMoney);
}
} else if (!allSame && allSameColorMultiplier) {
allSameColorMultiplier = false;
moneyAwarded = false; // Reset money award flag when colors no longer match
console.log('Deactivating 2x multiplier');
multiplierTxt.setText('');
}
}
game.down = function (x, y, obj) {
// Handle 2 player winner overlay clicks
if (gameMode === '2player' && game.winnerOverlay) {
// Check if enough time has passed since winner display was shown (3 seconds minimum)
var currentTime = LK.ticks;
if (!game.winnerDisplayTime) {
game.winnerDisplayTime = currentTime;
return; // Don't allow dismissal yet
}
var timeDisplayed = currentTime - game.winnerDisplayTime;
var minimumDisplayTime = 3 * 60; // 3 seconds at 60 FPS
if (timeDisplayed < minimumDisplayTime) {
return; // Don't allow dismissal until minimum time has passed
}
// Clean up winner overlay
if (game.winnerOverlay) {
game.winnerOverlay.destroy();
game.winnerOverlay = null;
}
if (game.winnerTitle) {
tween.stop(game.winnerTitle);
game.winnerTitle.destroy();
game.winnerTitle = null;
}
if (game.winnerSubtitle) {
game.winnerSubtitle.destroy();
game.winnerSubtitle = null;
}
if (game.winnerContinueText) {
game.winnerContinueText.destroy();
game.winnerContinueText = null;
}
// Reset winner display time
game.winnerDisplayTime = null;
// Clean up UI elements before returning to title screen
cleanupUIElements(); //{nz_new}
// Return to title screen
gameState = 'title';
gameMode = 'swish';
twoPlayerRhythmMode = false; // Reset rhythm mode flag
initializeTitleScreen();
return;
}
// Handle title screen clicks
if (gameState === 'title') {
// Check if store is showing
if (game.storeBackground) {
// Check if clicked on pacers ball item (expanded click area for better detection)
if (game.storeItem && game.storeItemImage) {
var itemLeft = game.storeItemImage.x - 250;
var itemRight = game.storeItemImage.x + 250;
var itemTop = game.storeItemImage.y - 200;
var itemBottom = game.storeItemImage.y + 200;
if (x >= itemLeft && x <= itemRight && y >= itemTop && y <= itemBottom) {
// Try to purchase item or select if owned
if (!game.storeItem.unlocked && gameStore.purchaseItem(game.storeItem)) {
// Switch to pacers mode when pacers team pack is purchased
if (game.storeItem.id === 'pacersball') {
currentBasketballMode = pacersMode; // Switch to pacersball
// Switch to pacers mode players (player4, player5, player6)
defaultPlayers = pacersPlayers.slice(); // Copy pacers players array
// Save the current basketball mode to storage
storage.currentBasketballMode = currentBasketballMode;
storage.defaultPlayers = defaultPlayers;
// Mark item as unlocked in storage
storage.pacersball_unlocked = true;
// Swap player sprites if currently in game
if (gameState === 'playing') {
swapPlayerSprites();
swapBasketballAssets();
}
// Update item status display
if (game.storeItemStatusText) {
game.storeItemStatusText.setText('SELECTED');
game.storeItemStatusText.tint = 0x00FF00;
}
// Update item price text color to show it's owned
if (game.storeItemPriceText) {
game.storeItemPriceText.tint = 0x888888; // Gray out price when owned
}
}
// Update money display
if (moneyTxt) {
moneyTxt.setText('$' + currentMoney.toFixed(2));
}
// Update store money display
if (game.storeMoneyText) {
game.storeMoneyText.setText('Money: $' + currentMoney.toFixed(2));
}
// Update item status display
if (game.storeItemStatusText) {
game.storeItemStatusText.setText('SELECTED');
game.storeItemStatusText.tint = 0x00FF00;
}
// Update item price text color to show it's owned
if (game.storeItemPriceText) {
game.storeItemPriceText.tint = 0x888888; // Gray out price when owned
}
} else if (game.storeItem.unlocked) {
// Item already owned - select it
if (game.storeItem.id === 'pacersball') {
currentBasketballMode = pacersMode; // Switch to pacersball
// Switch to pacers mode players (player4, player5, player6)
defaultPlayers = pacersPlayers.slice(); // Copy pacers players array
// Save the current basketball mode to storage
storage.currentBasketballMode = currentBasketballMode;
storage.defaultPlayers = defaultPlayers;
// Swap player sprites if currently in game
if (gameState === 'playing') {
swapPlayerSprites();
swapBasketballAssets();
}
// Update item status display
if (game.storeItemStatusText) {
game.storeItemStatusText.setText('SELECTED');
game.storeItemStatusText.tint = 0x00FF00;
}
// Update thunder item status to not selected
if (game.storeThunderItemStatusText) {
game.storeThunderItemStatusText.setText('TAP TO SELECT');
game.storeThunderItemStatusText.tint = 0xFFFFFF;
}
// Update warriors item status to not selected
if (game.storeWarriorsItemStatusText) {
game.storeWarriorsItemStatusText.setText('TAP TO SELECT');
game.storeWarriorsItemStatusText.tint = 0xFFFFFF;
}
// Play selection sound
LK.getSound('Cash').play();
}
} else if (!gameStore.canAfford(game.storeItem)) {
// Not enough money - flash red briefly
if (game.storeItemPriceText) {
var originalTint = game.storeItemPriceText.tint;
game.storeItemPriceText.tint = 0xFF0000;
LK.setTimeout(function () {
if (game.storeItemPriceText) {
game.storeItemPriceText.tint = originalTint;
}
}, 500);
}
}
return;
}
}
// Check if clicked on thunder ball item
if (game.storeThunderItem && game.storeThunderItemImage) {
var thunderItemLeft = game.storeThunderItemImage.x - 250;
var thunderItemRight = game.storeThunderItemImage.x + 250;
var thunderItemTop = game.storeThunderItemImage.y - 200;
var thunderItemBottom = game.storeThunderItemImage.y + 200;
if (x >= thunderItemLeft && x <= thunderItemRight && y >= thunderItemTop && y <= thunderItemBottom) {
// Try to purchase thunder item or select if owned
if (!game.storeThunderItem.unlocked && gameStore.purchaseItem(game.storeThunderItem)) {
// Switch to thunder mode when thunder team pack is purchased
if (game.storeThunderItem.id === 'thunderball') {
currentBasketballMode = thunderMode; // Switch to Thunderball
// Switch to thunder mode players (player7, player8, player9)
defaultPlayers = thunderPlayers.slice(); // Copy thunder players array
// Save the current basketball mode to storage
storage.currentBasketballMode = currentBasketballMode;
storage.defaultPlayers = defaultPlayers;
// Swap player sprites if currently in game
if (gameState === 'playing') {
swapPlayerSprites();
swapBasketballAssets();
}
}
// Update money display
if (moneyTxt) {
moneyTxt.setText('$' + currentMoney.toFixed(2));
}
// Update store money display
if (game.storeMoneyText) {
game.storeMoneyText.setText('Money: $' + currentMoney.toFixed(2));
}
// Update item status display
if (game.storeThunderItemStatusText) {
game.storeThunderItemStatusText.setText('SELECTED');
game.storeThunderItemStatusText.tint = 0x00FF00;
}
// Update item price text color to show it's owned
if (game.storeThunderItemPriceText) {
game.storeThunderItemPriceText.tint = 0x888888; // Gray out price when owned
}
} else if (game.storeThunderItem.unlocked) {
// Item already owned - select it
if (game.storeThunderItem.id === 'thunderball') {
currentBasketballMode = thunderMode; // Switch to Thunderball
// Switch to thunder mode players (player7, player8, player9)
defaultPlayers = thunderPlayers.slice(); // Copy thunder players array
// Save the current basketball mode to storage
storage.currentBasketballMode = currentBasketballMode;
storage.defaultPlayers = defaultPlayers;
// Swap player sprites if currently in game
if (gameState === 'playing') {
swapPlayerSprites();
swapBasketballAssets();
}
// Update item status display
if (game.storeThunderItemStatusText) {
game.storeThunderItemStatusText.setText('SELECTED');
game.storeThunderItemStatusText.tint = 0x00FF00;
}
// Update pacers item status to not selected
if (game.storeItemStatusText) {
game.storeItemStatusText.setText('TAP TO SELECT');
game.storeItemStatusText.tint = 0xFFFFFF;
}
// Update warriors item status to not selected
if (game.storeWarriorsItemStatusText) {
game.storeWarriorsItemStatusText.setText('TAP TO SELECT');
game.storeWarriorsItemStatusText.tint = 0xFFFFFF;
}
// Play selection sound
LK.getSound('Cash').play();
}
} else if (!gameStore.canAfford(game.storeThunderItem)) {
// Not enough money - flash red briefly
if (game.storeThunderItemPriceText) {
var originalThunderTint = game.storeThunderItemPriceText.tint;
game.storeThunderItemPriceText.tint = 0xFF0000;
LK.setTimeout(function () {
if (game.storeThunderItemPriceText) {
game.storeThunderItemPriceText.tint = originalThunderTint;
}
}, 500);
}
}
return;
}
}
// Check if clicked on 2playvs pack item
if (game.store2PlayerVsItem && game.store2PlayerVsItemImage) {
var twoPlayerVsItemLeft = game.store2PlayerVsItemImage.x - 250;
var twoPlayerVsItemRight = game.store2PlayerVsItemImage.x + 250;
var twoPlayerVsItemTop = game.store2PlayerVsItemImage.y - 200;
var twoPlayerVsItemBottom = game.store2PlayerVsItemImage.y + 200;
if (x >= twoPlayerVsItemLeft && x <= twoPlayerVsItemRight && y >= twoPlayerVsItemTop && y <= twoPlayerVsItemBottom) {
// Try to purchase 2playvs pack
if (!game.store2PlayerVsItem.unlocked && gameStore.purchaseItem(game.store2PlayerVsItem)) {
// Successfully purchased 2 Player Rhythm pack
storage['2playvs_unlocked'] = true;
// Update money display
if (moneyTxt) {
moneyTxt.setText('$' + currentMoney.toFixed(2));
}
// Update store money display
if (game.storeMoneyText) {
game.storeMoneyText.setText('Money: $' + currentMoney.toFixed(2));
}
// Update item status display
if (game.store2PlayerVsItemStatusText) {
game.store2PlayerVsItemStatusText.setText('UNLOCKED');
game.store2PlayerVsItemStatusText.tint = 0x00FF00;
}
// Update item price text color to show it's owned
if (game.store2PlayerVsItemPriceText) {
game.store2PlayerVsItemPriceText.tint = 0x888888; // Gray out price when owned
}
} else if (!gameStore.canAfford(game.store2PlayerVsItem)) {
// Not enough money - flash red briefly
if (game.store2PlayerVsItemPriceText) {
var originalTint = game.store2PlayerVsItemPriceText.tint;
game.store2PlayerVsItemPriceText.tint = 0xFF0000;
LK.setTimeout(function () {
if (game.store2PlayerVsItemPriceText) {
game.store2PlayerVsItemPriceText.tint = originalTint;
}
}, 500);
}
}
return;
}
}
// Check if clicked on swish2playvs pack item
if (game.storeSwish2PlayerVsItem && game.storeSwish2PlayerVsItemImage) {
var swishTwoPlayerVsItemLeft = game.storeSwish2PlayerVsItemImage.x - 250;
var swishTwoPlayerVsItemRight = game.storeSwish2PlayerVsItemImage.x + 250;
var swishTwoPlayerVsItemTop = game.storeSwish2PlayerVsItemImage.y - 200;
var swishTwoPlayerVsItemBottom = game.storeSwish2PlayerVsItemImage.y + 200;
if (x >= swishTwoPlayerVsItemLeft && x <= swishTwoPlayerVsItemRight && y >= swishTwoPlayerVsItemTop && y <= swishTwoPlayerVsItemBottom) {
// Try to purchase swish2playvs pack
if (!game.storeSwish2PlayerVsItem.unlocked && gameStore.purchaseItem(game.storeSwish2PlayerVsItem)) {
// Successfully purchased 2 Player Swish pack
storage['swish2playvs_unlocked'] = true;
// Update money display
if (moneyTxt) {
moneyTxt.setText('$' + currentMoney.toFixed(2));
}
// Update store money display
if (game.storeMoneyText) {
game.storeMoneyText.setText('Money: $' + currentMoney.toFixed(2));
}
// Update item status display
if (game.storeSwish2PlayerVsItemStatusText) {
game.storeSwish2PlayerVsItemStatusText.setText('UNLOCKED');
game.storeSwish2PlayerVsItemStatusText.tint = 0x00FF00;
}
// Update item price text color to show it's owned
if (game.storeSwish2PlayerVsItemPriceText) {
game.storeSwish2PlayerVsItemPriceText.tint = 0x888888; // Gray out price when owned
}
} else if (!gameStore.canAfford(game.storeSwish2PlayerVsItem)) {
// Not enough money - flash red briefly
if (game.storeSwish2PlayerVsItemPriceText) {
var originalTint = game.storeSwish2PlayerVsItemPriceText.tint;
game.storeSwish2PlayerVsItemPriceText.tint = 0xFF0000;
LK.setTimeout(function () {
if (game.storeSwish2PlayerVsItemPriceText) {
game.storeSwish2PlayerVsItemPriceText.tint = originalTint;
}
}, 500);
}
}
return;
}
}
// Check if clicked on aibattle pack item
if (game.storeAibattleItem && game.storeAibattleItemImage) {
var aibattleItemLeft = game.storeAibattleItemImage.x - 175;
var aibattleItemRight = game.storeAibattleItemImage.x + 175;
var aibattleItemTop = game.storeAibattleItemImage.y - 175;
var aibattleItemBottom = game.storeAibattleItemImage.y + 175;
if (x >= aibattleItemLeft && x <= aibattleItemRight && y >= aibattleItemTop && y <= aibattleItemBottom) {
// Try to purchase aibattle pack
if (!game.storeAibattleItem.unlocked && gameStore.purchaseItem(game.storeAibattleItem)) {
// Successfully purchased AI Battle pack
storage['aibattle_unlocked'] = true;
// Update money display//{tU_new1}
if (moneyTxt) {
//{tU_new2}
moneyTxt.setText('$' + currentMoney.toFixed(2)); //{tU_new3}
} //{tU_new4}
// Update store money display//{tU_new5}
if (game.storeMoneyText) {
//{tU_new6}
game.storeMoneyText.setText('Money: $' + currentMoney.toFixed(2)); //{tU_new7}
} //{tU_new8}
// Update item status display//{tU_new9}
if (game.storeAibattleItemStatusText) {
//{tU_new10}
game.storeAibattleItemStatusText.setText('UNLOCKED');
game.storeAibattleItemStatusText.tint = 0x00FF00;
} //{tU_new11}
// Update item price text color to show it's owned//{tU_new12}
if (game.storeAibattleItemPriceText) {
//{tU_new13}
game.storeAibattleItemPriceText.tint = 0x888888; // Gray out price when owned
} //{tU_new14}
} else if (!gameStore.canAfford(game.storeAibattleItem)) {
// Not enough money - flash red briefly//{tU_new15}
if (game.storeAibattleItemPriceText) {
//{tU_new16}
var originalTint = game.storeAibattleItemPriceText.tint;
game.storeAibattleItemPriceText.tint = 0xFF0000;
LK.setTimeout(function () {
//{tU_new17}
if (game.storeAibattleItemPriceText) {
//{tU_new18}
game.storeAibattleItemPriceText.tint = originalTint;
} //{tU_new19}
}, 500); //{tU_new20}
} //{tU_new21}
} //{tU_new22}
return; //{tU_new23}
} //{tU_new24}
} //{tU_new25}
// Check if clicked on Warriorsball item (default mode)
if (game.storeWarriorsItemImage) {
var warriorsItemLeft = game.storeWarriorsItemImage.x - 250;
var warriorsItemRight = game.storeWarriorsItemImage.x + 250;
var warriorsItemTop = game.storeWarriorsItemImage.y - 200;
var warriorsItemBottom = game.storeWarriorsItemImage.y + 200;
if (x >= warriorsItemLeft && x <= warriorsItemRight && y >= warriorsItemTop && y <= warriorsItemBottom) {
// Switch back to default Warriors mode
currentBasketballMode = defaultBasketballMode; // Switch to Warriorsball
// Switch back to default mode players (player1, player2, player3)
defaultPlayers = ['player1', 'player2', 'player3']; // Reset to default players
// Save the current basketball mode to storage
storage.currentBasketballMode = currentBasketballMode;
storage.defaultPlayers = defaultPlayers;
// Swap player sprites if currently in game
if (gameState === 'playing') {
swapPlayerSprites();
swapBasketballAssets();
}
// Update basketball mode display
if (game.basketballModeText) {
game.basketballModeText.setText(currentBasketballMode);
}
// Visual feedback
if (game.storeWarriorsItemStatusText) {
game.storeWarriorsItemStatusText.setText('SELECTED');
game.storeWarriorsItemStatusText.tint = 0x00FF00;
}
// Update pacers item status to not selected
if (game.storeItemStatusText) {
game.storeItemStatusText.setText('TAP TO SELECT');
game.storeItemStatusText.tint = 0xFFFFFF;
}
// Update thunder item status to not selected
if (game.storeThunderItemStatusText) {
game.storeThunderItemStatusText.setText('TAP TO SELECT');
game.storeThunderItemStatusText.tint = 0xFFFFFF;
}
// Play selection sound
LK.getSound('Cash').play();
return;
}
}
hideStore();
return;
}
// Check if instructions are showing
if (game.instructionsOverlay) {
hideHowToPlay();
return;
}
// Check if clicked on start button area (tap to start button)
var buttonLeft = startButton.x - 250; // Half of button width
var buttonRight = startButton.x + 250;
var buttonTop = startButton.y - 250; // Half of button height
var buttonBottom = startButton.y + 250;
if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) {
initializeModeSelection();
return;
}
// Check if clicked on how to play button
if (game.howToPlayButton) {
var howToLeft = game.howToPlayButton.x - 150;
var howToRight = game.howToPlayButton.x + 150;
var howToTop = game.howToPlayButton.y - 150;
var howToBottom = game.howToPlayButton.y + 150;
if (x >= howToLeft && x <= howToRight && y >= howToTop && y <= howToBottom) {
showHowToPlay();
return;
}
}
// Check if clicked on shop button
if (game.shopButton) {
var shopLeft = game.shopButton.x - 150;
var shopRight = game.shopButton.x + 150;
var shopTop = game.shopButton.y - 150;
var shopBottom = game.shopButton.y + 150;
if (x >= shopLeft && x <= shopRight && y >= shopTop && y <= shopBottom) {
showStore();
return;
}
}
return;
}
// Handle mode selection clicks
if (gameState === 'modeSelect') {
// Check Swish button
var swishLeft = swishButton.x - 200;
var swishRight = swishButton.x + 200;
var swishTop = swishButton.y - 150;
var swishBottom = swishButton.y + 150;
if (x >= swishLeft && x <= swishRight && y >= swishTop && y <= swishBottom) {
gameMode = 'swish';
LK.playMusic('backgroundMusic');
initializeGameplay();
return;
}
// Check Rhythm button
var rhythmLeft = rhythmButton.x - 200;
var rhythmRight = rhythmButton.x + 200;
var rhythmTop = rhythmButton.y - 50;
var rhythmBottom = rhythmButton.y + 50;
if (x >= rhythmLeft && x <= rhythmRight && y >= rhythmTop && y <= rhythmBottom) {
gameMode = 'rhythm';
LK.playMusic('Title');
musicStarted = true; // Mark music as started
initializeGameplay();
return;
}
// Check AI vs button
if (game.aiVsButton) {
var aiVsLeft = game.aiVsButton.x - 150;
var aiVsRight = game.aiVsButton.x + 150;
var aiVsTop = game.aiVsButton.y - 150;
var aiVsBottom = game.aiVsButton.y + 150;
if (x >= aiVsLeft && x <= aiVsRight && y >= aiVsTop && y <= aiVsBottom) {
// Check if AI Battle pack is unlocked
if (storage['aibattle_unlocked']) {
gameMode = 'ai_vs';
LK.playMusic('Second');
initializeGameplay();
} else {
//{uP_new1}
// Show message that pack needs to be purchased//{uP_new2}
// Flash the button to indicate it's locked//{uP_new3}
tween(game.aiVsButton, {
//{uP_new4}
tint: 0xFF0000,
//{uP_new5}
alpha: 0.5 //{uP_new6}
}, {
//{uP_new7}
duration: 200,
//{uP_new8}
easing: tween.easeOut,
//{uP_new9}
onFinish: function onFinish() {
//{uP_new10}
tween(game.aiVsButton, {
//{uP_new11}
tint: 0xFFFFFF,
//{uP_new12}
alpha: 1.0 //{uP_new13}
}, {
//{uP_new14}
duration: 200,
//{uP_new15}
easing: tween.easeIn //{uP_new16}
}); //{uP_new17}
} //{uP_new18}
}); //{uP_new19}
} //{uP_new20}
return;
}
}
// Check 2 Player vs button
if (game.twoPlayerButton) {
var twoPlayerLeft = game.twoPlayerButton.x - 150;
var twoPlayerRight = game.twoPlayerButton.x + 150;
var twoPlayerTop = game.twoPlayerButton.y - 150;
var twoPlayerBottom = game.twoPlayerButton.y + 150;
if (x >= twoPlayerLeft && x <= twoPlayerRight && y >= twoPlayerTop && y <= twoPlayerBottom) {
// Check if 2 Player Swish pack is unlocked
if (storage['swish2playvs_unlocked']) {
gameMode = '2player';
twoPlayerRhythmMode = false;
LK.playMusic('Third');
initializeGameplay();
} else {
// Show message that pack needs to be purchased
// Flash the button to indicate it's locked
tween(game.twoPlayerButton, {
tint: 0xFF0000,
alpha: 0.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(game.twoPlayerButton, {
tint: 0xFFFFFF,
alpha: 1.0
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
return;
}
}
// Check if clicked on 2 Player Rhythm vs button
if (game.twoPlayerRhythmButton) {
var twoPlayerRhythmLeft = game.twoPlayerRhythmButton.x - 150;
var twoPlayerRhythmRight = game.twoPlayerRhythmButton.x + 150;
var twoPlayerRhythmTop = game.twoPlayerRhythmButton.y - 150;
var twoPlayerRhythmBottom = game.twoPlayerRhythmButton.y + 150;
if (x >= twoPlayerRhythmLeft && x <= twoPlayerRhythmRight && y >= twoPlayerRhythmTop && y <= twoPlayerRhythmBottom) {
// Check if 2 Player Rhythm pack is unlocked
if (storage['2playvs_unlocked']) {
gameMode = '2player';
twoPlayerRhythmMode = true;
LK.playMusic('Sunrise');
musicStarted = true; // Mark music as started
initializeGameplay();
} else {
// Show message that pack needs to be purchased
// Flash the button to indicate it's locked
tween(game.twoPlayerRhythmButton, {
tint: 0xFF0000,
alpha: 0.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(game.twoPlayerRhythmButton, {
tint: 0xFFFF00,
alpha: 1.0
}, {
duration: 200,
easing: tween.easeIn
});
}
});
}
return;
}
}
return;
}
// In rhythm mode or 2 player rhythm mode, only process rhythm circle taps, disable shooting
if (gameMode === 'rhythm' || gameMode === '2player' && twoPlayerRhythmMode) {
checkSimultaneousTap(x, y);
return; // Don't process shooting in rhythm mode
}
// Prevent shooting during countdown in 2player mode
if (gameMode === '2player' && countdownActive) {
return;
}
// In AI vs mode, use normal shooting mechanics
if (gameMode === 'ai_vs') {
// Continue with normal shooting logic
}
if (LK.ticks - lastShotTime < 30) return; // Reduce cooldown for better responsiveness
// Unlock buttons removed - players are now always unlocked
// Check if tap is below the top of the backboard (backboards are at y=1300 and extend up ~726 pixels)
// Greatly increased tap sensitivity by expanding the detection area further
var backboardTopY = 1300 - 1100; // Expanded tap area by 374 pixels above backboard (200)
if (y <= backboardTopY) {
return; // Don't allow shooting if tapping above the backboard
}
// Determine which player/hoop to target based on tap position
var targetHoop = hoop;
var currentShotBar = shotBar;
var activePlayer = 1; // Track which player is shooting
if (x < 683) {
// Left third of screen - Player2's area
targetHoop = leftHoop;
currentShotBar = shotBar2;
activePlayer = 2;
} else if (x > 1365) {
// Right third of screen - Player3's area
targetHoop = rightHoop;
currentShotBar = shotBar3;
activePlayer = 3;
}
if (currentShotBar.isActive) {
// Stop the shot bar and check for perfect shot
var isPerfect = currentShotBar.stopMoving();
isChargingShot = false;
// Check rhythm timing if in rhythm mode
var onBeat = false;
if (gameMode === 'rhythm') {
var timeSinceLastBeat = LK.ticks - lastBeatTime;
var timeToNextBeat = beatInterval - timeSinceLastBeat;
// Check if shot is within beat tolerance
if (timeSinceLastBeat <= beatTolerance || timeToNextBeat <= beatTolerance) {
onBeat = true;
rhythmStreak++;
rhythmMultiplier = Math.min(3, 1 + Math.floor(rhythmStreak / 5) * 0.5); // Max 3x multiplier
// Remove pink flash to prevent excessive flashing
} else {
rhythmStreak = 0;
rhythmMultiplier = 1;
}
}
// Switch sprites for the appropriate player
if (activePlayer === 1) {
// Player1 shooting
player1.visible = true;
player1down.visible = false;
// Switch back after 1 second
LK.setTimeout(function () {
player1.visible = false;
player1down.visible = true;
}, 1000);
} else if (activePlayer === 2) {
// Player2 shooting
player2.visible = true;
player2down.visible = false;
// Switch back after 1 second
LK.setTimeout(function () {
player2.visible = false;
player2down.visible = true;
}, 1000);
} else if (activePlayer === 3) {
// Player3 shooting
player3.visible = true;
player3down.visible = false;
// Switch back after 1 second
LK.setTimeout(function () {
player3.visible = false;
player3down.visible = true;
}, 1000);
}
// Calculate shooting parameters based on active player
var startX, startY;
if (activePlayer === 2) {
// Launch from Player2's position (left player)
startX = 300; // Player2's x position
startY = 2000;
} else if (activePlayer === 3) {
// Launch from Player3's position (right player)
startX = 1748; // Player3's x position
startY = 2000;
} else {
// Launch from Player1's position (center) for main hoop
startX = 1024; // Player1's x position
startY = 2000;
}
var velocityX = 0;
var velocityY = -20; // Base upward velocity
if (isPerfect) {
// Perfect shot - guaranteed swish trajectory
var targetX = targetHoop.x;
var targetY = targetHoop.y - 350; // Aim directly at hoop center for clean entry
var deltaX = targetX - startX;
var deltaY = targetY - startY;
// Calculate perfect parabolic trajectory for guaranteed swish
var time = 45; // Optimized timing for better arc
var gravity = 0.5; // Match basketball gravity
// Calculate initial velocities for perfect arc
velocityX = deltaX / time;
velocityY = deltaY / time - 0.5 * gravity * time - 1.5; // Enhanced downward bias
// Fine-tune for guaranteed swish - ensure ball enters hoop cleanly
var horizontalAdjustment = (targetX - startX) * 0.02; // Small correction factor
var verticalAdjustment = -1; // Additional downward bias for clean entry
velocityX += horizontalAdjustment;
velocityY += verticalAdjustment;
// Create perfect shot basketball
var ball = createBasketball(startX, startY, velocityX, velocityY);
ball.isPerfectShot = true;
// Ensure ball will score by setting special trajectory flag
ball.guaranteedSwish = true;
// Set additional properties to ensure scoring
ball.hasScored = false; // Ensure it can score
ball.isActive = true; // Ensure it's active
// Visual feedback for perfect shot removed
// Ball color tinting removed to prevent color changes
// Add vertical rotation animation
tween(ball, {
rotation: ball.rotation + Math.PI * 4
}, {
duration: 1500,
easing: tween.easeOut
});
} else {
// Regular shot with some randomness
velocityX = (Math.random() - 0.5) * 8;
velocityY = -16 - Math.random() * 8;
var ball = createBasketball(startX, startY, velocityX, velocityY);
// Add vertical rotation animation for regular shot
tween(ball, {
rotation: ball.rotation + Math.PI * 3
}, {
duration: 1200,
easing: tween.easeOut
});
}
lastShotTime = LK.ticks;
} else {
// Start charging shot
isChargingShot = true;
currentShotBar.startMoving();
swipeStartX = x;
swipeStartY = y;
swipeStartTime = LK.ticks;
}
};
game.up = function (x, y, obj) {
// Shot bar system handles shooting now, remove swipe-based shooting
};
game.update = function () {
// Only run gameplay logic when in playing state
if (gameState !== 'playing') {
return;
}
// Update basketballs
for (var i = basketballs.length - 1; i >= 0; i--) {
var ball = basketballs[i];
if (!ball.isActive) {
ball.destroy();
basketballs.splice(i, 1);
continue;
}
}
// Clean up orphaned reflections
for (var i = ballReflections.length - 1; i >= 0; i--) {
var reflection = ballReflections[i];
if (!reflection.parentBall || !reflection.parentBall.isActive) {
reflection.destroy();
ballReflections.splice(i, 1);
}
// Check for scoring
checkBasketScore(ball);
// Check collision with other basketballs
for (var j = i + 1; j < basketballs.length; j++) {
var otherBall = basketballs[j];
if (!otherBall.isActive) continue;
var dx = ball.x - otherBall.x;
var dy = ball.y - otherBall.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var minDistance = 120; // Combined radius of two basketballs
if (distance < minDistance && distance > 0) {
// Calculate collision normal
var normalX = dx / distance;
var normalY = dy / distance;
// Separate balls to prevent overlap
var overlap = minDistance - distance;
var separationX = normalX * overlap * 0.5;
var separationY = normalY * overlap * 0.5;
ball.x += separationX;
ball.y += separationY;
otherBall.x -= separationX;
otherBall.y -= separationY;
// Calculate relative velocity
var relativeVelX = ball.velocityX - otherBall.velocityX;
var relativeVelY = ball.velocityY - otherBall.velocityY;
// Calculate relative velocity along collision normal
var relativeSpeed = relativeVelX * normalX + relativeVelY * normalY;
// Only resolve if objects are moving towards each other
if (relativeSpeed > 0) continue;
// Calculate impulse scalar (assuming equal mass)
var impulse = -2 * relativeSpeed / 2;
var impulseX = impulse * normalX;
var impulseY = impulse * normalY;
// Apply impulse with bounce decay
var bounceDecay = 0.8;
ball.velocityX += impulseX * bounceDecay;
ball.velocityY += impulseY * bounceDecay;
otherBall.velocityX -= impulseX * bounceDecay;
otherBall.velocityY -= impulseY * bounceDecay;
// Play bounce sound
LK.getSound('bounce').play();
}
}
}
// Streak is only reset when player misses a shot (handled in Basketball class)
// No automatic reset when no balls are active
// Handle break countdown in swish mode
if (isInBreak && gameMode === 'swish') {
// Update break countdown every 60 frames (1 second)
if (LK.ticks % 60 === 0 && breakCountdown > 0) {
breakCountdown--;
if (breakCountdown > 0) {
updateBreakCountdown();
} else {
// Break is over
endBreakCountdown();
}
}
}
// Update timer (pause during break in swish mode)
if (!gameEnded && (!isInBreak || gameMode !== 'swish')) {
gameTimer--;
var newTimeLeft = Math.floor(gameTimer / 60);
if (newTimeLeft !== gameTimeLeft && newTimeLeft >= 0) {
gameTimeLeft = newTimeLeft;
// Update timer display using number assets
updateTimerDisplay(gameTimeLeft);
}
// In swish mode, trigger break every 60 seconds
if (gameMode === 'swish' && !isInBreak && gameTimeLeft <= 0) {
startBreakCountdown();
// Apply reduced timer (60 seconds minus cumulative reductions)
var adjustedTime = Math.max(10, 60 - swishModeTimerReduction); // Minimum 10 seconds
gameTimer = adjustedTime * 60; // Convert to frames at 60 FPS
gameTimeLeft = adjustedTime;
updateTimerDisplay(adjustedTime);
}
// Check if time is up
if (gameTimer <= 0 && !gameEnded) {
gameEnded = true;
updateTimerDisplay(0);
// Check and update best score for current mode
var currentScore = LK.getScore();
if (gameMode === '2player') {
// 2 Player battle mode time handling
if (twoPlayerState === 'player1') {
// Player 1's turn is over, record score and transition to player 2
player1Score = currentScore;
player1ScoreTxt.setText('P1: ' + player1Score);
// Start transition phase
twoPlayerState = 'transition';
transitionTimer = 3 * 60; // 3 second transition
if (twoPlayerRhythmMode) {
createTransitionOverlay('PLAYER 2 RHYTHM - BEAT ' + player1Score + ' POINTS!');
} else {
createTransitionOverlay('PLAYER 2 - BEAT ' + player1Score + ' POINTS!');
}
} else if (twoPlayerState === 'player2') {
// Player 2's turn is over, determine winner
player2Score = currentScore;
player2ScoreTxt.setText('P2: ' + player2Score);
// Determine winner and show results
if (player2Score > player1Score) {
if (twoPlayerRhythmMode) {
createWinnerOverlay('PLAYER 2 WINS RHYTHM BATTLE!', 'Score: ' + player2Score + ' vs ' + player1Score);
} else {
createWinnerOverlay('PLAYER 2 WINS!', 'Score: ' + player2Score + ' vs ' + player1Score);
}
} else if (player1Score > player2Score) {
if (twoPlayerRhythmMode) {
createWinnerOverlay('PLAYER 1 WINS RHYTHM BATTLE!', 'Score: ' + player1Score + ' vs ' + player2Score);
} else {
createWinnerOverlay('PLAYER 1 WINS!', 'Score: ' + player1Score + ' vs ' + player2Score);
}
} else {
if (twoPlayerRhythmMode) {
createWinnerOverlay('RHYTHM BATTLE TIE!', 'Both scored: ' + player1Score);
} else {
createWinnerOverlay('TIE GAME!', 'Both scored: ' + player1Score);
}
}
}
} else if (gameMode === 'ai_vs') {
// AI vs mode - determine winner
if (aiOpponent && currentScore > aiOpponent.score) {
// Player wins
cleanupUIElements();
LK.showYouWin();
} else if (aiOpponent && currentScore < aiOpponent.score) {
// AI wins
cleanupUIElements();
LK.showGameOver();
} else {
// Tie game
cleanupUIElements();
LK.showGameOver(); // Could be modified to show tie message
}
} else if (gameMode === 'rhythm') {
if (currentScore > rhythmBestScore) {
rhythmBestScore = currentScore;
storage.rhythmBestScore = rhythmBestScore;
bestScore = rhythmBestScore;
bestScoreTxt.setText('Best: ' + bestScore);
}
cleanupUIElements();
LK.showGameOver();
} else {
if (currentScore > swishBestScore) {
swishBestScore = currentScore;
storage.swishBestScore = swishBestScore;
bestScore = swishBestScore;
bestScoreTxt.setText('Best: ' + bestScore);
}
cleanupUIElements();
LK.showGameOver();
}
}
}
// Handle countdown timer for 2 player mode
if (gameMode === '2player' && countdownActive) {
if (LK.ticks % 60 === 0 && countdownTimer > 0) {
countdownTimer--;
if (countdownTimer > 0) {
updateCountdownDisplay();
} else {
// Countdown finished
updateCountdownDisplay(); // Show "GO!"
LK.setTimeout(function () {
hideCountdownOverlay();
gameEnded = false; // Resume game
}, 1000);
}
}
}
// Handle 2 player mode transitions
if (gameMode === '2player' && twoPlayerState === 'transition') {
transitionTimer--;
if (transitionTimer <= 0) {
// Transition is over, start player 2's turn
hideTransitionOverlay();
twoPlayerState = 'player2';
// Reset game state for player 2
LK.setScore(0);
scoreTxt.setText('Score: 0');
currentStreak = 0;
if (streakTxt) {
//{vi_new}
streakTxt.setText('Streak: 0');
} //{vi_end}
streakRewardsAwarded = [];
// Reset rhythm mode specific variables if in rhythm mode
if (twoPlayerRhythmMode) {
rhythmStreak = 0;
rhythmMultiplier = 1;
// Clear existing rhythm circles
for (var rc = 0; rc < rhythmCircles.length; rc++) {
if (rhythmCircles[rc]) {
rhythmCircles[rc].destroy();
}
}
rhythmCircles = [];
rhythmCircleSpawnTimer = 0;
// Keep music playing for player 2 in rhythm mode
musicStarted = true;
}
// Reset timer for player 2
if (twoPlayerRhythmMode) {
// 90 seconds for rhythm mode
twoPlayerTimer = 90 * 60;
twoPlayerTimeLeft = 90;
updateTimerDisplay(90);
} else {
// 90 seconds for swish mode
twoPlayerTimer = 90 * 60;
twoPlayerTimeLeft = 90;
updateTimerDisplay(90);
}
gameTimer = twoPlayerTimer;
gameTimeLeft = twoPlayerTimeLeft;
// Ensure timer variables are properly synchronized for 2 player rhythm mode
if (twoPlayerRhythmMode) {
gameTimer = 90 * 60; // 90 seconds at 60 FPS
gameTimeLeft = 90;
twoPlayerTimer = gameTimer;
twoPlayerTimeLeft = gameTimeLeft;
}
// Reset shot bar speed to default for player 2's turn (only if shot bars exist)
if (shotBar) {
shotBar.moveSpeed = 8;
}
if (shotBar2) {
shotBar2.moveSpeed = 8;
}
if (shotBar3) {
shotBar3.moveSpeed = 8;
}
// Update current player display
var modeText = twoPlayerRhythmMode ? 'RHYTHM' : 'SWISH';
currentPlayerTxt.setText('PLAYER 2 - ' + modeText + ' - BEAT ' + player1Score + '!');
currentPlayerTxt.tint = 0xFF4444; // Red for player 2
player2ScoreTxt.tint = 0xFF4444; // Highlight player 2 score
// Start countdown for player 2
createCountdownOverlay('PLAYER 2 GET READY!', 5);
gameEnded = true; // Pause game during countdown
}
}
// Handle shot bar speed increase every 30 seconds in 2 player mode (only if not rhythm mode)
if (gameMode === '2player' && !gameEnded && !twoPlayerRhythmMode) {
var elapsedSeconds = Math.floor(90 - gameTimeLeft);
var speedMultiplier = 1 + Math.floor(elapsedSeconds / 30) * 0.5; // Increase speed by 50% every 30 seconds
// Apply speed multiplier to all shot bars
if (shotBar && speedMultiplier > 1) {
shotBar.moveSpeed = 8 * speedMultiplier;
}
if (shotBar2 && speedMultiplier > 1) {
shotBar2.moveSpeed = 8 * speedMultiplier;
}
if (shotBar3 && speedMultiplier > 1) {
shotBar3.moveSpeed = 8 * speedMultiplier;
}
}
// Handle shot bar speed increase every 20 seconds in AI battle mode
if (gameMode === 'ai_vs' && !gameEnded) {
var aiElapsedSeconds = Math.floor(90 - gameTimeLeft);
var aiSpeedMultiplier = 1 + Math.floor(aiElapsedSeconds / 20) * 0.3; // Increase speed by 30% every 20 seconds
// Apply speed multiplier to all shot bars using tween for smooth transition
if (shotBar && aiSpeedMultiplier > shotBar.currentSpeedMultiplier) {
shotBar.currentSpeedMultiplier = aiSpeedMultiplier;
tween(shotBar, {
moveSpeed: 8 * aiSpeedMultiplier
}, {
duration: 500,
easing: tween.easeOut
});
}
if (shotBar2 && aiSpeedMultiplier > shotBar2.currentSpeedMultiplier) {
shotBar2.currentSpeedMultiplier = aiSpeedMultiplier;
tween(shotBar2, {
moveSpeed: 8 * aiSpeedMultiplier
}, {
duration: 500,
easing: tween.easeOut
});
}
if (shotBar3 && aiSpeedMultiplier > shotBar3.currentSpeedMultiplier) {
shotBar3.currentSpeedMultiplier = aiSpeedMultiplier;
tween(shotBar3, {
moveSpeed: 8 * aiSpeedMultiplier
}, {
duration: 500,
easing: tween.easeOut
});
}
}
// Rhythm mode beat system
if ((gameMode === 'rhythm' || gameMode === '2player' && twoPlayerRhythmMode) && beatIndicator) {
// Check for beat timing
if (LK.ticks - lastBeatTime >= beatInterval) {
lastBeatTime = LK.ticks;
// Animate beat indicator
tween(beatIndicator, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(beatIndicator, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 400,
easing: tween.easeIn
});
}
});
// Play beat sound
LK.getSound('1').play();
}
// Rhythm circle spawning and management
if ((gameMode === 'rhythm' || gameMode === '2player' && twoPlayerRhythmMode) && musicStarted) {
rhythmCircleSpawnTimer++;
if (rhythmCircleSpawnTimer >= rhythmCircleSpawnInterval) {
rhythmCircleSpawnTimer = 0;
spawnRhythmCircle();
}
// Update and cleanup rhythm circles
for (var i = rhythmCircles.length - 1; i >= 0; i--) {
var circle = rhythmCircles[i];
if (!circle.isActive) {
circle.destroy();
rhythmCircles.splice(i, 1);
} else {
// Check if circle has passed the tap zone without being tapped correctly
if (circle.targetShotBar && circle.hasPassed && circle.wasInGreenZone) {
// Circle was in green zone but wasn't tapped correctly - reset streak
currentStreak = 0;
if (streakTxt) {
//{we_new}
streakTxt.setText('Streak: ' + currentStreak);
} //{we_end}
streakRewardsAwarded = []; // Reset streak rewards
rhythmStreak = 0;
rhythmMultiplier = 1;
// Remove onfire effects from all nets when streak is reset and show nets
if (hoop && hoop.onfire) {
hoop.net.visible = true;
hoop.onfire.destroy();
hoop.onfire = null;
}
if (leftHoop && leftHoop.onfire) {
leftHoop.net.visible = true;
leftHoop.onfire.destroy();
leftHoop.onfire = null;
}
if (rightHoop && rightHoop.onfire) {
rightHoop.net.visible = true;
rightHoop.onfire.destroy();
rightHoop.onfire = null;
}
// Mark as inactive to prevent multiple resets
circle.isActive = false;
}
}
}
}
}
// Swish mode visualizer beat system at 125bpm
if (gameMode === 'swish' && volumeVisualizerBars.length > 0) {
//{lR_new1}
var swishBeatInterval = 29; // 29 frames = ~125 BPM at 60 FPS
var lastSwishBeatTime = lastSwishBeatTime || 0;
// Check for beat timing at 125bpm
if (LK.ticks - lastSwishBeatTime >= swishBeatInterval) {
lastSwishBeatTime = LK.ticks; //{lR_new2}
// Trigger volume visualizer pulse effect
for (var v = 0; v < volumeVisualizerBars.length; v++) {
var bar = volumeVisualizerBars[v];
var randomHeight = 0.5 + Math.random() * 2.0; // Random height between 0.5 and 2.5 for heavy response
bar.targetHeight = randomHeight;
// Cycle through neon colors
var neonColors = [0xFF0080, 0x00FF80, 0x8000FF, 0xFF8000, 0x0080FF, 0x80FF00, 0xFF0040, 0x40FF00];
var randomColor = neonColors[Math.floor(Math.random() * neonColors.length)];
// Animate bar to target height and change color
tween(bar, {
scaleY: randomHeight * 1.5,
tint: randomColor
}, {
//{lR_new3}
duration: 300,
//{lR_new4}
easing: tween.easeOut,
//{lR_new5}
onFinish: function () {
// Animate back to base height
tween(this, {
scaleY: 0.1 //{lR_new6}
}, {
//{lR_new7}
duration: 800,
//{lR_new8}
easing: tween.easeIn //{lR_new9}
}); //{lR_new10}
}.bind(bar)
}); //{lR_new11}
} //{lR_new12}
} //{lR_new13}
} //{lR_new14}
// Win condition removed - no score target
};
Make picture high definition
Remove everything but net
Remove basketball rings and backboards from picture
Shiny black rectangle frame. In-Game asset. 2d. High contrast. No shadows
Neon green basketball. In-Game asset. 2d. High contrast. No shadows
Change to black warriors uniform
Change to black warriors uniform
Padlock button that says *locked* Purchase for: $100. In-Game asset. 2d. High contrast. No shadows
Remove words "with basketball"
Number 1
Number 2
Number 3
Number 4
Number 5
Number 6
Number 7
Number 8
Make it say $HOP in big letters across the ball
Change it to say Rhythm
Make a shop backdrop with display shelves and framed areas to place items
Remove ball and put his hands down like he just caught a pass
Remove ball and fix hands
Record. In-Game asset. 2d. High contrast. No shadows
Make the net look like it's on fire
Make button teal and purple text
A UI button that says Ai Battle Mode in sports ESPN style fonts. In-Game asset. 2d. High contrast. No shadows
1
Sound effect
2
Sound effect
3
Sound effect
swish
Sound effect
bounce
Sound effect
backgroundMusic
Music
Makeaswish
Sound effect
Title
Music
Second
Music
Third
Music
Fourth
Music
Cash
Sound effect
Hypersonic
Music
swim
Music
Sunrise
Music
Onfire
Sound effect
Speedup
Sound effect
Fifth
Music