User prompt
Move how to play button right 50
User prompt
Make tapzone bigger in rhythm mode make green basketballs bigger and easier to tapnjn rhythm mode make falling rhythm circles bigger ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Make falling rhythm circles bigger
User prompt
Make bpm for title song 123bpm
User prompt
Make tapzone bigger in rhythm mode make green basketballs bigger and easier to tapnjn rhythm mode ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
When playing sunrise song change rhythm circles pattern to 136bpm
User prompt
After title song finishes in rhythm mode stop playing title song and play sunrise song
User prompt
When sunrise music starts playing change the rhythm circles falling bpm to 136bpm ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
In rhythm mode after 184033ms play stop playing title music and play sunrise music ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Move swish button up 300
User prompt
Ensure only one shot per rhythm circles tap
User prompt
In rhythm mode make tapzone green ball bigger ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Fix tapzones and debug rhythm mode
User prompt
Make rhythm circles white
User prompt
When a song is selected in the store make sure that the game remembers which song has been selected to play in rhythm mode. When it plays swim the rhythm circles must fall at 124bpm ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Fix this please
User prompt
When swim music is selected in shopbackdrop ensure it is swapped immediately with the hypersonic music in rhythm mode
User prompt
Add swim music pack to shopbackdrop so it can be selected to swap back from hypersonic or any other song packs that are added in the future
User prompt
Define swim music pack as the default song for rhythm mode
User prompt
Define swim asset and song as a song pack in music class
User prompt
Change title music name from title to swim
User prompt
Ensure hypersonic song pack isn't able to be selected until purchased for $500
User prompt
Make rhythm circles white
User prompt
When hypersonic song pack is purchased and selected swap the title music in rhythm mode with hypersonic music and change the rhythm circles dropping raye to 150bpm
User prompt
Move hypersonic song pack left 250
/**** * 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; 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 }); } }); // 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 }); } }); // 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 Music = Container.expand(function () { var self = Container.call(this); // Define song packs with their metadata self.songPacks = { 'hypersonic': { id: 'hypersonic', name: 'Hypersonic Pack', musicId: 'Hypersonic', unlocked: false, price: 1000.00 }, 'swim': { id: 'swim', name: 'Swim Pack', musicId: 'swim', unlocked: true, price: 0 }, 'fourth': { id: 'fourth', name: 'Fourth Pack', musicId: 'Fourth', unlocked: true, price: 0 }, 'second': { id: 'second', name: 'Second Pack', musicId: 'Second', unlocked: true, price: 0 }, 'third': { id: 'third', name: 'Third Pack', musicId: 'Third', unlocked: true, price: 0 } }; // Get song pack by id self.getSongPack = function (packId) { return self.songPacks[packId] || null; }; // Check if song pack is unlocked self.isUnlocked = function (packId) { var pack = self.getSongPack(packId); return pack ? pack.unlocked : false; }; // Unlock song pack self.unlockPack = function (packId) { var pack = self.getSongPack(packId); if (pack) { pack.unlocked = true; storage[packId + '_unlocked'] = true; } }; // Play music from song pack self.playPack = function (packId) { var pack = self.getSongPack(packId); if (pack && pack.unlocked) { LK.playMusic(pack.musicId); return true; } return false; }; // Load unlocked status from storage self.loadUnlockedPacks = function () { for (var packId in self.songPacks) { var pack = self.songPacks[packId]; pack.unlocked = storage[packId + '_unlocked'] || pack.unlocked; } }; // Initialize self.loadUnlockedPacks(); 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 = 0xFFFFFF; // White 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; // 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 } // 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 hypersonic song pack item var musicManager = new Music(); var hypersonicPack = musicManager.getSongPack('hypersonic'); if (hypersonicPack) { // Update price to $500.00 hypersonicPack.price = 500.00; // Create item image using Hypersonic asset var hypersonicImage = game.addChild(LK.getAsset('Hypersonic', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0 })); hypersonicImage.x = 324; // 574 - 250 hypersonicImage.y = 1766; // 1366 + 400 hypersonicImage.zIndex = 51; // Create item name text var hypersonicNameText = new Text2('Song Pack: Hypersonic', { size: 60, fill: 0xFFFFFF }); hypersonicNameText.anchor.set(0.5, 0.5); hypersonicNameText.x = 324; // 574 - 250 hypersonicNameText.y = 1500; // 1100 + 400 hypersonicNameText.zIndex = 51; game.addChild(hypersonicNameText); // Create price text var hypersonicPriceColor = currentMoney >= hypersonicPack.price ? 0x00FF00 : 0xFF0000; var hypersonicPriceText = new Text2('$' + hypersonicPack.price.toFixed(2), { size: 50, fill: hypersonicPriceColor }); hypersonicPriceText.anchor.set(0.5, 0.5); hypersonicPriceText.x = 324; // 574 - 250 hypersonicPriceText.y = 1900; // 1500 + 400 hypersonicPriceText.zIndex = 51; game.addChild(hypersonicPriceText); // Create status text var hypersonicStatusText = new Text2(hypersonicPack.unlocked ? 'TAP TO SELECT' : 'TAP TO BUY', { size: 40, fill: hypersonicPack.unlocked ? 0x00FF00 : 0xFFFFFF }); hypersonicStatusText.anchor.set(0.5, 0.5); hypersonicStatusText.x = 324; // 574 - 250 hypersonicStatusText.y = 1600; // 1200 + 400 hypersonicStatusText.zIndex = 51; game.addChild(hypersonicStatusText); // Store references for cleanup and purchase handling game.storeHypersonicImage = hypersonicImage; game.storeHypersonicNameText = hypersonicNameText; game.storeHypersonicPriceText = hypersonicPriceText; game.storeHypersonicStatusText = hypersonicStatusText; game.storeHypersonicPack = hypersonicPack; game.storeMusicManager = musicManager; } // Create swim song pack item var swimPack = musicManager.getSongPack('swim'); if (swimPack) { // Create item image using swim asset var swimImage = game.addChild(LK.getAsset('swim', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0 })); swimImage.x = 1724; // Right side position swimImage.y = 1766; // Same Y as hypersonic swimImage.zIndex = 51; // Create item name text var swimNameText = new Text2('Song Pack: Swim', { size: 60, fill: 0xFFFFFF }); swimNameText.anchor.set(0.5, 0.5); swimNameText.x = 1724; // Right side position swimNameText.y = 1500; // Same Y as hypersonic swimNameText.zIndex = 51; game.addChild(swimNameText); // Create status text (swim is always unlocked and free) var swimStatusText = new Text2('TAP TO SELECT', { size: 40, fill: 0x00FF00 }); swimStatusText.anchor.set(0.5, 0.5); swimStatusText.x = 1724; // Right side position swimStatusText.y = 1600; // Same Y as hypersonic swimStatusText.zIndex = 51; game.addChild(swimStatusText); // Store references for cleanup and selection handling game.storeSwimImage = swimImage; game.storeSwimNameText = swimNameText; game.storeSwimStatusText = swimStatusText; game.storeSwimPack = swimPack; } // 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); // Create announcement text for store interactions var announcementText = new Text2('', { size: 50, fill: 0xFFFFFF }); announcementText.anchor.set(0.5, 0.5); announcementText.x = 1024; announcementText.y = 2200; announcementText.zIndex = 51; game.addChild(announcementText); // 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 hypersonic song pack elements if (game.storeHypersonicImage) { game.storeHypersonicImage.destroy(); game.storeHypersonicImage = null; } if (game.storeHypersonicNameText) { game.storeHypersonicNameText.destroy(); game.storeHypersonicNameText = null; } if (game.storeHypersonicPriceText) { game.storeHypersonicPriceText.destroy(); game.storeHypersonicPriceText = null; } if (game.storeHypersonicStatusText) { game.storeHypersonicStatusText.destroy(); game.storeHypersonicStatusText = null; } game.storeHypersonicPack = null; game.storeMusicManager = null; // Clean up swim song pack elements if (game.storeSwimImage) { game.storeSwimImage.destroy(); game.storeSwimImage = null; } if (game.storeSwimNameText) { game.storeSwimNameText.destroy(); game.storeSwimNameText = null; } if (game.storeSwimStatusText) { game.storeSwimStatusText.destroy(); game.storeSwimStatusText = null; } game.storeSwimPack = 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; // 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 = 200; 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 = 2100; 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.0, scaleY: 1.0 })); 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; } // 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) continue; // 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 <= 180) { // Further increased circle tap radius for much better sensitivity tappedCircle = circle; // Check if circle is currently in the horizontal tap zone area var tolerance = 150; // 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) { // 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) { // 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 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!'); // 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 hypersonic song pack item if (game.storeHypersonicPack && game.storeHypersonicImage) { var hypersonicItemLeft = game.storeHypersonicImage.x - 200; var hypersonicItemRight = game.storeHypersonicImage.x + 200; var hypersonicItemTop = game.storeHypersonicImage.y - 200; var hypersonicItemBottom = game.storeHypersonicImage.y + 200; if (x >= hypersonicItemLeft && x <= hypersonicItemRight && y >= hypersonicItemTop && y <= hypersonicItemBottom) { // Only allow purchase or selection if pack is unlocked if (!game.storeHypersonicPack.unlocked) { // Check if player can afford the pack if (currentMoney >= game.storeHypersonicPack.price) { // Purchase hypersonic pack currentMoney -= game.storeHypersonicPack.price; storage.money = currentMoney; // Unlock pack game.storeMusicManager.unlockPack('hypersonic'); // Update money displays if (moneyTxt) { moneyTxt.setText('$' + currentMoney.toFixed(2)); } if (game.storeMoneyText) { game.storeMoneyText.setText('Money: $' + currentMoney.toFixed(2)); } // Update item status display if (game.storeHypersonicStatusText) { game.storeHypersonicStatusText.setText('SELECTED'); game.storeHypersonicStatusText.tint = 0x00FF00; } // Update item price text color to show it's owned if (game.storeHypersonicPriceText) { game.storeHypersonicPriceText.tint = 0x888888; // Gray out price when owned } // Store selection in storage for future rhythm mode sessions storage.selectedMusicPack = 'hypersonic'; // Update swim item status to not selected if (game.storeSwimStatusText) { game.storeSwimStatusText.setText('TAP TO SELECT'); game.storeSwimStatusText.tint = 0xFFFFFF; } // Play purchase and selection sound LK.getSound('Cash').play(); } else { // Not enough money - flash red briefly if (game.storeHypersonicPriceText) { var originalHypersonicTint = game.storeHypersonicPriceText.tint; game.storeHypersonicPriceText.tint = 0xFF0000; LK.setTimeout(function () { if (game.storeHypersonicPriceText) { game.storeHypersonicPriceText.tint = originalHypersonicTint; } }, 500); } } } else { // Item already owned - select it (play the music) game.storeMusicManager.playPack('hypersonic'); // Store selection in storage for future rhythm mode sessions storage.selectedMusicPack = 'hypersonic'; // Update status display if (game.storeHypersonicStatusText) { game.storeHypersonicStatusText.setText('SELECTED'); game.storeHypersonicStatusText.tint = 0x00FF00; } // Update swim item status to not selected if (game.storeSwimStatusText) { game.storeSwimStatusText.setText('TAP TO SELECT'); game.storeSwimStatusText.tint = 0xFFFFFF; } // Play selection sound LK.getSound('Cash').play(); } return; } } // Check if clicked on swim song pack item if (game.storeSwimPack && game.storeSwimImage) { var swimItemLeft = game.storeSwimImage.x - 200; var swimItemRight = game.storeSwimImage.x + 200; var swimItemTop = game.storeSwimImage.y - 200; var swimItemBottom = game.storeSwimImage.y + 200; if (x >= swimItemLeft && x <= swimItemRight && y >= swimItemTop && y <= swimItemBottom) { // Select swim pack (always unlocked) game.storeMusicManager.playPack('swim'); // Store selection in storage for future rhythm mode sessions storage.selectedMusicPack = 'swim'; // If currently in rhythm mode, immediately switch the music if (gameMode === 'rhythm' && gameState === 'playing') { LK.playMusic('swim'); } // Update status display if (game.storeSwimStatusText) { game.storeSwimStatusText.setText('SELECTED'); game.storeSwimStatusText.tint = 0x00FF00; } // Update hypersonic item status to not selected if (game.storeHypersonicStatusText) { game.storeHypersonicStatusText.setText(game.storeHypersonicPack.unlocked ? 'TAP TO SELECT' : 'TAP TO BUY'); game.storeHypersonicStatusText.tint = game.storeHypersonicPack.unlocked ? 0xFFFFFF : 0xFFFFFF; } // Play selection sound LK.getSound('Cash').play(); 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 - 350; // Expanded button width for better touch sensitivity var buttonRight = startButton.x + 350; var buttonTop = startButton.y - 350; // Expanded button height for better touch sensitivity var buttonBottom = startButton.y + 350; 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 - 250; var howToRight = game.howToPlayButton.x + 250; var howToTop = game.howToPlayButton.y - 250; var howToBottom = game.howToPlayButton.y + 250; 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 - 250; var shopRight = game.shopButton.x + 250; var shopTop = game.shopButton.y - 250; var shopBottom = game.shopButton.y + 250; 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 - 350; var swishRight = swishButton.x + 350; var swishTop = swishButton.y - 250; var swishBottom = swishButton.y + 250; if (x >= swishLeft && x <= swishRight && y >= swishTop && y <= swishBottom) { gameMode = 'swish'; LK.playMusic('backgroundMusic'); initializeGameplay(); return; } // Check Rhythm button var rhythmLeft = rhythmButton.x - 300; var rhythmRight = rhythmButton.x + 300; var rhythmTop = rhythmButton.y - 150; var rhythmBottom = rhythmButton.y + 150; if (x >= rhythmLeft && x <= rhythmRight && y >= rhythmTop && y <= rhythmBottom) { gameMode = 'rhythm'; // Check stored music pack preference and play appropriate music var musicManager = new Music(); var selectedPack = storage.selectedMusicPack || 'swim'; if (selectedPack === 'hypersonic' && musicManager.isUnlocked('hypersonic')) { LK.playMusic('Hypersonic'); } else { LK.playMusic('swim'); } 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 < 15) return; // Further reduced 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 much further var backboardTopY = 1300 - 1400; // Expanded tap area by 674 pixels above backboard for much better sensitivity 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 < 750) { // Expanded left area - Player2's area targetHoop = leftHoop; currentShotBar = shotBar2; activePlayer = 2; } else if (x > 1298) { // Expanded right area - 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 - use 150 BPM interval for hypersonic music var currentBeatInterval = beatInterval; // Check if hypersonic pack is unlocked and selected var musicManager = new Music(); if (musicManager.isUnlocked('hypersonic')) { currentBeatInterval = 24; // 150 BPM (24 frames = ~150 beats per minute at 60 FPS) } if (LK.ticks - lastBeatTime >= currentBeatInterval) { 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++; // Use 150 BPM spawn rate for hypersonic music var currentSpawnInterval = rhythmCircleSpawnInterval; var musicManager = new Music(); if (musicManager.isUnlocked('hypersonic')) { currentSpawnInterval = 24; // 150 BPM spawn rate } if (rhythmCircleSpawnTimer >= currentSpawnInterval) { 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; // Mark as inactive to prevent multiple resets circle.isActive = false; } } } } } // Win condition removed - no score target };
===================================================================
--- original.js
+++ change.js
@@ -2659,8 +2659,12 @@
// Select swim pack (always unlocked)
game.storeMusicManager.playPack('swim');
// Store selection in storage for future rhythm mode sessions
storage.selectedMusicPack = 'swim';
+ // If currently in rhythm mode, immediately switch the music
+ if (gameMode === 'rhythm' && gameState === 'playing') {
+ LK.playMusic('swim');
+ }
// Update status display
if (game.storeSwimStatusText) {
game.storeSwimStatusText.setText('SELECTED');
game.storeSwimStatusText.tint = 0x00FF00;
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