/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Customer = Container.expand(function () { var self = Container.call(this); var customerSprite = self.attachAsset('customer', { anchorX: 0.5, anchorY: 1.0 }); self.walkSpeed = 2; self.targetX = 0; self.targetY = 0; self.hasReachedStand = false; self.hasPurchased = false; self.isInQueue = false; self.queueIndex = -1; // Index in the customerQueue array self.orderStartTime = 0; self.orderDuration = 5000; // 5 seconds base order time // Create loading circle for order progress self.loadingCircle = new Container(); var loadingBg = LK.getAsset('coin', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); loadingBg.tint = 0x333333; self.loadingCircle.addChild(loadingBg); var loadingFill = LK.getAsset('coin', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.6, scaleY: 0.6 }); loadingFill.tint = 0x00FF00; loadingFill.alpha = 0; self.loadingCircle.addChild(loadingFill); self.loadingCircle.x = 0; self.loadingCircle.y = -160; self.loadingCircle.alpha = 0; self.addChild(self.loadingCircle); self.loadingFill = loadingFill; // Initialize idle animation properties self.idleTimer = 0; self.baseY = 0; self.isIdle = false; self.update = function () { // Only move if we have valid target coordinates var distanceX = Math.abs(self.x - self.targetX); var distanceY = Math.abs(self.y - self.targetY); if (distanceX > 5 || distanceY > 5) { // Moving - stop idle animation self.isIdle = false; // Move towards target if (self.x < self.targetX) { self.x += self.walkSpeed * gameSpeedMultiplier; } else if (self.x > self.targetX) { self.x -= self.walkSpeed * gameSpeedMultiplier; } if (self.y < self.targetY) { self.y += self.walkSpeed * gameSpeedMultiplier; } else if (self.y > self.targetY) { self.y -= self.walkSpeed * gameSpeedMultiplier; } } else { // Reached target position if (!self.isInQueue && !self.hasPurchased) { // Join the queue joinQueue(self); } else if (self.isInQueue && self.queueIndex === 0 && !self.hasReachedStand && !self.hasPurchased) { // First in queue, ready for manual sale self.hasReachedStand = true; } // Start idle animation when stationary if (!self.isIdle) { self.isIdle = true; self.baseY = self.y; self.idleTimer = 0; } // Gentle idle bobbing animation self.idleTimer += 0.05; self.y = self.baseY + Math.sin(self.idleTimer) * 3; } }; self.leaveStand = function () { var exitX = self.x < 1024 ? -100 : 2148; tween(self, { x: exitX }, { duration: 2000, onFinish: function onFinish() { self.destroy(); var index = customers.indexOf(self); if (index > -1) { customers.splice(index, 1); } } }); }; return self; }); var LemonadeGlass = Container.expand(function () { var self = Container.call(this); var glass = self.attachAsset('lemonadeGlass', { anchorX: 0.5, anchorY: 0.5 }); self.moveToCustomer = function (targetX, targetY, callback) { tween(self, { x: targetX, y: targetY }, { duration: 1000, easing: tween.easeOut, onFinish: callback }); }; return self; }); var LemonadeStand = Container.expand(function () { var self = Container.call(this); // Always start with normal lemonade stand initially var standBase = self.attachAsset('lemonadeStand', { anchorX: 0.5, anchorY: 1.0 }); self.standBase = standBase; // Store reference for upgrades // Add menu table var menuTable = self.attachAsset('menuTable', { anchorX: 0.5, anchorY: 0.5, x: 150, y: -50 }); // Add price sign on menu table with bubble font style var signText = new Text2('$1.00', { size: 28, fill: 0x00FF00, font: "'Comic Sans MS', 'Chalkboard SE', cursive", dropShadow: true, dropShadowColor: 0x000000, dropShadowBlur: 4, dropShadowDistance: 2 }); signText.anchor.set(0.5, 0.5); signText.x = 150; signText.y = -50; self.addChild(signText); self.updateSign = function (price) { signText.setText('$' + price.toFixed(2)); }; self.updateStandAsset = function () { // Remove old stand asset if (self.standBase) { self.removeChild(self.standBase); } // Add new upgraded stand asset var assetName = standLevel > 1 ? 'upgradedstand' : 'lemonadeStand'; self.standBase = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 1.0, x: standLevel > 1 ? -20 : 0, y: standLevel > 1 ? -20 : 0 }); // Hide/show lemonade glass on stand based on upgrade level for (var l = 0; l < lemonadeGlasses.length; l++) { if (lemonadeGlasses[l] && lemonadeGlasses[l].parent === game) { // Check if this is the stand lemonade glass (positioned on stand) if (Math.abs(lemonadeGlasses[l].x - lemonadeStand.x) < 50 && Math.abs(lemonadeGlasses[l].y - (lemonadeStand.y - 160)) < 50) { lemonadeGlasses[l].alpha = standLevel > 1 ? 0 : 1; } } } // Ensure menu table and sign stay on top of upgraded stand if (standLevel > 1) { self.addChild(menuTable); self.addChild(signText); // Bring price sign to front } }; return self; }); var UpgradeButton = Container.expand(function (upgradeData) { var self = Container.call(this); var button = self.attachAsset('upgradeButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.4, scaleY: 1.4 }); var titleText = new Text2(upgradeData.title, { size: 32, fill: 0xFFFFFF, font: "'Comic Sans MS', 'Chalkboard SE', cursive" }); titleText.anchor.set(0.5, 0.3); titleText.x = 0; titleText.y = -15; self.addChild(titleText); var costText = new Text2('$' + upgradeData.cost, { size: 72, fill: 0xFF8C00, font: "'Comic Sans MS', 'Chalkboard SE', cursive", dropShadow: true, dropShadowColor: 0x000000, dropShadowBlur: 3, dropShadowDistance: 2 }); costText.anchor.set(0.5, 0.0); costText.x = 0; costText.y = 60; self.addChild(costText); self.upgradeData = upgradeData; self.updateCost = function () { costText.setText('$' + self.upgradeData.cost.toFixed(0)); // Update price color based on affordability if (money >= self.upgradeData.cost) { costText.tint = 0x00FF00; // Green when affordable } else { costText.tint = 0xFF0000; // Red when unaffordable } // Remove tinting to show original button image colors button.tint = 0xFFFFFF; // Reset to original colors }; self.down = function (x, y, obj) { if (money >= self.upgradeData.cost) { money -= self.upgradeData.cost; self.upgradeData.apply(); self.upgradeData.cost *= 1.5; self.updateCost(); if (!isSoundMuted) { LK.getSound('upgrade').play(); } // No animation - keep same size } else { // Play button click sound even when can't afford if (!isSoundMuted) { LK.getSound('buttonClick').play(); } } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ // Game variables var money = 0; var lemonadeCount = 0; // No longer stackable var salesCount = 0; var productionRate = storage.productionRate || 2000; // milliseconds per lemonade, starting at 2 seconds var currentPrice = 1.00; var customerSpawnRate = storage.customerSpawnRate || 4000; var standLevel = storage.standLevel || 1; var customerCapacity = storage.customerCapacity || 3; // Starting customer capacity is 3 // Mute state variables var isMusicMuted = storage.isMusicMuted || false; var isSoundMuted = storage.isSoundMuted || false; // Game arrays var customers = []; var lemonadeGlasses = []; // Speed boost variables var gameSpeedMultiplier = 1.0; var boostEndTime = 0; // Queue system variables var queuePositions = [{ x: 924, y: 1710 }, // Front of queue (closest to stand) { x: 824, y: 1710 }, // Second position { x: 724, y: 1710 }, // Third position { x: 624, y: 1710 }, // Fourth position { x: 524, y: 1710 } // Fifth position ]; var customerQueue = []; // Ordered array of customers in queue var maxQueueSize = customerCapacity; // Maximum customers allowed in queue based on capacity // Production tracking for customers per minute var lastSaleTime = Date.now(); var salesHistory = []; var currentProductionRate = 0; // Create background environment // Sky background game.setBackgroundColor(0x87CEEB); // Add clouds with random positions var clouds = []; for (var c = 0; c < 6; c++) { var cloud = LK.getAsset('cloud', { anchorX: 0.5, anchorY: 0.5 }); cloud.x = Math.random() * 2500 - 200; cloud.y = 250 + Math.random() * 300; clouds.push(cloud); game.addChild(cloud); } // Add sun to sky var sun = LK.getAsset('sun', { anchorX: 0.5, anchorY: 0.5 }); sun.x = 1700; sun.y = 300; game.addChild(sun); // Start cloud animations with 5x slower speed function animateCloud(cloud) { var randomSpeed = (15000 + Math.random() * 10000) * 5; // 5x slower tween(cloud, { x: cloud.x + 2500 }, { duration: randomSpeed, easing: tween.linear, onFinish: function onFinish() { cloud.x = -250; cloud.y = 250 + Math.random() * 300; animateCloud(cloud); } }); } for (var c = 0; c < clouds.length; c++) { animateCloud(clouds[c]); } // Add houses in background var house1 = LK.getAsset('house', { anchorX: 0.5, anchorY: 1.0 }); house1.x = 200; house1.y = 1450; game.addChild(house1); var house2 = LK.getAsset('house', { anchorX: 0.5, anchorY: 1.0 }); house2.x = 600; house2.y = 1450; game.addChild(house2); var house3 = LK.getAsset('house', { anchorX: 0.5, anchorY: 1.0 }); house3.x = 1400; house3.y = 1450; game.addChild(house3); var house4 = LK.getAsset('house', { anchorX: 0.5, anchorY: 1.0 }); house4.x = 1800; house4.y = 1450; game.addChild(house4); // Add grass pattern var grassPattern = []; for (var g = 0; g < 5; g++) { var garden = LK.getAsset('garden', { anchorX: 0.0, anchorY: 1.0 }); garden.x = g * 512; garden.y = 1600; grassPattern.push(garden); game.addChild(garden); } // Add fences for each house (beginning and end with gaps) // House 1 fences (x: 200) var fence1a = LK.getAsset('fence', { anchorX: 0.5, anchorY: 1.0 }); fence1a.x = 50; fence1a.y = 1580; game.addChild(fence1a); var fence1b = LK.getAsset('fence', { anchorX: 0.5, anchorY: 1.0 }); fence1b.x = 350; fence1b.y = 1580; game.addChild(fence1b); // House 2 fences (x: 600) var fence2a = LK.getAsset('fence', { anchorX: 0.5, anchorY: 1.0 }); fence2a.x = 450; fence2a.y = 1580; game.addChild(fence2a); var fence2b = LK.getAsset('fence', { anchorX: 0.5, anchorY: 1.0 }); fence2b.x = 750; fence2b.y = 1580; game.addChild(fence2b); // House 3 fences (x: 1400) var fence3a = LK.getAsset('fence', { anchorX: 0.5, anchorY: 1.0 }); fence3a.x = 1250; fence3a.y = 1580; game.addChild(fence3a); var fence3b = LK.getAsset('fence', { anchorX: 0.5, anchorY: 1.0 }); fence3b.x = 1550; fence3b.y = 1580; game.addChild(fence3b); // House 4 fences (x: 1800) var fence4a = LK.getAsset('fence', { anchorX: 0.5, anchorY: 1.0 }); fence4a.x = 1650; fence4a.y = 1580; game.addChild(fence4a); var fence4b = LK.getAsset('fence', { anchorX: 0.5, anchorY: 1.0 }); fence4b.x = 1950; fence4b.y = 1580; game.addChild(fence4b); // Add beige background section covering entire bottom area var brownBackground = LK.getAsset('bottompart', { anchorX: 0.5, anchorY: 0.0 }); brownBackground.tint = 0xF5F5DC; // Beige color brownBackground.x = 1024; brownBackground.y = 2000; // Start below the asphalt road to keep it visible // Add asphalt road var asphalt = LK.getAsset('asphalt', { anchorX: 0.5, anchorY: 1.0 }); asphalt.x = 1024; asphalt.y = 2000; game.addChild(asphalt); // Add sidewalk pattern var sidewalkPattern = []; for (var s = 0; s < 5; s++) { var sidewalk = LK.getAsset('sidewalk', { anchorX: 0.0, anchorY: 1.0 }); sidewalk.x = s * 555; sidewalk.y = 1710; sidewalkPattern.push(sidewalk); game.addChild(sidewalk); } // Create lemonade stand var lemonadeStand = game.addChild(new LemonadeStand()); lemonadeStand.x = 1024; lemonadeStand.y = 1700; // Add manual selling variables var isProcessingSale = false; var saleProgressCircle = null; // Add click handler for manual selling lemonadeStand.down = function (x, y, obj) { // Only process if there's a customer at front of queue and we're not already processing if (customerQueue.length > 0 && !isProcessingSale && lemonadeCount > 0) { var frontCustomer = customerQueue[0]; if (frontCustomer && frontCustomer.hasReachedStand && !frontCustomer.hasPurchased) { startManualSale(frontCustomer); } else { // Play button click sound when clicking but can't sell if (!isSoundMuted) { LK.getSound('buttonClick').play(); } } } else { // Play button click sound when clicking but can't sell if (!isSoundMuted) { LK.getSound('buttonClick').play(); } } }; // Create HUD elements // Create modern HUD container with background var hudContainer = new Container(); hudContainer.x = 120; hudContainer.y = 40; LK.gui.topLeft.addChild(hudContainer); // HUD background panel removed to clean up top corner appearance var moneyText = new Text2('💰 $' + money.toFixed(2), { size: 52, fill: 0xFFD700, font: "'Comic Sans MS', 'Chalkboard SE', cursive", stroke: 0x000000, strokeThickness: 4 }); moneyText.anchor.set(0, 0); moneyText.x = 20; moneyText.y = 15; hudContainer.addChild(moneyText); var lemonadeText = new Text2('🏆 ' + salesCount + ' Sales', { size: 52, fill: 0x00FF88, font: "'Comic Sans MS', 'Chalkboard SE', cursive", stroke: 0x000000, strokeThickness: 4 }); lemonadeText.anchor.set(0, 0); lemonadeText.x = 20; lemonadeText.y = 80; hudContainer.addChild(lemonadeText); var customerRateText = new Text2('⚡ 0/min served', { size: 42, fill: 0xFF6B35, font: "'Comic Sans MS', 'Chalkboard SE', cursive", stroke: 0x000000, strokeThickness: 3 }); customerRateText.anchor.set(0, 0); customerRateText.x = 20; customerRateText.y = 145; hudContainer.addChild(customerRateText); // Create upgrade menu var upgradeMenu = new Container(); upgradeMenu.x = 1024; upgradeMenu.y = 2400; // Move up 100 pixels from 2500 to 2400 game.addChild(upgradeMenu); // Upgrade definitions var upgrades = [{ title: "Faster Production", cost: 5, apply: function apply() { productionRate *= 0.8; // Make production 20% faster each upgrade updateHUD(); } }, { title: "Better Recipe", cost: 15, apply: function apply() { currentPrice += 0.3; lemonadeStand.updateSign(currentPrice); } }, { title: "Marketing", cost: 30, apply: function apply() { customerCapacity += 1; // Increase customer capacity by 1 maxQueueSize = customerCapacity; // Update max queue size customerSpawnRate *= 0.75; } }, { title: "Stand Upgrade", cost: 1000, apply: function apply() { standLevel++; // Double the profit (price) and production speed currentPrice *= 2; productionRate *= 0.5; // Half the time = double the speed // Update stand visual asset lemonadeStand.updateStandAsset(); lemonadeStand.updateSign(currentPrice); // Ensure customers stay on top layer after stand upgrade for (var c = 0; c < customers.length; c++) { if (customers[c]) { game.addChild(customers[c]); // Brings customers to front } } } }]; // Create upgrade buttons var upgradeButtons = []; for (var i = 0; i < upgrades.length; i++) { var upgradeButton = new UpgradeButton(upgrades[i]); upgradeButton.x = (i - 1.5) * 425; // Button width (300 * 1.4 = 420) + 5 pixel padding = 425 upgradeButton.y = 0; // Keep buttons aligned horizontally upgradeMenu.addChild(upgradeButton); upgradeButtons.push(upgradeButton); } // Timers var lastProductionTime = Date.now(); var lastCustomerTime = Date.now(); // We'll handle timing manually in update loop for speed boost // Auto-save timer var saveTimer = LK.setInterval(function () { saveGame(); }, 5000); function updateHUD() { moneyText.setText('💰 $' + money.toFixed(2)); lemonadeText.setText('🏆 ' + salesCount + ' Sales'); customerRateText.setText('⚡ ' + calculateCustomerRate() + '/min served'); // Update upgrade buttons for (var i = 0; i < upgradeMenu.children.length; i++) { upgradeMenu.children[i].updateCost(); } } function joinQueue(customer) { // Check if customer is already in queue to prevent duplicates if (customerQueue.indexOf(customer) !== -1) { return; } // Only add if there's an available position and under max limit if (customerQueue.length < maxQueueSize && customerQueue.length < queuePositions.length) { customerQueue.push(customer); customer.isInQueue = true; customer.queueIndex = customerQueue.length - 1; // Assign specific position immediately var positionIndex = customerQueue.length - 1; customer.targetX = queuePositions[positionIndex].x; customer.targetY = queuePositions[positionIndex].y; } } function leaveQueue(customer) { var index = customerQueue.indexOf(customer); if (index !== -1) { customerQueue.splice(index, 1); customer.isInQueue = false; customer.queueIndex = -1; // Update queue positions for remaining customers updateQueuePositions(); } } function updateQueuePositions() { // Reassign positions based on current queue order for (var i = 0; i < customerQueue.length; i++) { var customer = customerQueue[i]; customer.queueIndex = i; if (i < queuePositions.length) { customer.targetX = queuePositions[i].x; customer.targetY = queuePositions[i].y; } } } function calculateCustomerRate() { if (salesHistory.length < 2) { return 0; } var timeSpan = salesHistory[salesHistory.length - 1] - salesHistory[0]; var salesInSpan = salesHistory.length; if (timeSpan > 0) { return (salesInSpan / (timeSpan / 60000)).toFixed(1); } return 0; } function spawnCustomer() { // Don't spawn if we already have the maximum number of customers on screen if (customers.length >= customerCapacity) { return; } // Only spawn one customer at a time var customer = new Customer(); var startSide = Math.random() < 0.5 ? 0 : 1; if (startSide === 0) { customer.x = -100; customer.targetX = queuePositions[0].x - 100; } else { customer.x = 2148; customer.targetX = queuePositions[0].x + 100; } customer.y = 1710; customer.targetY = 1710; customers.push(customer); game.addChild(customer); } function startManualSale(customer) { isProcessingSale = true; // Create progress circle saleProgressCircle = new Container(); // Background circle var progressBg = LK.getAsset('coin', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.0, scaleY: 2.0 }); progressBg.tint = 0x333333; progressBg.alpha = 0.8; saleProgressCircle.addChild(progressBg); // Progress fill circle var progressFill = LK.getAsset('coin', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, scaleY: 0.1 }); progressFill.tint = 0x00FF00; saleProgressCircle.addChild(progressFill); // Position above the stand saleProgressCircle.x = lemonadeStand.x; saleProgressCircle.y = lemonadeStand.y - 300; game.addChild(saleProgressCircle); // Animate the progress fill over 2 seconds tween(progressFill, { scaleX: 1.8, scaleY: 1.8 }, { duration: 2000, easing: tween.linear, onFinish: function onFinish() { completeManualSale(customer); } }); } function completeManualSale(customer) { // Complete the customer's purchase if (customer && !customer.hasPurchased && customer.queueIndex === 0) { customer.hasPurchased = true; customer.hasReachedStand = false; lemonadeCount = 0; // Used up the ready lemonade salesCount++; money += currentPrice; // Track sale time for production rate calculation salesHistory.push(Date.now()); if (salesHistory.length > 10) { salesHistory.shift(); } if (!isSoundMuted) { LK.getSound('cashRegister').play(); } // Create lemonade glass for customer var lemonadeGlass = new LemonadeGlass(); lemonadeGlass.x = lemonadeStand.x; lemonadeGlass.y = lemonadeStand.y - 50; game.addChild(lemonadeGlass); lemonadeGlasses.push(lemonadeGlass); // Move lemonade to customer's hand position lemonadeGlass.moveToCustomer(customer.x, customer.y - 80, function () { // Keep lemonade with customer while they leave customer.addChild(lemonadeGlass); lemonadeGlass.x = 20; // Offset from customer center lemonadeGlass.y = -80; // Above customer }); // Show coin animation var coin = new Container(); var coinSprite = coin.attachAsset('coin', { anchorX: 0.5, anchorY: 0.5 }); coin.x = customer.x; coin.y = customer.y - 100; game.addChild(coin); tween(coin, { y: coin.y - 100, alpha: 0 }, { duration: 1500, onFinish: function onFinish() { coin.destroy(); } }); // Remove from queue and advance other customers leaveQueue(customer); // Customer leaves after purchase LK.setTimeout(function () { customer.leaveStand(); }, 1000); } // Clean up progress circle if (saleProgressCircle) { saleProgressCircle.destroy(); saleProgressCircle = null; } isProcessingSale = false; } function saveGame() { storage.money = money; storage.salesCount = salesCount; storage.productionRate = productionRate; storage.currentPrice = currentPrice; storage.customerSpawnRate = customerSpawnRate; storage.standLevel = standLevel; storage.customerCapacity = customerCapacity; storage.isMusicMuted = isMusicMuted; storage.isSoundMuted = isSoundMuted; } // Game update loop game.update = function () { // Check if speed boost should end if (Date.now() > boostEndTime) { gameSpeedMultiplier = 1.0; } var currentTime = Date.now(); // Handle production timer with speed boost - always have lemonade ready if (currentTime - lastProductionTime >= productionRate / gameSpeedMultiplier) { lemonadeCount = 1; // Always have one ready lastProductionTime = currentTime; } // Handle customer spawn timer with speed boost if (currentTime - lastCustomerTime >= customerSpawnRate / gameSpeedMultiplier) { spawnCustomer(); lastCustomerTime = currentTime; } // Update customers with speed boost for (var i = customers.length - 1; i >= 0; i--) { if (customers[i] && customers[i].update) { // Apply speed boost to customer walk speed customers[i].walkSpeed = 2 * gameSpeedMultiplier; customers[i].update(); } } // Update HUD every 30 frames (0.5 seconds) if (LK.ticks % 30 === 0) { updateHUD(); } // Ensure lemonade glasses are always on top layer for visibility for (var l = 0; l < lemonadeGlasses.length; l++) { if (lemonadeGlasses[l] && lemonadeGlasses[l].parent === game) { game.addChild(lemonadeGlasses[l]); // Brings to front } } // Ensure customers are always on top layer for visibility for (var c = 0; c < customers.length; c++) { if (customers[c] && customers[c].parent === game) { game.addChild(customers[c]); // Brings customers to front } } // Ensure lemonade stand price sign stays on absolute top layer if (lemonadeStand && lemonadeStand.children) { for (var s = 0; s < lemonadeStand.children.length; s++) { if (lemonadeStand.children[s] instanceof Text2) { lemonadeStand.addChild(lemonadeStand.children[s]); // Bring price text to front break; } } } }; // Add brown background to front layer to ensure it covers all blue areas game.addChild(brownBackground); // Fences are already added earlier and should stay behind upgradedstand // No need to bring them to front layer // Bring upgrade menu to front layer game.addChild(upgradeMenu); // Add one lemonade glass on lemonade stand on top layer var standLemonadeGlass = new LemonadeGlass(); standLemonadeGlass.x = lemonadeStand.x; standLemonadeGlass.y = lemonadeStand.y - 160; // Position on top of stand, moved 10 pixels up game.addChild(standLemonadeGlass); lemonadeGlasses.push(standLemonadeGlass); // Initial setup lemonadeStand.updateSign(currentPrice); updateHUD(); // Create music mute button var musicMuteButton = LK.getAsset('musicMuteButton', { anchorX: 0.5, anchorY: 0.5 }); musicMuteButton.x = -100; musicMuteButton.y = 70; LK.gui.topRight.addChild(musicMuteButton); // Add music note symbol var musicNoteText = new Text2('♪', { size: 36, fill: 0xFFFFFF, font: "'Arial', sans-serif" }); musicNoteText.anchor.set(0.5, 0.5); musicNoteText.x = -100; musicNoteText.y = 70; LK.gui.topRight.addChild(musicNoteText); // Update music button appearance based on mute state function updateMusicButton() { if (isMusicMuted) { musicMuteButton.alpha = 0.5; musicNoteText.alpha = 0.5; } else { musicMuteButton.alpha = 1.0; musicNoteText.alpha = 1.0; } } // Music mute button click handler musicMuteButton.down = function (x, y, obj) { isMusicMuted = !isMusicMuted; updateMusicButton(); if (isMusicMuted) { LK.stopMusic(); } else { LK.playMusic('backgroundMusic', { volume: 0.3 }); } // Save mute state storage.isMusicMuted = isMusicMuted; }; // Create sound mute button var soundMuteButton = LK.getAsset('soundMuteButton', { anchorX: 0.5, anchorY: 0.5 }); soundMuteButton.x = -100; soundMuteButton.y = 140; LK.gui.topRight.addChild(soundMuteButton); // Add sound symbol var soundText = new Text2('♫', { size: 36, fill: 0xFFFFFF, font: "'Arial', sans-serif" }); soundText.anchor.set(0.5, 0.5); soundText.x = -100; soundText.y = 140; LK.gui.topRight.addChild(soundText); // Update sound button appearance based on mute state function updateSoundButton() { if (isSoundMuted) { soundMuteButton.alpha = 0.5; soundText.alpha = 0.5; } else { soundMuteButton.alpha = 1.0; soundText.alpha = 1.0; } } // Sound mute button click handler soundMuteButton.down = function (x, y, obj) { isSoundMuted = !isSoundMuted; updateSoundButton(); // Save mute state storage.isSoundMuted = isSoundMuted; }; // Initialize button states updateMusicButton(); updateSoundButton(); // Start background music if (!isMusicMuted) { LK.playMusic('backgroundMusic', { volume: 0.3 }); }
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Customer = Container.expand(function () {
var self = Container.call(this);
var customerSprite = self.attachAsset('customer', {
anchorX: 0.5,
anchorY: 1.0
});
self.walkSpeed = 2;
self.targetX = 0;
self.targetY = 0;
self.hasReachedStand = false;
self.hasPurchased = false;
self.isInQueue = false;
self.queueIndex = -1; // Index in the customerQueue array
self.orderStartTime = 0;
self.orderDuration = 5000; // 5 seconds base order time
// Create loading circle for order progress
self.loadingCircle = new Container();
var loadingBg = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
loadingBg.tint = 0x333333;
self.loadingCircle.addChild(loadingBg);
var loadingFill = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6
});
loadingFill.tint = 0x00FF00;
loadingFill.alpha = 0;
self.loadingCircle.addChild(loadingFill);
self.loadingCircle.x = 0;
self.loadingCircle.y = -160;
self.loadingCircle.alpha = 0;
self.addChild(self.loadingCircle);
self.loadingFill = loadingFill;
// Initialize idle animation properties
self.idleTimer = 0;
self.baseY = 0;
self.isIdle = false;
self.update = function () {
// Only move if we have valid target coordinates
var distanceX = Math.abs(self.x - self.targetX);
var distanceY = Math.abs(self.y - self.targetY);
if (distanceX > 5 || distanceY > 5) {
// Moving - stop idle animation
self.isIdle = false;
// Move towards target
if (self.x < self.targetX) {
self.x += self.walkSpeed * gameSpeedMultiplier;
} else if (self.x > self.targetX) {
self.x -= self.walkSpeed * gameSpeedMultiplier;
}
if (self.y < self.targetY) {
self.y += self.walkSpeed * gameSpeedMultiplier;
} else if (self.y > self.targetY) {
self.y -= self.walkSpeed * gameSpeedMultiplier;
}
} else {
// Reached target position
if (!self.isInQueue && !self.hasPurchased) {
// Join the queue
joinQueue(self);
} else if (self.isInQueue && self.queueIndex === 0 && !self.hasReachedStand && !self.hasPurchased) {
// First in queue, ready for manual sale
self.hasReachedStand = true;
}
// Start idle animation when stationary
if (!self.isIdle) {
self.isIdle = true;
self.baseY = self.y;
self.idleTimer = 0;
}
// Gentle idle bobbing animation
self.idleTimer += 0.05;
self.y = self.baseY + Math.sin(self.idleTimer) * 3;
}
};
self.leaveStand = function () {
var exitX = self.x < 1024 ? -100 : 2148;
tween(self, {
x: exitX
}, {
duration: 2000,
onFinish: function onFinish() {
self.destroy();
var index = customers.indexOf(self);
if (index > -1) {
customers.splice(index, 1);
}
}
});
};
return self;
});
var LemonadeGlass = Container.expand(function () {
var self = Container.call(this);
var glass = self.attachAsset('lemonadeGlass', {
anchorX: 0.5,
anchorY: 0.5
});
self.moveToCustomer = function (targetX, targetY, callback) {
tween(self, {
x: targetX,
y: targetY
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: callback
});
};
return self;
});
var LemonadeStand = Container.expand(function () {
var self = Container.call(this);
// Always start with normal lemonade stand initially
var standBase = self.attachAsset('lemonadeStand', {
anchorX: 0.5,
anchorY: 1.0
});
self.standBase = standBase; // Store reference for upgrades
// Add menu table
var menuTable = self.attachAsset('menuTable', {
anchorX: 0.5,
anchorY: 0.5,
x: 150,
y: -50
});
// Add price sign on menu table with bubble font style
var signText = new Text2('$1.00', {
size: 28,
fill: 0x00FF00,
font: "'Comic Sans MS', 'Chalkboard SE', cursive",
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 4,
dropShadowDistance: 2
});
signText.anchor.set(0.5, 0.5);
signText.x = 150;
signText.y = -50;
self.addChild(signText);
self.updateSign = function (price) {
signText.setText('$' + price.toFixed(2));
};
self.updateStandAsset = function () {
// Remove old stand asset
if (self.standBase) {
self.removeChild(self.standBase);
}
// Add new upgraded stand asset
var assetName = standLevel > 1 ? 'upgradedstand' : 'lemonadeStand';
self.standBase = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 1.0,
x: standLevel > 1 ? -20 : 0,
y: standLevel > 1 ? -20 : 0
});
// Hide/show lemonade glass on stand based on upgrade level
for (var l = 0; l < lemonadeGlasses.length; l++) {
if (lemonadeGlasses[l] && lemonadeGlasses[l].parent === game) {
// Check if this is the stand lemonade glass (positioned on stand)
if (Math.abs(lemonadeGlasses[l].x - lemonadeStand.x) < 50 && Math.abs(lemonadeGlasses[l].y - (lemonadeStand.y - 160)) < 50) {
lemonadeGlasses[l].alpha = standLevel > 1 ? 0 : 1;
}
}
}
// Ensure menu table and sign stay on top of upgraded stand
if (standLevel > 1) {
self.addChild(menuTable);
self.addChild(signText); // Bring price sign to front
}
};
return self;
});
var UpgradeButton = Container.expand(function (upgradeData) {
var self = Container.call(this);
var button = self.attachAsset('upgradeButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.4,
scaleY: 1.4
});
var titleText = new Text2(upgradeData.title, {
size: 32,
fill: 0xFFFFFF,
font: "'Comic Sans MS', 'Chalkboard SE', cursive"
});
titleText.anchor.set(0.5, 0.3);
titleText.x = 0;
titleText.y = -15;
self.addChild(titleText);
var costText = new Text2('$' + upgradeData.cost, {
size: 72,
fill: 0xFF8C00,
font: "'Comic Sans MS', 'Chalkboard SE', cursive",
dropShadow: true,
dropShadowColor: 0x000000,
dropShadowBlur: 3,
dropShadowDistance: 2
});
costText.anchor.set(0.5, 0.0);
costText.x = 0;
costText.y = 60;
self.addChild(costText);
self.upgradeData = upgradeData;
self.updateCost = function () {
costText.setText('$' + self.upgradeData.cost.toFixed(0));
// Update price color based on affordability
if (money >= self.upgradeData.cost) {
costText.tint = 0x00FF00; // Green when affordable
} else {
costText.tint = 0xFF0000; // Red when unaffordable
}
// Remove tinting to show original button image colors
button.tint = 0xFFFFFF; // Reset to original colors
};
self.down = function (x, y, obj) {
if (money >= self.upgradeData.cost) {
money -= self.upgradeData.cost;
self.upgradeData.apply();
self.upgradeData.cost *= 1.5;
self.updateCost();
if (!isSoundMuted) {
LK.getSound('upgrade').play();
}
// No animation - keep same size
} else {
// Play button click sound even when can't afford
if (!isSoundMuted) {
LK.getSound('buttonClick').play();
}
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game variables
var money = 0;
var lemonadeCount = 0; // No longer stackable
var salesCount = 0;
var productionRate = storage.productionRate || 2000; // milliseconds per lemonade, starting at 2 seconds
var currentPrice = 1.00;
var customerSpawnRate = storage.customerSpawnRate || 4000;
var standLevel = storage.standLevel || 1;
var customerCapacity = storage.customerCapacity || 3; // Starting customer capacity is 3
// Mute state variables
var isMusicMuted = storage.isMusicMuted || false;
var isSoundMuted = storage.isSoundMuted || false;
// Game arrays
var customers = [];
var lemonadeGlasses = [];
// Speed boost variables
var gameSpeedMultiplier = 1.0;
var boostEndTime = 0;
// Queue system variables
var queuePositions = [{
x: 924,
y: 1710
},
// Front of queue (closest to stand)
{
x: 824,
y: 1710
},
// Second position
{
x: 724,
y: 1710
},
// Third position
{
x: 624,
y: 1710
},
// Fourth position
{
x: 524,
y: 1710
} // Fifth position
];
var customerQueue = []; // Ordered array of customers in queue
var maxQueueSize = customerCapacity; // Maximum customers allowed in queue based on capacity
// Production tracking for customers per minute
var lastSaleTime = Date.now();
var salesHistory = [];
var currentProductionRate = 0;
// Create background environment
// Sky background
game.setBackgroundColor(0x87CEEB);
// Add clouds with random positions
var clouds = [];
for (var c = 0; c < 6; c++) {
var cloud = LK.getAsset('cloud', {
anchorX: 0.5,
anchorY: 0.5
});
cloud.x = Math.random() * 2500 - 200;
cloud.y = 250 + Math.random() * 300;
clouds.push(cloud);
game.addChild(cloud);
}
// Add sun to sky
var sun = LK.getAsset('sun', {
anchorX: 0.5,
anchorY: 0.5
});
sun.x = 1700;
sun.y = 300;
game.addChild(sun);
// Start cloud animations with 5x slower speed
function animateCloud(cloud) {
var randomSpeed = (15000 + Math.random() * 10000) * 5; // 5x slower
tween(cloud, {
x: cloud.x + 2500
}, {
duration: randomSpeed,
easing: tween.linear,
onFinish: function onFinish() {
cloud.x = -250;
cloud.y = 250 + Math.random() * 300;
animateCloud(cloud);
}
});
}
for (var c = 0; c < clouds.length; c++) {
animateCloud(clouds[c]);
}
// Add houses in background
var house1 = LK.getAsset('house', {
anchorX: 0.5,
anchorY: 1.0
});
house1.x = 200;
house1.y = 1450;
game.addChild(house1);
var house2 = LK.getAsset('house', {
anchorX: 0.5,
anchorY: 1.0
});
house2.x = 600;
house2.y = 1450;
game.addChild(house2);
var house3 = LK.getAsset('house', {
anchorX: 0.5,
anchorY: 1.0
});
house3.x = 1400;
house3.y = 1450;
game.addChild(house3);
var house4 = LK.getAsset('house', {
anchorX: 0.5,
anchorY: 1.0
});
house4.x = 1800;
house4.y = 1450;
game.addChild(house4);
// Add grass pattern
var grassPattern = [];
for (var g = 0; g < 5; g++) {
var garden = LK.getAsset('garden', {
anchorX: 0.0,
anchorY: 1.0
});
garden.x = g * 512;
garden.y = 1600;
grassPattern.push(garden);
game.addChild(garden);
}
// Add fences for each house (beginning and end with gaps)
// House 1 fences (x: 200)
var fence1a = LK.getAsset('fence', {
anchorX: 0.5,
anchorY: 1.0
});
fence1a.x = 50;
fence1a.y = 1580;
game.addChild(fence1a);
var fence1b = LK.getAsset('fence', {
anchorX: 0.5,
anchorY: 1.0
});
fence1b.x = 350;
fence1b.y = 1580;
game.addChild(fence1b);
// House 2 fences (x: 600)
var fence2a = LK.getAsset('fence', {
anchorX: 0.5,
anchorY: 1.0
});
fence2a.x = 450;
fence2a.y = 1580;
game.addChild(fence2a);
var fence2b = LK.getAsset('fence', {
anchorX: 0.5,
anchorY: 1.0
});
fence2b.x = 750;
fence2b.y = 1580;
game.addChild(fence2b);
// House 3 fences (x: 1400)
var fence3a = LK.getAsset('fence', {
anchorX: 0.5,
anchorY: 1.0
});
fence3a.x = 1250;
fence3a.y = 1580;
game.addChild(fence3a);
var fence3b = LK.getAsset('fence', {
anchorX: 0.5,
anchorY: 1.0
});
fence3b.x = 1550;
fence3b.y = 1580;
game.addChild(fence3b);
// House 4 fences (x: 1800)
var fence4a = LK.getAsset('fence', {
anchorX: 0.5,
anchorY: 1.0
});
fence4a.x = 1650;
fence4a.y = 1580;
game.addChild(fence4a);
var fence4b = LK.getAsset('fence', {
anchorX: 0.5,
anchorY: 1.0
});
fence4b.x = 1950;
fence4b.y = 1580;
game.addChild(fence4b);
// Add beige background section covering entire bottom area
var brownBackground = LK.getAsset('bottompart', {
anchorX: 0.5,
anchorY: 0.0
});
brownBackground.tint = 0xF5F5DC; // Beige color
brownBackground.x = 1024;
brownBackground.y = 2000; // Start below the asphalt road to keep it visible
// Add asphalt road
var asphalt = LK.getAsset('asphalt', {
anchorX: 0.5,
anchorY: 1.0
});
asphalt.x = 1024;
asphalt.y = 2000;
game.addChild(asphalt);
// Add sidewalk pattern
var sidewalkPattern = [];
for (var s = 0; s < 5; s++) {
var sidewalk = LK.getAsset('sidewalk', {
anchorX: 0.0,
anchorY: 1.0
});
sidewalk.x = s * 555;
sidewalk.y = 1710;
sidewalkPattern.push(sidewalk);
game.addChild(sidewalk);
}
// Create lemonade stand
var lemonadeStand = game.addChild(new LemonadeStand());
lemonadeStand.x = 1024;
lemonadeStand.y = 1700;
// Add manual selling variables
var isProcessingSale = false;
var saleProgressCircle = null;
// Add click handler for manual selling
lemonadeStand.down = function (x, y, obj) {
// Only process if there's a customer at front of queue and we're not already processing
if (customerQueue.length > 0 && !isProcessingSale && lemonadeCount > 0) {
var frontCustomer = customerQueue[0];
if (frontCustomer && frontCustomer.hasReachedStand && !frontCustomer.hasPurchased) {
startManualSale(frontCustomer);
} else {
// Play button click sound when clicking but can't sell
if (!isSoundMuted) {
LK.getSound('buttonClick').play();
}
}
} else {
// Play button click sound when clicking but can't sell
if (!isSoundMuted) {
LK.getSound('buttonClick').play();
}
}
};
// Create HUD elements
// Create modern HUD container with background
var hudContainer = new Container();
hudContainer.x = 120;
hudContainer.y = 40;
LK.gui.topLeft.addChild(hudContainer);
// HUD background panel removed to clean up top corner appearance
var moneyText = new Text2('💰 $' + money.toFixed(2), {
size: 52,
fill: 0xFFD700,
font: "'Comic Sans MS', 'Chalkboard SE', cursive",
stroke: 0x000000,
strokeThickness: 4
});
moneyText.anchor.set(0, 0);
moneyText.x = 20;
moneyText.y = 15;
hudContainer.addChild(moneyText);
var lemonadeText = new Text2('🏆 ' + salesCount + ' Sales', {
size: 52,
fill: 0x00FF88,
font: "'Comic Sans MS', 'Chalkboard SE', cursive",
stroke: 0x000000,
strokeThickness: 4
});
lemonadeText.anchor.set(0, 0);
lemonadeText.x = 20;
lemonadeText.y = 80;
hudContainer.addChild(lemonadeText);
var customerRateText = new Text2('⚡ 0/min served', {
size: 42,
fill: 0xFF6B35,
font: "'Comic Sans MS', 'Chalkboard SE', cursive",
stroke: 0x000000,
strokeThickness: 3
});
customerRateText.anchor.set(0, 0);
customerRateText.x = 20;
customerRateText.y = 145;
hudContainer.addChild(customerRateText);
// Create upgrade menu
var upgradeMenu = new Container();
upgradeMenu.x = 1024;
upgradeMenu.y = 2400; // Move up 100 pixels from 2500 to 2400
game.addChild(upgradeMenu);
// Upgrade definitions
var upgrades = [{
title: "Faster Production",
cost: 5,
apply: function apply() {
productionRate *= 0.8; // Make production 20% faster each upgrade
updateHUD();
}
}, {
title: "Better Recipe",
cost: 15,
apply: function apply() {
currentPrice += 0.3;
lemonadeStand.updateSign(currentPrice);
}
}, {
title: "Marketing",
cost: 30,
apply: function apply() {
customerCapacity += 1; // Increase customer capacity by 1
maxQueueSize = customerCapacity; // Update max queue size
customerSpawnRate *= 0.75;
}
}, {
title: "Stand Upgrade",
cost: 1000,
apply: function apply() {
standLevel++;
// Double the profit (price) and production speed
currentPrice *= 2;
productionRate *= 0.5; // Half the time = double the speed
// Update stand visual asset
lemonadeStand.updateStandAsset();
lemonadeStand.updateSign(currentPrice);
// Ensure customers stay on top layer after stand upgrade
for (var c = 0; c < customers.length; c++) {
if (customers[c]) {
game.addChild(customers[c]); // Brings customers to front
}
}
}
}];
// Create upgrade buttons
var upgradeButtons = [];
for (var i = 0; i < upgrades.length; i++) {
var upgradeButton = new UpgradeButton(upgrades[i]);
upgradeButton.x = (i - 1.5) * 425; // Button width (300 * 1.4 = 420) + 5 pixel padding = 425
upgradeButton.y = 0; // Keep buttons aligned horizontally
upgradeMenu.addChild(upgradeButton);
upgradeButtons.push(upgradeButton);
}
// Timers
var lastProductionTime = Date.now();
var lastCustomerTime = Date.now();
// We'll handle timing manually in update loop for speed boost
// Auto-save timer
var saveTimer = LK.setInterval(function () {
saveGame();
}, 5000);
function updateHUD() {
moneyText.setText('💰 $' + money.toFixed(2));
lemonadeText.setText('🏆 ' + salesCount + ' Sales');
customerRateText.setText('⚡ ' + calculateCustomerRate() + '/min served');
// Update upgrade buttons
for (var i = 0; i < upgradeMenu.children.length; i++) {
upgradeMenu.children[i].updateCost();
}
}
function joinQueue(customer) {
// Check if customer is already in queue to prevent duplicates
if (customerQueue.indexOf(customer) !== -1) {
return;
}
// Only add if there's an available position and under max limit
if (customerQueue.length < maxQueueSize && customerQueue.length < queuePositions.length) {
customerQueue.push(customer);
customer.isInQueue = true;
customer.queueIndex = customerQueue.length - 1;
// Assign specific position immediately
var positionIndex = customerQueue.length - 1;
customer.targetX = queuePositions[positionIndex].x;
customer.targetY = queuePositions[positionIndex].y;
}
}
function leaveQueue(customer) {
var index = customerQueue.indexOf(customer);
if (index !== -1) {
customerQueue.splice(index, 1);
customer.isInQueue = false;
customer.queueIndex = -1;
// Update queue positions for remaining customers
updateQueuePositions();
}
}
function updateQueuePositions() {
// Reassign positions based on current queue order
for (var i = 0; i < customerQueue.length; i++) {
var customer = customerQueue[i];
customer.queueIndex = i;
if (i < queuePositions.length) {
customer.targetX = queuePositions[i].x;
customer.targetY = queuePositions[i].y;
}
}
}
function calculateCustomerRate() {
if (salesHistory.length < 2) {
return 0;
}
var timeSpan = salesHistory[salesHistory.length - 1] - salesHistory[0];
var salesInSpan = salesHistory.length;
if (timeSpan > 0) {
return (salesInSpan / (timeSpan / 60000)).toFixed(1);
}
return 0;
}
function spawnCustomer() {
// Don't spawn if we already have the maximum number of customers on screen
if (customers.length >= customerCapacity) {
return;
}
// Only spawn one customer at a time
var customer = new Customer();
var startSide = Math.random() < 0.5 ? 0 : 1;
if (startSide === 0) {
customer.x = -100;
customer.targetX = queuePositions[0].x - 100;
} else {
customer.x = 2148;
customer.targetX = queuePositions[0].x + 100;
}
customer.y = 1710;
customer.targetY = 1710;
customers.push(customer);
game.addChild(customer);
}
function startManualSale(customer) {
isProcessingSale = true;
// Create progress circle
saleProgressCircle = new Container();
// Background circle
var progressBg = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0
});
progressBg.tint = 0x333333;
progressBg.alpha = 0.8;
saleProgressCircle.addChild(progressBg);
// Progress fill circle
var progressFill = LK.getAsset('coin', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1
});
progressFill.tint = 0x00FF00;
saleProgressCircle.addChild(progressFill);
// Position above the stand
saleProgressCircle.x = lemonadeStand.x;
saleProgressCircle.y = lemonadeStand.y - 300;
game.addChild(saleProgressCircle);
// Animate the progress fill over 2 seconds
tween(progressFill, {
scaleX: 1.8,
scaleY: 1.8
}, {
duration: 2000,
easing: tween.linear,
onFinish: function onFinish() {
completeManualSale(customer);
}
});
}
function completeManualSale(customer) {
// Complete the customer's purchase
if (customer && !customer.hasPurchased && customer.queueIndex === 0) {
customer.hasPurchased = true;
customer.hasReachedStand = false;
lemonadeCount = 0; // Used up the ready lemonade
salesCount++;
money += currentPrice;
// Track sale time for production rate calculation
salesHistory.push(Date.now());
if (salesHistory.length > 10) {
salesHistory.shift();
}
if (!isSoundMuted) {
LK.getSound('cashRegister').play();
}
// Create lemonade glass for customer
var lemonadeGlass = new LemonadeGlass();
lemonadeGlass.x = lemonadeStand.x;
lemonadeGlass.y = lemonadeStand.y - 50;
game.addChild(lemonadeGlass);
lemonadeGlasses.push(lemonadeGlass);
// Move lemonade to customer's hand position
lemonadeGlass.moveToCustomer(customer.x, customer.y - 80, function () {
// Keep lemonade with customer while they leave
customer.addChild(lemonadeGlass);
lemonadeGlass.x = 20; // Offset from customer center
lemonadeGlass.y = -80; // Above customer
});
// Show coin animation
var coin = new Container();
var coinSprite = coin.attachAsset('coin', {
anchorX: 0.5,
anchorY: 0.5
});
coin.x = customer.x;
coin.y = customer.y - 100;
game.addChild(coin);
tween(coin, {
y: coin.y - 100,
alpha: 0
}, {
duration: 1500,
onFinish: function onFinish() {
coin.destroy();
}
});
// Remove from queue and advance other customers
leaveQueue(customer);
// Customer leaves after purchase
LK.setTimeout(function () {
customer.leaveStand();
}, 1000);
}
// Clean up progress circle
if (saleProgressCircle) {
saleProgressCircle.destroy();
saleProgressCircle = null;
}
isProcessingSale = false;
}
function saveGame() {
storage.money = money;
storage.salesCount = salesCount;
storage.productionRate = productionRate;
storage.currentPrice = currentPrice;
storage.customerSpawnRate = customerSpawnRate;
storage.standLevel = standLevel;
storage.customerCapacity = customerCapacity;
storage.isMusicMuted = isMusicMuted;
storage.isSoundMuted = isSoundMuted;
}
// Game update loop
game.update = function () {
// Check if speed boost should end
if (Date.now() > boostEndTime) {
gameSpeedMultiplier = 1.0;
}
var currentTime = Date.now();
// Handle production timer with speed boost - always have lemonade ready
if (currentTime - lastProductionTime >= productionRate / gameSpeedMultiplier) {
lemonadeCount = 1; // Always have one ready
lastProductionTime = currentTime;
}
// Handle customer spawn timer with speed boost
if (currentTime - lastCustomerTime >= customerSpawnRate / gameSpeedMultiplier) {
spawnCustomer();
lastCustomerTime = currentTime;
}
// Update customers with speed boost
for (var i = customers.length - 1; i >= 0; i--) {
if (customers[i] && customers[i].update) {
// Apply speed boost to customer walk speed
customers[i].walkSpeed = 2 * gameSpeedMultiplier;
customers[i].update();
}
}
// Update HUD every 30 frames (0.5 seconds)
if (LK.ticks % 30 === 0) {
updateHUD();
}
// Ensure lemonade glasses are always on top layer for visibility
for (var l = 0; l < lemonadeGlasses.length; l++) {
if (lemonadeGlasses[l] && lemonadeGlasses[l].parent === game) {
game.addChild(lemonadeGlasses[l]); // Brings to front
}
}
// Ensure customers are always on top layer for visibility
for (var c = 0; c < customers.length; c++) {
if (customers[c] && customers[c].parent === game) {
game.addChild(customers[c]); // Brings customers to front
}
}
// Ensure lemonade stand price sign stays on absolute top layer
if (lemonadeStand && lemonadeStand.children) {
for (var s = 0; s < lemonadeStand.children.length; s++) {
if (lemonadeStand.children[s] instanceof Text2) {
lemonadeStand.addChild(lemonadeStand.children[s]); // Bring price text to front
break;
}
}
}
};
// Add brown background to front layer to ensure it covers all blue areas
game.addChild(brownBackground);
// Fences are already added earlier and should stay behind upgradedstand
// No need to bring them to front layer
// Bring upgrade menu to front layer
game.addChild(upgradeMenu);
// Add one lemonade glass on lemonade stand on top layer
var standLemonadeGlass = new LemonadeGlass();
standLemonadeGlass.x = lemonadeStand.x;
standLemonadeGlass.y = lemonadeStand.y - 160; // Position on top of stand, moved 10 pixels up
game.addChild(standLemonadeGlass);
lemonadeGlasses.push(standLemonadeGlass);
// Initial setup
lemonadeStand.updateSign(currentPrice);
updateHUD();
// Create music mute button
var musicMuteButton = LK.getAsset('musicMuteButton', {
anchorX: 0.5,
anchorY: 0.5
});
musicMuteButton.x = -100;
musicMuteButton.y = 70;
LK.gui.topRight.addChild(musicMuteButton);
// Add music note symbol
var musicNoteText = new Text2('♪', {
size: 36,
fill: 0xFFFFFF,
font: "'Arial', sans-serif"
});
musicNoteText.anchor.set(0.5, 0.5);
musicNoteText.x = -100;
musicNoteText.y = 70;
LK.gui.topRight.addChild(musicNoteText);
// Update music button appearance based on mute state
function updateMusicButton() {
if (isMusicMuted) {
musicMuteButton.alpha = 0.5;
musicNoteText.alpha = 0.5;
} else {
musicMuteButton.alpha = 1.0;
musicNoteText.alpha = 1.0;
}
}
// Music mute button click handler
musicMuteButton.down = function (x, y, obj) {
isMusicMuted = !isMusicMuted;
updateMusicButton();
if (isMusicMuted) {
LK.stopMusic();
} else {
LK.playMusic('backgroundMusic', {
volume: 0.3
});
}
// Save mute state
storage.isMusicMuted = isMusicMuted;
};
// Create sound mute button
var soundMuteButton = LK.getAsset('soundMuteButton', {
anchorX: 0.5,
anchorY: 0.5
});
soundMuteButton.x = -100;
soundMuteButton.y = 140;
LK.gui.topRight.addChild(soundMuteButton);
// Add sound symbol
var soundText = new Text2('♫', {
size: 36,
fill: 0xFFFFFF,
font: "'Arial', sans-serif"
});
soundText.anchor.set(0.5, 0.5);
soundText.x = -100;
soundText.y = 140;
LK.gui.topRight.addChild(soundText);
// Update sound button appearance based on mute state
function updateSoundButton() {
if (isSoundMuted) {
soundMuteButton.alpha = 0.5;
soundText.alpha = 0.5;
} else {
soundMuteButton.alpha = 1.0;
soundText.alpha = 1.0;
}
}
// Sound mute button click handler
soundMuteButton.down = function (x, y, obj) {
isSoundMuted = !isSoundMuted;
updateSoundButton();
// Save mute state
storage.isSoundMuted = isSoundMuted;
};
// Initialize button states
updateMusicButton();
updateSoundButton();
// Start background music
if (!isMusicMuted) {
LK.playMusic('backgroundMusic', {
volume: 0.3
});
}
Standart coin. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
clear
Lemonade glass. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Lemonade stand. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Cloud. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Grassy garden. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Asphalt. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Tiny house. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
rounded fund button, no text. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Wooden table menu. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Sidewalk stones. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
White garden fence. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Mobile game style bottom menu background with borders vector. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
White fill Lemonade truck with tires, with lemonade stand space on behind, door, windows, white color fill. . No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Sun. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat