User prompt
After the 6th customer, any new customer overlaps and stands inside the 6th customer's position. This is a major bug and it should never happen. The second issue is that after a few customers, the customer at the front stops placing orders and the game freezes or gets stuck. The system must work perfectly without any deadlocks or bugs. If this is happening due to too many customers (high traffic), we can reduce the customer spawn rate. Additionally, if the queue is full, new customers should not join or enter the queue at all. We should set a maximum number of customers allowed in the queue, and any extra customers should not attempt to join. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Some customers overlap and share the same queue position, which causes problems. This should never happen; each queue position can only hold one customer at a time simultaneously. Additionally, when we click on the screen, it currently turns green — this should be disabled completely. Customers also grow or scale up when clicking; this should also be removed. Remove the entire click system completely. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'TypeError: Cannot use 'in' operator to search for 'scaleX' in undefined' in or related to this line: 'tween(customers[i], {' Line Number: 698 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Design a customer queueing and processing system for a shop simulation game. Here's how the logic must work: Queue Positioning: Customers can only wait in line in front of the shop stand. There should be an array of fixed positions where customers can queue. Only these positions are valid for standing in line. Queue Behavior: When the first customer arrives, they take the first available spot in the queue. Any following customer checks the queue. If there are customers already in line, they go to the next available spot at the back. Only the customer at the front-most queue position is allowed to place an order and complete a transaction. When the first customer leaves, every customer behind moves forward to the next closer spot. Movement should be handled one by one, always giving priority to the customer who has been in the queue longer. A customer must never "cut in line." Arrival Behavior: If a new customer arrives at the exact moment the front-most position is freed (due to a previous customer leaving), the new customer must still go to the back of the queue. The system must prevent newly arriving customers from immediately occupying a freed front position just because they are physically closer. Interaction Rules: Only the customer standing at the closest position to the stand can interact with it. No customer may skip queue positions or perform interactions if they are not at the first position. Production Rate Display: There should be a counter labeled "Production per Minute" or "Customers Served per Minute". This counter should be calculated based on the average time a customer spends to complete a transaction (assume 5 seconds per customer), customer arrival intervals, and the total queue throughput. The player should be able to see how efficiently their stand is operating. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
I want to see boost effect while i click on screen. I need to feel how they move faster. Put some outline for upgrade prices for make more readable. Change button colors if they can usable make it same color as garden grass green. And if they not same as house roof color. Change customer move set. They need to wait for making lemonade. If one customer coming for take, anotherone need to stay behind others. Who taking lemonade we need to see some icon top of them like a loading circle filling green circle things. And lemonade making time or selling time need to 5 sec each customer at the begining. Faster production upgrade make it faster. Lemonade not stackable and change the amount meter of top with how much sells. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Clouds moving together like a same object, make them random position. Economy is not good check this and fix that for make more playable. Screen click must be do game speed 1.3x faster for a 1 sec. More click doesnt effect cap is 1.3x always more click just keep that along no change amount just like a boost. Change upgrade price position. Can't read inside of buttons. Put them near to buttons for more good and understandable. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Remove roofs. Make cloud move animation endless slide slowly. create pattern horizontally for sidewalk. Sidewalk need to go down 10 pixels. create pattern horizontally for garden grass delete 4 and choose one of them first and make pattern horizontally fill the screen horizontally with same like a sidewalk. Put two fence for each house begining and end put a gap between of them like a enterance. Customers walking on asphalt they must walking on sidewalk check this and fix vertically positions for customers. Change "Lemonade Price ..." with just price like a $.. ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Delete top of stand. Make a little menu table near to stand and put this "Lemonade price" on it. Change font like bubble and fun font. Add sidewalk and asphalt and some houses at back like a side scroll games. Some gardens and fences. Sky and clouds.
Code edit (1 edits merged)
Please save this source code
User prompt
Lemonade Stand Tycoon
Initial prompt
Make me a lemonade tycoon game. Fixed screen, standart tycoon or idle game mechanics. Easy play. One lemonade stand on center. Currency and other things on hud. Some mobile style tycoon menus like some upgrade things or other etc.
/**** * 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