/**** * 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 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 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); // Check if score reached multiple of 50 points to reset timer var currentScore = LK.getScore(); var previousScore = currentScore - points; var currentFifties = Math.floor(currentScore / 50); var previousFifties = Math.floor(previousScore / 50); if (currentFifties > previousFifties) { if (gameMode === 'rhythm') { gameTimer = 15 * 60; // Reset to 15 seconds for rhythm mode at 60 FPS gameTimeLeft = 15; updateTimerDisplay(15); } else { // In swish mode, start 5-second break before speed increase if (!isInBreak) { startBreakCountdown(); } gameTimer = 60 * 60; // Reset to 60 seconds for swish mode at 60 FPS gameTimeLeft = 60; updateTimerDisplay(60); } } // 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(); } scoreTxt.setText('Score: ' + LK.getScore()); streakTxt.setText('Streak: ' + currentStreak); // 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 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); // Check if score reached multiple of 50 points to reset timer var currentScore = LK.getScore(); var previousScore = currentScore - points; var currentFifties = Math.floor(currentScore / 50); var previousFifties = Math.floor(previousScore / 50); if (currentFifties > previousFifties) { if (gameMode === 'rhythm') { gameTimer = 15 * 60; // Reset to 15 seconds for rhythm mode at 60 FPS gameTimeLeft = 15; updateTimerDisplay(15); } else { // In swish mode, start 5-second break before speed increase if (!isInBreak) { startBreakCountdown(); } gameTimer = 60 * 60; // Reset to 60 seconds for swish mode at 60 FPS gameTimeLeft = 60; updateTimerDisplay(60); } } // 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 scoreTxt.setText('Score: ' + LK.getScore()); streakTxt.setText('Streak: ' + currentStreak); // 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; streakTxt.setText('Streak: ' + currentStreak); 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 } // Increase speed every 50 points scored (but pause during break in swish mode) var currentSpeed = self.moveSpeed; var scoreMultiplier = Math.floor(LK.getScore() / 50); if (scoreMultiplier > 0 && (!isInBreak || gameMode !== 'swish')) { currentSpeed = self.moveSpeed * (1 + scoreMultiplier * 0.5); // 50% speed increase per 50 points } // 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 }]; // 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 = 400; 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 announcement text in middle of shop backdrop var announcementText = new Text2('NEW RHYTHM MODE SONGS\nCOMING SOON!', { size: 70, fill: 0xFFD700 }); announcementText.anchor.set(0.5, 0.5); announcementText.x = 1024; announcementText.y = 1366; // Middle of screen vertically announcementText.zIndex = 51; game.addChild(announcementText); // 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 announcement text reference for cleanup game.storeAnnouncementText = announcementText; // 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 announcement text if (game.storeAnnouncementText) { game.storeAnnouncementText.destroy(); game.storeAnnouncementText = null; } } // Title screen is now initialized - gameplay will be initialized when start is pressed; var gameState = 'title'; // 'title', 'playing', 'modeSelect' var gameMode = 'swish'; // 'swish' or 'rhythm' 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 // Global timer variables var timerNumbers = []; // Break system variables for swish mode var isInBreak = false; var breakCountdown = 0; var breakCountdownNumbers = []; var speedIncreaseDelayed = false; // 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; isInBreak = true; breakCountdown = 5; speedIncreaseDelayed = false; // 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 initializeTitleScreen() { // Stop all music when returning to title LK.stopMusic(); // 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 = 1800; swishButton.zIndex = 10; // Create Rhythm mode button rhythmButton = game.addChild(LK.getAsset('Rhythm', { anchorX: 0.5, anchorY: 0.5 })); rhythmButton.x = 1024; rhythmButton.y = 1150; rhythmButton.zIndex = 10; // Change game state to mode selection gameState = 'modeSelect'; // Animate buttons function animateModeButtons() { if (gameState !== 'modeSelect') return; tween(swishButton, { scaleX: 1.1, scaleY: 1.1 }, { duration: 600, easing: tween.easeInOut, onFinish: function onFinish() { if (gameState !== 'modeSelect') return; tween(swishButton, { scaleX: 1.0, scaleY: 1.0 }, { duration: 600, easing: tween.easeInOut, onFinish: animateModeButtons }); } }); // 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; } // 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 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 shotBar.startMoving(); shotBar2.startMoving(); shotBar3.startMoving(); // Initialize rhythm mode elements if in rhythm mode if (gameMode === 'rhythm') { // 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') return; // Randomly choose which shot bar to align with (all players available) var availableShotBars = [shotBar]; // Always include center if (shotBar2) { availableShotBars.push(shotBar2); } if (shotBar3) { availableShotBars.push(shotBar3); } 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') 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; } break; } } return { tapped: tappedCircle !== null, circle: tappedCircle, inGreenZone: tappedInGreenZone }; } function checkSimultaneousTap(x, y) { if (gameMode !== 'rhythm') 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 scoreTxt.setText('Score: ' + LK.getScore()); // 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++; streakTxt.setText('Streak: ' + currentStreak); // Play swish sound LK.getSound('swish').play(); // Make the player in that row shoot a perfect swish if (rhythmResult.circle && rhythmResult.circle.targetShotBar) { var targetBar = rhythmResult.circle.targetShotBar; var targetHoop = hoop; // Default to center hoop var activePlayer = 1; var startX = 1024; var startY = 2000; // 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; streakTxt.setText('Streak: ' + currentStreak); 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 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!'); // Play match sound when 3 backboards match the same color LK.getSound('Match').play(); // 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 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 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'); initializeGameplay(); return; } return; } // In rhythm mode, only process rhythm circle taps, disable shooting if (gameMode === 'rhythm') { checkSimultaneousTap(x, y); return; // Don't process shooting in rhythm mode } 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); } // 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 === 'rhythm') { if (currentScore > rhythmBestScore) { rhythmBestScore = currentScore; storage.rhythmBestScore = rhythmBestScore; bestScore = rhythmBestScore; bestScoreTxt.setText('Best: ' + bestScore); } } else { if (currentScore > swishBestScore) { swishBestScore = currentScore; storage.swishBestScore = swishBestScore; bestScore = swishBestScore; bestScoreTxt.setText('Best: ' + bestScore); } } LK.showGameOver(); } } // Rhythm mode beat system if (gameMode === 'rhythm' && 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') { 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; streakTxt.setText('Streak: ' + currentStreak); 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 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
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);
// Check if score reached multiple of 50 points to reset timer
var currentScore = LK.getScore();
var previousScore = currentScore - points;
var currentFifties = Math.floor(currentScore / 50);
var previousFifties = Math.floor(previousScore / 50);
if (currentFifties > previousFifties) {
if (gameMode === 'rhythm') {
gameTimer = 15 * 60; // Reset to 15 seconds for rhythm mode at 60 FPS
gameTimeLeft = 15;
updateTimerDisplay(15);
} else {
// In swish mode, start 5-second break before speed increase
if (!isInBreak) {
startBreakCountdown();
}
gameTimer = 60 * 60; // Reset to 60 seconds for swish mode at 60 FPS
gameTimeLeft = 60;
updateTimerDisplay(60);
}
}
// 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();
}
scoreTxt.setText('Score: ' + LK.getScore());
streakTxt.setText('Streak: ' + currentStreak);
// 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
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);
// Check if score reached multiple of 50 points to reset timer
var currentScore = LK.getScore();
var previousScore = currentScore - points;
var currentFifties = Math.floor(currentScore / 50);
var previousFifties = Math.floor(previousScore / 50);
if (currentFifties > previousFifties) {
if (gameMode === 'rhythm') {
gameTimer = 15 * 60; // Reset to 15 seconds for rhythm mode at 60 FPS
gameTimeLeft = 15;
updateTimerDisplay(15);
} else {
// In swish mode, start 5-second break before speed increase
if (!isInBreak) {
startBreakCountdown();
}
gameTimer = 60 * 60; // Reset to 60 seconds for swish mode at 60 FPS
gameTimeLeft = 60;
updateTimerDisplay(60);
}
}
// 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
scoreTxt.setText('Score: ' + LK.getScore());
streakTxt.setText('Streak: ' + currentStreak);
// 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;
streakTxt.setText('Streak: ' + currentStreak);
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
}
// Increase speed every 50 points scored (but pause during break in swish mode)
var currentSpeed = self.moveSpeed;
var scoreMultiplier = Math.floor(LK.getScore() / 50);
if (scoreMultiplier > 0 && (!isInBreak || gameMode !== 'swish')) {
currentSpeed = self.moveSpeed * (1 + scoreMultiplier * 0.5); // 50% speed increase per 50 points
}
// 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
}];
// 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 = 400;
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 announcement text in middle of shop backdrop
var announcementText = new Text2('NEW RHYTHM MODE SONGS\nCOMING SOON!', {
size: 70,
fill: 0xFFD700
});
announcementText.anchor.set(0.5, 0.5);
announcementText.x = 1024;
announcementText.y = 1366; // Middle of screen vertically
announcementText.zIndex = 51;
game.addChild(announcementText);
// 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 announcement text reference for cleanup
game.storeAnnouncementText = announcementText;
// 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 announcement text
if (game.storeAnnouncementText) {
game.storeAnnouncementText.destroy();
game.storeAnnouncementText = null;
}
}
// Title screen is now initialized - gameplay will be initialized when start is pressed;
var gameState = 'title'; // 'title', 'playing', 'modeSelect'
var gameMode = 'swish'; // 'swish' or 'rhythm'
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
// Global timer variables
var timerNumbers = [];
// Break system variables for swish mode
var isInBreak = false;
var breakCountdown = 0;
var breakCountdownNumbers = [];
var speedIncreaseDelayed = false;
// 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;
isInBreak = true;
breakCountdown = 5;
speedIncreaseDelayed = false;
// 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 initializeTitleScreen() {
// Stop all music when returning to title
LK.stopMusic();
// 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 = 1800;
swishButton.zIndex = 10;
// Create Rhythm mode button
rhythmButton = game.addChild(LK.getAsset('Rhythm', {
anchorX: 0.5,
anchorY: 0.5
}));
rhythmButton.x = 1024;
rhythmButton.y = 1150;
rhythmButton.zIndex = 10;
// Change game state to mode selection
gameState = 'modeSelect';
// Animate buttons
function animateModeButtons() {
if (gameState !== 'modeSelect') return;
tween(swishButton, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (gameState !== 'modeSelect') return;
tween(swishButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 600,
easing: tween.easeInOut,
onFinish: animateModeButtons
});
}
});
// 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;
}
// 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
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
shotBar.startMoving();
shotBar2.startMoving();
shotBar3.startMoving();
// Initialize rhythm mode elements if in rhythm mode
if (gameMode === 'rhythm') {
// 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') return;
// Randomly choose which shot bar to align with (all players available)
var availableShotBars = [shotBar]; // Always include center
if (shotBar2) {
availableShotBars.push(shotBar2);
}
if (shotBar3) {
availableShotBars.push(shotBar3);
}
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') 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;
}
break;
}
}
return {
tapped: tappedCircle !== null,
circle: tappedCircle,
inGreenZone: tappedInGreenZone
};
}
function checkSimultaneousTap(x, y) {
if (gameMode !== 'rhythm') 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
scoreTxt.setText('Score: ' + LK.getScore());
// 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++;
streakTxt.setText('Streak: ' + currentStreak);
// Play swish sound
LK.getSound('swish').play();
// Make the player in that row shoot a perfect swish
if (rhythmResult.circle && rhythmResult.circle.targetShotBar) {
var targetBar = rhythmResult.circle.targetShotBar;
var targetHoop = hoop; // Default to center hoop
var activePlayer = 1;
var startX = 1024;
var startY = 2000;
// 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;
streakTxt.setText('Streak: ' + currentStreak);
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 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!');
// Play match sound when 3 backboards match the same color
LK.getSound('Match').play();
// 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 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 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');
initializeGameplay();
return;
}
return;
}
// In rhythm mode, only process rhythm circle taps, disable shooting
if (gameMode === 'rhythm') {
checkSimultaneousTap(x, y);
return; // Don't process shooting in rhythm mode
}
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);
}
// 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 === 'rhythm') {
if (currentScore > rhythmBestScore) {
rhythmBestScore = currentScore;
storage.rhythmBestScore = rhythmBestScore;
bestScore = rhythmBestScore;
bestScoreTxt.setText('Best: ' + bestScore);
}
} else {
if (currentScore > swishBestScore) {
swishBestScore = currentScore;
storage.swishBestScore = swishBestScore;
bestScore = swishBestScore;
bestScoreTxt.setText('Best: ' + bestScore);
}
}
LK.showGameOver();
}
}
// Rhythm mode beat system
if (gameMode === 'rhythm' && 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') {
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;
streakTxt.setText('Streak: ' + currentStreak);
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