User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1619
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1619
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1619
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1619
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1619
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1619
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1619
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1619
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1619
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1610
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1601
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1601
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1601
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1601
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1592
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1583
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1574
User prompt
Haz que para cada usuario se reinicie todo el progreso de las misiones, los nutripoints y la tienda. Que cada usuario empieze desde 0 ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1539
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1539
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1539
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1530
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1530
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1530
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading '0')' in or related to this line: 'return;' Line Number: 1530
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var FAQScreen = Container.expand(function () { var self = Container.call(this); // Create background var bg = LK.getAsset('energyBarBg', { width: 2048, height: 2732, anchorX: 0, anchorY: 0 }); bg.tint = 0xF8F9FA; self.addChild(bg); // Create scrollable container for FAQ content var scrollContainer = new Container(); self.addChild(scrollContainer); // Title var titleText = new Text2('PREGUNTAS FRECUENTES', { size: 80, fill: 0x2C3E50, font: "Impact" }); titleText.anchor.set(0.5, 0); titleText.x = 2048 / 2; titleText.y = 150; scrollContainer.addChild(titleText); self.faqContainer = new Container(); self.faqContainer.x = 0; self.faqContainer.y = 300; scrollContainer.addChild(self.faqContainer); // FAQ state tracking self.openFAQIndex = -1; // Track which FAQ is currently open self.faqItems = []; // Store FAQ item references // Create FAQ items self.createFAQItems = function () { self.faqContainer.removeChildren(); self.faqItems = []; var currentY = 0; var itemSpacing = 20; for (var i = 0; i < faqData.length; i++) { var faq = faqData[i]; var isOpen = self.openFAQIndex === i; // Question container with shadow effect var questionContainer = new Container(); questionContainer.y = currentY; self.faqContainer.addChild(questionContainer); // Question background with rounded appearance var questionBg = LK.getAsset('restartButton', { width: 1800, height: 160, anchorX: 0.5, anchorY: 0 }); questionBg.tint = isOpen ? 0x3498DB : 0x34495E; questionBg.x = 2048 / 2; questionBg.y = 0; questionContainer.addChild(questionBg); // Expand/collapse icon var iconText = new Text2(isOpen ? '⊖' : '⊕', { size: 70, fill: 0xFFFFFF, font: "Impact" }); iconText.anchor.set(0, 0.5); iconText.x = 250; iconText.y = 80; questionContainer.addChild(iconText); // Question text var questionText = new Text2(faq.question, { size: 58, fill: 0xFFFFFF, font: "Impact" }); questionText.anchor.set(0, 0.5); questionText.x = 350; questionText.y = 80; questionContainer.addChild(questionText); // Answer container (initially hidden if not open) var answerContainer = new Container(); answerContainer.y = 170; answerContainer.alpha = isOpen ? 1 : 0; answerContainer.visible = isOpen; questionContainer.addChild(answerContainer); // Answer background var answerBg = LK.getAsset('restartButton', { width: 1700, height: isOpen ? 240 : 0, anchorX: 0.5, anchorY: 0 }); answerBg.tint = 0xECF0F1; answerBg.x = 2048 / 2; answerBg.y = 0; answerContainer.addChild(answerBg); // Answer text with proper wrapping var answerText = new Text2(faq.answer, { size: 50, fill: 0x2C3E50, font: "Impact", wordWrap: true, wordWrapWidth: 1600 }); answerText.anchor.set(0.5, 0); answerText.x = 2048 / 2; answerText.y = 30; answerContainer.addChild(answerText); // Store references var faqItem = { index: i, questionContainer: questionContainer, questionBg: questionBg, iconText: iconText, answerContainer: answerContainer, answerBg: answerBg, isOpen: isOpen }; self.faqItems.push(faqItem); // Add click handlers with closure (function (itemIndex) { questionBg.down = function () { self.toggleFAQ(itemIndex); }; iconText.down = function () { self.toggleFAQ(itemIndex); }; questionText.down = function () { self.toggleFAQ(itemIndex); }; })(i); // Calculate next Y position currentY += 160 + itemSpacing; if (isOpen) { currentY += 240 + itemSpacing; } } }; // Toggle FAQ open/close self.toggleFAQ = function (index) { if (index === self.openFAQIndex) { // Close currently open FAQ self.closeFAQ(index); self.openFAQIndex = -1; } else { // Close currently open FAQ if any if (self.openFAQIndex >= 0) { self.closeFAQ(self.openFAQIndex); } // Open new FAQ self.openFAQ(index); self.openFAQIndex = index; } }; // Open FAQ with animation self.openFAQ = function (index) { var item = self.faqItems[index]; if (!item) return; // Update icon and background color item.iconText.setText('⊖'); tween(item.questionBg, { tint: 0x3498DB }, { duration: 200 }); // Show and animate answer container item.answerContainer.visible = true; item.answerContainer.alpha = 0; // Animate answer background height tween(item.answerBg, { height: 240 }, { duration: 300, easing: tween.easeOut }); // Fade in answer container tween(item.answerContainer, { alpha: 1 }, { duration: 250, onFinish: function onFinish() { // Recreate all items to adjust positions LK.setTimeout(function () { self.createFAQItems(); }, 50); } }); }; // Close FAQ with animation self.closeFAQ = function (index) { var item = self.faqItems[index]; if (!item) return; // Update icon and background color item.iconText.setText('⊕'); tween(item.questionBg, { tint: 0x34495E }, { duration: 200 }); // Fade out and hide answer container tween(item.answerContainer, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { item.answerContainer.visible = false; // Animate answer background height to 0 tween(item.answerBg, { height: 0 }, { duration: 200, easing: tween.easeIn, onFinish: function onFinish() { // Recreate all items to adjust positions LK.setTimeout(function () { self.createFAQItems(); }, 50); } }); } }); }; // Bottom back button var bottomBackButton = LK.getAsset('restartButton', { width: 400, height: 100, anchorX: 0.5, anchorY: 0.5 }); bottomBackButton.tint = 0xFF6B35; bottomBackButton.x = 2048 / 2; bottomBackButton.y = 2600; self.addChild(bottomBackButton); var bottomBackText = new Text2('← VOLVER', { size: 60, fill: 0xFFFFFF, font: "Impact" }); bottomBackText.anchor.set(0.5, 0.5); bottomBackText.x = 2048 / 2; bottomBackText.y = 2600; self.addChild(bottomBackText); bottomBackButton.down = function () { showStartScreen(); }; bottomBackText.down = function () { showStartScreen(); }; return self; }); var FallingItem = Container.expand(function (type, specificFood) { var self = Container.call(this); self.type = type; self.specificFood = specificFood; // Set different speeds based on type and add randomness if (type === 'anxiety') { self.speed = fallSpeed * 1.5; // Anxiety bombs fall faster } else if (type === 'water') { self.speed = fallSpeed * 0.8; // Water bottles fall slower } else { // Food items have variable speeds between 1.2x and 2.0x base speed (much faster) var speedMultiplier = 1.2 + Math.random() * 0.8; // Increase speed significantly during expert mode if (anxietyBombsActive) { speedMultiplier *= 2.2; // Make items fall 120% faster in expert mode } self.speed = fallSpeed * speedMultiplier; } var assetName = specificFood || 'waterBottle'; if (type === 'water') assetName = 'waterBottle';else if (type === 'anxiety') assetName = 'anxietyBomb'; var graphic = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { self.y += self.speed; }; return self; }); var MissionManager = Container.expand(function () { var self = Container.call(this); self.activeMissions = []; self.init = function () { self.loadActiveMissions(); }; self.loadActiveMissions = function () { var today = new Date().toDateString(); var savedDate = storage.missionsDate; if (savedDate !== today) { self.generateNewDailyMissions(); } else { var savedMissions = storage.activeMissions; if (savedMissions && savedMissions.length > 0) { self.activeMissions = []; for (var i = 0; i < savedMissions.length; i++) { self.activeMissions.push({ id: savedMissions['mission_' + i + '_id'], text: savedMissions['mission_' + i + '_text'], metaTotal: savedMissions['mission_' + i + '_metaTotal'], type: savedMissions['mission_' + i + '_type'], avanceActual: savedMissions['mission_' + i + '_avanceActual'] || 0, completada: savedMissions['mission_' + i + '_completada'] || false }); } } else { self.activeMissions = []; } missionManager.activeMissions = self.activeMissions; } }; self.generateNewDailyMissions = function () { var shuffled = allMissions.slice(); for (var i = shuffled.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = shuffled[i]; shuffled[i] = shuffled[j]; shuffled[j] = temp; } self.activeMissions = shuffled.slice(0, 3).map(function (mission) { return { id: mission.id, text: mission.text, metaTotal: mission.metaTotal, type: mission.type, avanceActual: 0, completada: false }; }); missionManager.activeMissions = self.activeMissions; var today = new Date().toDateString(); var storageData = {}; for (var i = 0; i < self.activeMissions.length; i++) { var mission = self.activeMissions[i]; storageData['mission_' + i + '_id'] = mission.id; storageData['mission_' + i + '_text'] = mission.text; storageData['mission_' + i + '_metaTotal'] = mission.metaTotal; storageData['mission_' + i + '_type'] = mission.type; storageData['mission_' + i + '_avanceActual'] = mission.avanceActual; storageData['mission_' + i + '_completada'] = mission.completada; } storageData.length = self.activeMissions.length; storage.activeMissions = storageData; storage.missionsDate = today; }; self.emitEvent = function (eventType, data) { for (var i = 0; i < self.activeMissions.length; i++) { var mission = self.activeMissions[i]; if (mission.completada) continue; var oldProgress = mission.avanceActual; switch (mission.type) { case "energia": if (eventType === "energia_updated" && data.energia >= mission.metaTotal) { mission.avanceActual = data.energia; } break; case "frutas": if (eventType === "fruta_atrapada") { mission.avanceActual = Math.min(mission.avanceActual + 1, mission.metaTotal); } break; case "tiempo_sin_gaseosas": if (eventType === "frame_update" && data.gameTime >= 0) { var timeSinceLastSoda = data.gameTime - missionManager.lastGaseosaTime; mission.avanceActual = Math.min(timeSinceLastSoda, mission.metaTotal); } if (eventType === "gaseosa_atrapada") { missionManager.lastGaseosaTime = data.gameTime; mission.avanceActual = 0; } break; case "nutripoints_total": if (eventType === "nutripoints_updated") { mission.avanceActual = Math.min(data.total, mission.metaTotal); } break; case "agua": if (eventType === "agua_atrapada") { mission.avanceActual = Math.min(mission.avanceActual + 1, mission.metaTotal); } break; case "partidas_consecutivas": if (eventType === "partida_ganada") { mission.avanceActual = Math.min(missionManager.consecutiveWins, mission.metaTotal); } break; case "partida_vidas": if (eventType === "partida_ganada" && data.vidasRestantes >= 3) { mission.avanceActual = Math.min(mission.avanceActual + 1, mission.metaTotal); } break; case "falsos_ganar": if (eventType === "partida_ganada" && missionManager.falsosInCurrentGame >= 3) { mission.avanceActual = Math.min(mission.avanceActual + 1, mission.metaTotal); } break; case "partidas_energia_25": if (eventType === "partida_ganada" && data.energia >= 25) { mission.avanceActual = Math.min(missionManager.consecutiveHighEnergyWins, mission.metaTotal); } break; case "tiempo_continuo": if (eventType === "frame_update") { var playTime = data.gameTime; mission.avanceActual = Math.min(playTime, mission.metaTotal); } break; } // Animate progress bar if progress changed if (oldProgress !== mission.avanceActual) { self.animateProgressBar(i, oldProgress, mission.avanceActual); } // Check if mission completed if (!mission.completada && mission.avanceActual >= mission.metaTotal) { mission.completada = true; sumarNutriPoints(2); self.showMissionCompleted(mission); // Replace completed mission with a new one after a short delay LK.setTimeout(function () { self.replaceCompletedMission(i); // Refresh missions display if currently viewing missions if (currentScreen === 'missions') { updateMissionsDisplay(); } }, 3000); // Wait 3 seconds before replacing } } missionManager.activeMissions = self.activeMissions; var storageData = {}; for (var i = 0; i < self.activeMissions.length; i++) { var mission = self.activeMissions[i]; storageData['mission_' + i + '_id'] = mission.id; storageData['mission_' + i + '_text'] = mission.text; storageData['mission_' + i + '_metaTotal'] = mission.metaTotal; storageData['mission_' + i + '_type'] = mission.type; storageData['mission_' + i + '_avanceActual'] = mission.avanceActual; storageData['mission_' + i + '_completada'] = mission.completada; } storageData.length = self.activeMissions.length; storage.activeMissions = storageData; }; self.animateProgressBar = function (missionIndex, oldProgress, newProgress) { // Find progress bar for this mission and animate it if (currentScreen === 'missions' && missionsScreen && missionsScreen.progressBars) { var progressBar = missionsScreen.progressBars[missionIndex]; if (progressBar) { var mission = self.activeMissions[missionIndex]; var newWidth = Math.min(newProgress / mission.metaTotal * 450, 450); tween(progressBar, { width: newWidth }, { duration: 300, easing: tween.easeOut }); } } }; self.replaceCompletedMission = function (missionIndex) { // Get available missions that are not currently active var availableMissions = []; for (var i = 0; i < allMissions.length; i++) { var isActive = false; for (var j = 0; j < self.activeMissions.length; j++) { if (self.activeMissions[j].id === allMissions[i].id) { isActive = true; break; } } if (!isActive) { availableMissions.push(allMissions[i]); } } // If we have available missions, replace the completed one if (availableMissions.length > 0) { var randomIndex = Math.floor(Math.random() * availableMissions.length); var newMission = availableMissions[randomIndex]; self.activeMissions[missionIndex] = { id: newMission.id, text: newMission.text, metaTotal: newMission.metaTotal, type: newMission.type, avanceActual: 0, completada: false }; // Save updated missions self.saveMissions(); } }; self.saveMissions = function () { var storageData = {}; for (var i = 0; i < self.activeMissions.length; i++) { var mission = self.activeMissions[i]; storageData['mission_' + i + '_id'] = mission.id; storageData['mission_' + i + '_text'] = mission.text; storageData['mission_' + i + '_metaTotal'] = mission.metaTotal; storageData['mission_' + i + '_type'] = mission.type; storageData['mission_' + i + '_avanceActual'] = mission.avanceActual; storageData['mission_' + i + '_completada'] = mission.completada; } storageData.length = self.activeMissions.length; storage.activeMissions = storageData; missionManager.activeMissions = self.activeMissions; }; self.showMissionCompleted = function (mission) { if (!gameActive) return; // Create mission completed banner var banner = LK.getAsset('restartButton', { width: 800, height: 120, anchorX: 0.5, anchorY: 0.5 }); banner.tint = 0x4CAF50; banner.alpha = 0; banner.x = 2048 / 2; banner.y = 200; game.addChild(banner); var bannerText = new Text2('¡Misión cumplida: ' + mission.text.substring(0, 20) + '... +2 NP!', { size: 35, fill: 0xFFFFFF, font: "Impact" }); bannerText.anchor.set(0.5, 0.5); bannerText.x = 2048 / 2; bannerText.y = 200; bannerText.alpha = 0; game.addChild(bannerText); // Play success sound LK.getSound('powerup').play(); // Animate banner tween(banner, { alpha: 0.9 }, { duration: 250, onFinish: function onFinish() { LK.setTimeout(function () { tween(banner, { alpha: 0 }, { duration: 250, onFinish: function onFinish() { banner.destroy(); } }); tween(bannerText, { alpha: 0 }, { duration: 250, onFinish: function onFinish() { bannerText.destroy(); } }); }, 2500); } }); tween(bannerText, { alpha: 1 }, { duration: 250 }); }; return self; }); var MissionsScreen = Container.expand(function () { var self = Container.call(this); // Create background var bg = LK.getAsset('energyBarBg', { width: 2048, height: 2732, anchorX: 0, anchorY: 0 }); bg.tint = 0x2C3E50; bg.alpha = 0.95; self.addChild(bg); // Title var titleText = new Text2('MISIONES DIARIAS', { size: 100, fill: 0xFFD700, font: "Impact" }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 300; self.addChild(titleText); // Create scrollable container for missions var scrollableArea = new Container(); scrollableArea.x = 0; scrollableArea.y = 450; // Start below title scrollableArea.scrollY = 0; // Track scroll position self.addChild(scrollableArea); // Create mask for scrollable area (visible area) var scrollMask = LK.getAsset('energyBarBg', { width: 2048, height: 2000, // Height available for scrolling (from y=450 to y=2450) anchorX: 0, anchorY: 0 }); scrollMask.x = 0; scrollMask.y = 450; scrollMask.alpha = 0; // Invisible mask self.addChild(scrollMask); scrollableArea.mask = scrollMask; self.missionsContainer = new Container(); scrollableArea.addChild(self.missionsContainer); // Store references for scrolling self.scrollableArea = scrollableArea; self.maxScrollY = 0; // Will be calculated based on content self.scrollMask = scrollMask; // Add scroll functionality self.enableScrolling = function () { // Touch/mouse wheel scrolling var isDragging = false; var lastY = 0; var scrollSpeed = 2; scrollableArea.down = function (x, y, obj) { isDragging = true; lastY = y; }; scrollableArea.move = function (x, y, obj) { if (isDragging) { var deltaY = y - lastY; self.scroll(deltaY * scrollSpeed); lastY = y; } }; scrollableArea.up = function (x, y, obj) { isDragging = false; }; // Also enable scrolling on the background bg.down = function (x, y, obj) { isDragging = true; lastY = y; }; bg.move = function (x, y, obj) { if (isDragging && y > 450 && y < 2450) { // Only scroll in missions area var deltaY = y - lastY; self.scroll(deltaY * scrollSpeed); lastY = y; } }; bg.up = function (x, y, obj) { isDragging = false; }; }; // Scroll function self.scroll = function (deltaY) { var newScrollY = self.scrollableArea.scrollY + deltaY; // Calculate max scroll based on content height var contentHeight = self.missionsContainer.height || 0; var visibleHeight = 2000; // Height of visible area self.maxScrollY = Math.max(0, contentHeight - visibleHeight); // Constrain scroll within bounds newScrollY = Math.max(-self.maxScrollY, Math.min(0, newScrollY)); self.scrollableArea.scrollY = newScrollY; self.scrollableArea.y = 450 + newScrollY; }; // Update content height calculation self.updateScrollBounds = function () { // Calculate total content height based on missions var activeMissions = missionManager.activeMissions; if (activeMissions && activeMissions.length > 0) { var totalHeight = activeMissions.length * 320 + 100; // Each mission is 320px + padding var visibleHeight = 2000; self.maxScrollY = Math.max(0, totalHeight - visibleHeight); // Reset scroll to top when content updates self.scrollableArea.scrollY = 0; self.scrollableArea.y = 450; } }; // Enable scrolling self.enableScrolling(); // Bottom back button var bottomBackButton = LK.getAsset('restartButton', { width: 400, height: 100, anchorX: 0.5, anchorY: 0.5 }); bottomBackButton.tint = 0xFF6B35; bottomBackButton.x = 2048 / 2; bottomBackButton.y = 2600; self.addChild(bottomBackButton); var bottomBackText = new Text2('← VOLVER', { size: 60, fill: 0xFFFFFF, font: "Impact" }); bottomBackText.anchor.set(0.5, 0.5); bottomBackText.x = 2048 / 2; bottomBackText.y = 2600; self.addChild(bottomBackText); bottomBackButton.down = function () { showStartScreen(); }; bottomBackText.down = function () { showStartScreen(); }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerBody = self.attachAsset('player', { anchorX: 0.5, anchorY: 1.0 }); var basket = self.attachAsset('basket', { anchorX: 0.5, anchorY: 0.5, y: -110 }); self.speed = 8; self.targetX = self.x; self.update = function () { var dx = self.targetX - self.x; if (Math.abs(dx) > 5) { self.x += dx * 0.15; } else { self.x = self.targetX; } // Keep player within bounds if (self.x < 150) self.x = 150; if (self.x > 2048 - 150) self.x = 2048 - 150; }; self.moveTo = function (targetX) { self.targetX = targetX; }; return self; }); var StartScreen = Container.expand(function () { var self = Container.call(this); // Create background var bg = LK.getAsset('energyBarBg', { width: 2048, height: 2732, anchorX: 0, anchorY: 0 }); bg.tint = 0x5d6c16; self.addChild(bg); // Game title var titleText = new Text2('Caza-ingredientes', { size: 120, fill: 0xFFD700, font: "Impact" }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 400; self.addChild(titleText); // Nutripoints display on start screen var nutripointsDisplay = new Text2('Nutripoints: ' + (storage.totalNutripoints || 0), { size: 75, fill: 0x32CD32, font: "Impact" }); nutripointsDisplay.anchor.set(0.5, 0.5); nutripointsDisplay.x = 2048 / 2; nutripointsDisplay.y = 500; self.addChild(nutripointsDisplay); // Store reference for updates self.nutripointsDisplay = nutripointsDisplay; var subtitleText = new Text2('Elige bien, vive mejor', { size: 80, fill: 0x32CD32, font: "Impact" }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 2048 / 2; subtitleText.y = 580; self.addChild(subtitleText); // Create buttons var buttonProps = [{ text: 'PLAY', y: 850, color: 0x32CD32 }, { text: 'MISIONES', y: 1050, color: 0xFF6B35 }, { text: 'TIENDA', y: 1250, color: 0x4ECDC4 }, { text: 'PREGUNTAS', y: 1450, color: 0x9B59B6 }]; self.buttons = []; for (var i = 0; i < buttonProps.length; i++) { var buttonBg = LK.getAsset('restartButton', { width: 600, height: 120, anchorX: 0.5, anchorY: 0.5 }); buttonBg.tint = buttonProps[i].color; buttonBg.x = 2048 / 2; buttonBg.y = buttonProps[i].y; self.addChild(buttonBg); var buttonText = new Text2(buttonProps[i].text, { size: 70, fill: 0xFFFFFF, font: "Impact" }); buttonText.anchor.set(0.5, 0.5); buttonText.x = 2048 / 2; buttonText.y = buttonProps[i].y; self.addChild(buttonText); buttonBg.buttonType = buttonProps[i].text; buttonText.buttonType = buttonProps[i].text; self.buttons.push({ bg: buttonBg, text: buttonText, type: buttonProps[i].text }); } // Button click handlers for (var j = 0; j < self.buttons.length; j++) { (function (button) { button.bg.down = function (x, y, obj) { handleStartScreenButton(button.type); }; button.text.down = function (x, y, obj) { handleStartScreenButton(button.type); }; })(self.buttons[j]); } return self; }); var StoreScreen = Container.expand(function () { var self = Container.call(this); // Create background var bg = LK.getAsset('energyBarBg', { width: 2048, height: 2732, anchorX: 0, anchorY: 0 }); bg.tint = 0x2C3E50; bg.alpha = 0.95; self.addChild(bg); // Title var titleText = new Text2('TIENDA', { size: 100, fill: 0xFFD700, font: "Impact" }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 250; self.addChild(titleText); // Nutripoints display var nutripointsDisplay = new Text2('Nutripoints: ' + (storage.totalNutripoints || 0), { size: 60, fill: 0x32CD32, font: "Impact" }); nutripointsDisplay.anchor.set(0.5, 0.5); nutripointsDisplay.x = 2048 / 2; nutripointsDisplay.y = 350; self.addChild(nutripointsDisplay); // Store reference for updates self.nutripointsDisplay = nutripointsDisplay; self.storeContainer = new Container(); self.addChild(self.storeContainer); // Bottom back button var bottomBackButton = LK.getAsset('restartButton', { width: 400, height: 100, anchorX: 0.5, anchorY: 0.5 }); bottomBackButton.tint = 0xFF6B35; bottomBackButton.x = 2048 / 2; bottomBackButton.y = 2600; self.addChild(bottomBackButton); var bottomBackText = new Text2('← VOLVER', { size: 60, fill: 0xFFFFFF, font: "Impact" }); bottomBackText.anchor.set(0.5, 0.5); bottomBackText.x = 2048 / 2; bottomBackText.y = 2600; self.addChild(bottomBackText); bottomBackButton.down = function () { showStartScreen(); }; bottomBackText.down = function () { showStartScreen(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x87CEEB }); /**** * Game Code ****/ // Game state management function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } var currentScreen = 'start'; // 'start', 'game', 'missions', 'store', 'faq' var gameStarted = false; // Track if game has been started via PLAY button var gamePaused = false; // Track if game is paused var pauseButton; var pauseMenu; var startScreen; var missionsScreen; var storeScreen; var faqScreen; // Mission system var allMissions = [{ id: "energia_20", text: "Alcanza 20 de Energía en una sola partida.", metaTotal: 20, type: "energia" }, { id: "frutas_10", text: "Atrapa 10 frutas o verduras sanas en una partida.", metaTotal: 10, type: "frutas" }, { id: "evitar_gaseosas_60", text: "Evita TODAS las gaseosas durante 60 segundos.", metaTotal: 60, type: "tiempo_sin_gaseosas" }, { id: "nutripoints_6", text: "Consigue 6 Nutripoints en total.", metaTotal: 6, type: "nutripoints_total" }, { id: "agua_5", text: "Recoge 5 botellas de agua (power-ups) en una sesión.", metaTotal: 5, type: "agua" }, { id: "partidas_3_sin_perder", text: "Juega 3 partidas seguidas sin perder una vida.", metaTotal: 3, type: "partidas_consecutivas" }, { id: "partida_3_vidas", text: "Completa una partida con al menos 3 vidas restantes.", metaTotal: 1, type: "partida_vidas" }, { id: "falsos_3_ganar", text: "Atrapa 3 alimentos 'falsos sanos' y aún así gana.", metaTotal: 3, type: "falsos_ganar" }, { id: "energia_25_2_partidas", text: "Gana 2 partidas consecutivas con Energía ≥25.", metaTotal: 2, type: "partidas_energia_25" }, { id: "tiempo_5_min", text: "Juega durante 5 min. continuos sin colapsar.", metaTotal: 300, type: "tiempo_continuo" }]; // Store items var storeItems = [{ id: "skin_rojo", nombre: "Skin Roja", costo: 5, tipo: "skin" }, { id: "skin_verde", nombre: "Skin Verde", costo: 5, tipo: "skin" }, { id: "fondo_parque", nombre: "Fondo Parque", costo: 8, tipo: "fondo" }, { id: "fondo_playa", nombre: "Fondo Playa", costo: 10, tipo: "fondo" }]; // FAQ data var faqData = [{ question: "¿Cómo se juega \"Caza-ingredientes\"?", answer: "Mueve tu avatar a izquierda y derecha y atrapa solo los alimentos saludables para sumar Energía. Evita los ultraprocesados y trampas." }, { question: "¿Para qué sirve la barra de Energía?", answer: "Representa tu nivel de salud en el juego. Si llega a 0, pierdes. Si llegas a 30, ganas Nutripoints extra." }, { question: "¿Qué son los Nutripoints y cómo se consiguen?", answer: "Son puntos que obtienes al ganar con Energía completa o cumpliendo misiones. Sirven para comprar skins y fondos en la Tienda." }, { question: "¿Cómo funciona la Tienda?", answer: "En la Tienda puedes cambiar Nutripoints por apariencias nuevas para tu avatar o fondos temáticos para el juego." }, { question: "¿Cómo se completan las misiones?", answer: "Ve a MISIONES, revisa las tareas diarias y juega hasta lograr cada objetivo. Al cumplirlas, recibes Nutripoints automáticamente." }]; // Game elements // Fake healthy foods // Junk foods // Healthy foods // Game variables // Healthy Foods - Fruits // Healthy Foods - Vegetables // Healthy Foods - Proteins & Grains // Junk Foods // Fake Healthy Foods var player; var fallingItems = []; var energy = 15; var lives = 3; var fallSpeed = 350 / 60; // 350px/s converted to pixels per frame (much faster) var lastSpeedIncrease = 0; var lastWaterSpawn = 0; var gameStartTime = 0; var foodsCaught = 0; var anxietyBombsActive = false; var lastSpawnTime = 0; var lastAnxietySpawnTime = 0; var expertMessageShown = false; var gameActive = true; // Track if game is active var expertModeTimer = 0; // Timer to track when expert mode should activate (20 seconds) var expertModeStartTime = 1200; // 20 seconds * 60 fps = 1200 frames // Nutripoints system variables and initialization function initializeNutripoints() { // Check if this is first time installation if (storage.totalNutripoints === undefined) { storage.totalNutripoints = 0; } // Check for daily login bonus var today = new Date().toISOString().split('T')[0]; // Get YYYY-MM-DD format var lastLoginDate = storage.lastLoginDate; if (lastLoginDate !== today) { // Award daily login bonus storage.totalNutripoints = (storage.totalNutripoints || 0) + 1; storage.lastLoginDate = today; // Show login bonus message (non-intrusive) if (lastLoginDate) { // Don't show on first install, only subsequent days LK.setTimeout(function () { showLoginBonusMessage(); }, 1000); } } } // Global function to add nutripoints function sumarNutriPoints(cantidad) { totalNutripoints += cantidad; storage.totalNutripoints = totalNutripoints; // Update UI immediately updateNutripointsDisplay(); } // Function to show login bonus message function showLoginBonusMessage() { if (!gameStarted) { // Only show on start screen var banner = LK.getAsset('restartButton', { width: 600, height: 80, anchorX: 0.5, anchorY: 0.5 }); banner.tint = 0x32CD32; banner.alpha = 0; banner.x = 2048 / 2; banner.y = 650; if (startScreen) { startScreen.addChild(banner); var bannerText = new Text2('¡Has ganado 1 Nutripoint por iniciar hoy!', { size: 45, fill: 0xFFFFFF, font: "Impact" }); bannerText.anchor.set(0.5, 0.5); bannerText.x = 2048 / 2; bannerText.y = 650; bannerText.alpha = 0; startScreen.addChild(bannerText); // Animate banner tween(banner, { alpha: 0.9 }, { duration: 500, onFinish: function onFinish() { LK.setTimeout(function () { tween(banner, { alpha: 0 }, { duration: 500, onFinish: function onFinish() { banner.destroy(); } }); tween(bannerText, { alpha: 0 }, { duration: 500, onFinish: function onFinish() { bannerText.destroy(); } }); }, 3000); } }); tween(bannerText, { alpha: 1 }, { duration: 500 }); } } } // Function to update nutripoints display across all screens function updateNutripointsDisplay() { // Update start screen display if (startScreen && startScreen.nutripointsDisplay) { startScreen.nutripointsDisplay.setText('Nutripoints: ' + totalNutripoints); } // Update store screen display if (storeScreen && storeScreen.nutripointsDisplay) { storeScreen.nutripointsDisplay.setText('Nutripoints: ' + totalNutripoints); } // Update game UI display if (totalNutripointsText) { totalNutripointsText.setText('Nutripoints: ' + totalNutripoints); } } // Initialize nutripoints system initializeNutripoints(); var totalNutripoints = storage.totalNutripoints || 0; var gameNutripoints = 0; // Points earned in current game // Mission tracking variables var missionManager = { activeMissions: [], gameStartTime: 0, lastGaseosaTime: 0, consecutiveWins: 0, falsosInCurrentGame: 0, consecutiveHighEnergyWins: 0, continuousPlayTime: 0 }; // Initialize mission progress from storage var missionProgress = storage.missionProgress || {}; // Food tracking variables var foodCounts = { 'apple': 0, 'banana': 0, 'hardEgg': 0, 'broccoli': 0, 'carrot': 0, 'wholeBread': 0, 'waterBottle': 0 }; // UI elements var livesText; var scoreText; var energyText; var energyBarBg; var energyBarFill; var nutripointsText; var totalNutripointsText; // Initialize UI function initializeUI() { // Energy text with larger size energyText = new Text2('Energía: 15/30', { size: 72, fill: 0xFFFFFF, font: "Impact" }); energyText.anchor.set(0, 0); LK.gui.topLeft.addChild(energyText); energyText.x = 150; energyText.y = 20; // Energy bar background energyBarBg = LK.getAsset('energyBarBg', { anchorX: 0, anchorY: 0 }); LK.gui.topLeft.addChild(energyBarBg); energyBarBg.x = 150; energyBarBg.y = 100; // Energy bar fill energyBarFill = LK.getAsset('energyBarFill', { anchorX: 0, anchorY: 0 }); LK.gui.topLeft.addChild(energyBarFill); energyBarFill.x = 150; energyBarFill.y = 100; // Lives text with larger size livesText = new Text2('Vidas: 3', { size: 84, fill: 0xFF0000, font: "Impact" }); livesText.anchor.set(1, 0); LK.gui.topRight.addChild(livesText); livesText.x = -20; livesText.y = 20; // Total Nutripoints display (made larger) totalNutripointsText = new Text2('Nutripoints: ' + totalNutripoints, { size: 72, fill: 0x32CD32, font: "Impact" }); totalNutripointsText.anchor.set(1, 0); LK.gui.topRight.addChild(totalNutripointsText); totalNutripointsText.x = -20; totalNutripointsText.y = 120; // Pause button pauseButton = LK.getAsset('pauseButton', { anchorX: 0.5, anchorY: 0.5 }); pauseButton.x = 2048 - 60; pauseButton.y = 300; LK.gui.topRight.addChild(pauseButton); var pauseText = new Text2('⏸', { size: 50, fill: 0xFFFFFF, font: "Impact" }); pauseText.anchor.set(0.5, 0.5); pauseText.x = 2048 - 60; pauseText.y = 300; LK.gui.topRight.addChild(pauseText); pauseButton.down = function () { showPauseMenu(); }; pauseText.down = function () { showPauseMenu(); }; // Score text removed } // Update UI function updateUI() { if (energyText) energyText.setText('Energía: ' + energy + '/30'); if (livesText) livesText.setText('Vidas: ' + lives); if (totalNutripointsText) totalNutripointsText.setText('Nutripoints: ' + totalNutripoints); // Score text update removed // Update energy bar fill based on current energy (0-30 range) if (energyBarFill) { var energyPercentage = energy / 30; energyBarFill.width = 400 * energyPercentage; // Change energy bar color based on energy level if (energy >= 20) { energyBarFill.tint = 0x00ff00; // Green for high energy } else if (energy >= 10) { energyBarFill.tint = 0xffff00; // Yellow for medium energy } else { energyBarFill.tint = 0xff0000; // Red for low energy } } } // Flash effect function flashScreen(color) { LK.effects.flashScreen(color, 300); } // Food arrays for variety - exactly 10 sprite types + 2 fake healthy var healthyFoods = ['banana', 'apple', 'carrot', 'broccoli', 'wholeBread', 'hardEgg']; var junkFoods = ['soda', 'chips', 'candy', 'burger']; var fakeFoods = ['cerealBar', 'flavoredYogurt']; // Spawn falling item function spawnFallingItem() { var type = 'healthy'; var specificFood = null; var rand = Math.random(); if (foodsCaught > 0 && foodsCaught % 20 === 0 && lastWaterSpawn !== foodsCaught) { type = 'water'; lastWaterSpawn = foodsCaught; } else if (rand < 0.3) { type = 'junk'; specificFood = junkFoods[Math.floor(Math.random() * junkFoods.length)]; } else if (rand < 0.5) { type = 'fake'; specificFood = fakeFoods[Math.floor(Math.random() * fakeFoods.length)]; } else { type = 'healthy'; specificFood = healthyFoods[Math.floor(Math.random() * healthyFoods.length)]; } var item = new FallingItem(type, specificFood); item.x = Math.random() * (2048 - 350) + 175; item.y = -175; fallingItems.push(item); game.addChild(item); } // Spawn anxiety bomb function spawnAnxietyBomb() { var item = new FallingItem('anxiety', null); item.x = Math.random() * (2048 - 350) + 175; item.y = -175; fallingItems.push(item); game.addChild(item); } // Helper function for player visual feedback function playerFeedback(color, duration, scaleEffect) { if (scaleEffect) { tween(player, { scaleX: 1.2, scaleY: 1.2 }, { duration: duration, onFinish: function onFinish() { tween(player, { scaleX: 1.0, scaleY: 1.0 }, { duration: duration }); } }); } else { tween(player, { tint: color }, { duration: duration, onFinish: function onFinish() { tween(player, { tint: 0xFFFFFF }, { duration: duration }); } }); } } // Helper function for vibration feedback function vibrateDevice() { if (navigator && navigator.vibrate) { navigator.vibrate(100); } } // Handle item collision function handleItemCollision(item) { switch (item.type) { case 'healthy': energy = Math.min(30, energy + 1); // Score increment removed LK.getSound('ping').play(); flashScreen(0x32CD32); playerFeedback(0x32CD32, 100, false); foodsCaught++; // Track healthy food counts if (item.specificFood && foodCounts.hasOwnProperty(item.specificFood)) { foodCounts[item.specificFood]++; } // Emit mission event missionManagerInstance.emitEvent("fruta_atrapada", {}); missionManagerInstance.emitEvent("energia_updated", { energia: energy }); break; case 'junk': lives--; energy = Math.max(0, energy - 2); LK.getSound('buzz').play(); vibrateDevice(); flashScreen(0xFF4500); playerFeedback(0xFF4500, 100, false); // Emit mission event for soda specifically if (item.specificFood === 'soda') { var gameTime = (LK.ticks - gameStartTime) / 60; missionManagerInstance.emitEvent("gaseosa_atrapada", { gameTime: gameTime }); } missionManagerInstance.emitEvent("energia_updated", { energia: energy }); break; case 'fake': energy = Math.max(0, energy - 2); LK.getSound('buzz').play(); vibrateDevice(); flashScreen(0xFFD700); playerFeedback(0xFFD700, 100, false); missionManager.falsosInCurrentGame++; missionManagerInstance.emitEvent("energia_updated", { energia: energy }); break; case 'water': energy = Math.min(30, energy + 3); // Score increment removed LK.getSound('powerup').play(); flashScreen(0x00BFFF); playerFeedback(0x00BFFF, 150, true); // Track water bottle counts foodCounts['waterBottle']++; // Emit mission events missionManagerInstance.emitEvent("agua_atrapada", {}); missionManagerInstance.emitEvent("energia_updated", { energia: energy }); break; case 'anxiety': energy = Math.max(0, energy - 5); LK.getSound('explosion').play(); vibrateDevice(); flashScreen(0x8B008B); playerFeedback(0x8B008B, 300, false); missionManagerInstance.emitEvent("energia_updated", { energia: energy }); break; } // Update nutripoints mission missionManagerInstance.emitEvent("nutripoints_updated", { total: totalNutripoints }); } // Initialize game function initializeGame() { gameStartTime = LK.ticks; // Initialize mission tracking for this game missionManager.gameStartTime = gameStartTime; missionManager.falsosInCurrentGame = 0; // Create player player = new Player(); player.x = 2048 / 2; player.y = 2732 - 100; game.addChild(player); // Initialize UI initializeUI(); updateUI(); } // Game input handling game.down = function (x, y, obj) { if (!player) return; // Check if player exists var gamePos = game.toLocal({ x: x, y: y }); player.moveTo(gamePos.x); }; game.move = function (x, y, obj) { if (!player) return; // Check if player exists var gamePos = game.toLocal({ x: x, y: y }); player.moveTo(gamePos.x); }; // Main game update loop game.update = function () { // Don't update game logic if game hasn't started, is not active, or is paused if (!gameStarted || !gameActive || gamePaused) { return; } var currentTime = LK.ticks; var gameTime = (currentTime - gameStartTime) / 60; // Convert to seconds // Increase speed every 15 seconds if (gameTime - lastSpeedIncrease >= 15) { fallSpeed += 20 / 60; // Increase by 20px/s (double the previous increment) lastSpeedIncrease = gameTime; } // Increment expert mode timer expertModeTimer++; // Activate anxiety bombs after 20 seconds (1200 frames) if (expertModeTimer >= expertModeStartTime && !anxietyBombsActive) { anxietyBombsActive = true; lastAnxietySpawnTime = currentTime; // Only show expert message when expert mode activates if (expertModeTimer >= expertModeStartTime && !expertMessageShown) { expertMessageShown = true; // Create full screen overlay for expert message var expertOverlay = LK.getAsset('basket', { width: 2048, height: 2732, anchorX: 0, anchorY: 0 }); expertOverlay.tint = 0x000000; expertOverlay.alpha = 0.9; game.addChild(expertOverlay); // Show expert challenge message with attractive styling var expertText = new Text2('¡RETO EXPERTO!', { size: 150, fill: 0xFFD700, font: "Impact" }); expertText.anchor.set(0.5, 0.5); expertText.x = 2048 / 2; expertText.y = 2732 / 2 - 100; game.addChild(expertText); // Add subtitle text var subtitleText = new Text2('¡Los alimentos caen más rápido!', { size: 75, fill: 0xFF4500, font: "Impact" }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 2048 / 2; subtitleText.y = 2732 / 2 + 50; game.addChild(subtitleText); // Animate expert message with pulsing effect tween(expertText, { scaleX: 1.2, scaleY: 1.2 }, { duration: 500, easing: tween.easeInOut, onFinish: function onFinish() { tween(expertText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 500, easing: tween.easeInOut }); } }); // Animate and remove message after 4 seconds tween(expertOverlay, { alpha: 0 }, { duration: 4000, onFinish: function onFinish() { expertOverlay.destroy(); } }); tween(expertText, { alpha: 0 }, { duration: 4000, onFinish: function onFinish() { expertText.destroy(); } }); tween(subtitleText, { alpha: 0 }, { duration: 4000, onFinish: function onFinish() { subtitleText.destroy(); } }); } } // Spawn items every 1.5 seconds if (currentTime - lastSpawnTime >= 90) { // 1.5 * 60 = 90 frames // Spawn 2-3 items at once for more food variety var itemsToSpawn = 2 + Math.floor(Math.random() * 2); // 2 or 3 items for (var s = 0; s < itemsToSpawn; s++) { spawnFallingItem(); } lastSpawnTime = currentTime; } // Spawn anxiety bombs every 40 seconds after activation if (anxietyBombsActive && currentTime - lastAnxietySpawnTime >= 2400) { // 40 * 60 = 2400 frames spawnAnxietyBomb(); lastAnxietySpawnTime = currentTime; } // Update falling items for (var i = fallingItems.length - 1; i >= 0; i--) { var item = fallingItems[i]; // Check collision with player if (item.intersects(player)) { handleItemCollision(item); item.destroy(); fallingItems.splice(i, 1); continue; } // Remove items that fall off screen if (item.y > 2732 + 350) { item.destroy(); fallingItems.splice(i, 1); } } // Update UI updateUI(); // Emit frame update for missions if (gameActive && gameStarted) { var gameTime = (LK.ticks - gameStartTime) / 60; missionManagerInstance.emitEvent("frame_update", { gameTime: gameTime }); } // Check game over conditions if (energy >= 30) { // Store final stats for victory storage.finalEnergy = energy; storage.finalTime = Math.floor(gameTime); storage.gameEndReason = 'victoria'; // Track mission progress for winning with high energy missionManager.consecutiveWins++; if (energy >= 25) { missionManager.consecutiveHighEnergyWins++; } storage.consecutiveWins = missionManager.consecutiveWins; storage.consecutiveHighEnergyWins = missionManager.consecutiveHighEnergyWins; gameActive = false; // Stop game updates showVictoryMessage(); } else if (lives <= 0) { // Store final stats when lives reach 0 storage.finalEnergy = energy; storage.finalTime = Math.floor(gameTime); storage.gameEndReason = 'colapso'; // Reset consecutive wins on game over missionManager.consecutiveWins = 0; missionManager.consecutiveHighEnergyWins = 0; storage.consecutiveWins = 0; storage.consecutiveHighEnergyWins = 0; gameActive = false; // Stop game updates showGameOver(); } else if (energy <= 0) { // Store final stats storage.finalEnergy = energy; storage.finalTime = Math.floor(gameTime); storage.gameEndReason = 'fatiga'; // Reset consecutive wins on game over missionManager.consecutiveWins = 0; missionManager.consecutiveHighEnergyWins = 0; storage.consecutiveWins = 0; storage.consecutiveHighEnergyWins = 0; gameActive = false; // Stop game updates showCustomGameOver(); } }; // Get nutritional information for the most caught food function getNutritionalInfo() { var maxCount = 0; var mostCaughtFood = null; // Find the food with highest count for (var food in foodCounts) { if (foodCounts[food] > maxCount) { maxCount = foodCounts[food]; mostCaughtFood = food; } } if (!mostCaughtFood || maxCount === 0) { return { title: "¡Sigue practicando!", info: "Intenta atrapar más alimentos saludables la próxima vez." }; } var nutritionalData = { 'apple': { title: "Manzana (1 unidad mediana)", info: "✅ Rica en fibra (4g), mejora la digestión.\n✅ Aporta vitamina C (8% de la recomendación diaria).\n✅ Tiene antioxidantes que protegen las células.\n⚖️ Solo 95 kcal y 0 grasa." }, 'banana': { title: "Plátano (1 unidad mediana)", info: "✅ Rico en potasio (400–450 mg), ideal para los músculos.\n✅ Contiene vitamina B6, que ayuda al sistema nervioso.\n✅ Da energía rápida gracias a sus azúcares naturales." }, 'hardEgg': { title: "Huevo duro (1 unidad)", info: "✅ Aporta proteínas completas (6g por huevo).\n✅ Rico en colina, esencial para la memoria y el cerebro.\n✅ Contiene vitamina D y hierro.\n⚠️ Contiene algo de colesterol, pero no es dañino en jóvenes sanos." }, 'broccoli': { title: "Brócoli (1 taza cocida)", info: "✅ Altísimo en vitamina C y vitamina K.\n✅ Fuente de fibra y antioxidantes.\n✅ Tiene compuestos que ayudan a prevenir el cáncer." }, 'carrot': { title: "Zanahoria (1 mediana cruda)", info: "✅ Altísima en betacaroteno (vitamina A), buena para la vista.\n✅ Solo 25 kcal y con fibra.\n✅ Rica en antioxidantes, fortalece el sistema inmune." }, 'wholeBread': { title: "Pan integral (1 rebanada)", info: "✅ Buena fuente de fibra (2–3 g por porción).\n✅ Aporta carbohidratos complejos que dan energía duradera.\n✅ Tiene hierro y vitaminas del grupo B." }, 'waterBottle': { title: "Agua (1 vaso / 240ml)", info: "✅ Hidratación esencial para todo el cuerpo.\n✅ Regula la temperatura, transporta nutrientes y limpia toxinas.\n✅ 0 calorías, 0 azúcar, 100% necesaria." } }; return nutritionalData[mostCaughtFood] || { title: "¡Sigue practicando!", info: "Intenta atrapar más alimentos saludables la próxima vez." }; } // Show victory message when energy reaches 30 function showVictoryMessage() { var finalTime = storage.finalTime || Math.floor((LK.ticks - gameStartTime) / 60); // Emit mission events for winning the game missionManagerInstance.emitEvent("partida_ganada", { energia: energy, vidasRestantes: lives }); // Award Nutripoints only for reaching maximum energy if (energy >= 30) { gameNutripoints = 2; // Award 2 Nutripoints for completing with max energy sumarNutriPoints(gameNutripoints); } // Create full screen overlay var overlay = LK.getAsset('energyBarBg', { width: 2048, height: 2732, anchorX: 0, anchorY: 0 }); overlay.tint = 0x000000; overlay.alpha = 0.9; game.addChild(overlay); // Victory title var titleText = new Text2('¡FELICITACIONES!', { size: 120, fill: 0xFFD700, font: "Impact" }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 400; game.addChild(titleText); // Victory message var messageText = new Text2('¡Alcanzaste el nivel máximo de energía saludable!', { size: 70, fill: 0x32CD32, font: "Impact" }); messageText.anchor.set(0.5, 0.5); messageText.x = 2048 / 2; messageText.y = 600; game.addChild(messageText); // Additional message lines var message2Text = new Text2('Tu cuerpo y tu mente están listas para todo.', { size: 60, fill: 0x00BFFF, font: "Impact" }); message2Text.anchor.set(0.5, 0.5); message2Text.x = 2048 / 2; message2Text.y = 750; game.addChild(message2Text); var message3Text = new Text2('Elegiste bien, vivís mejor.', { size: 60, fill: 0xFF69B4, font: "Impact" }); message3Text.anchor.set(0.5, 0.5); message3Text.x = 2048 / 2; message3Text.y = 900; game.addChild(message3Text); // Score section removed // Time played section var timeText = new Text2('Tiempo jugado: ' + finalTime + ' segundos', { size: 60, fill: 0xFFFFFF, font: "Impact" }); timeText.anchor.set(0.5, 0.5); timeText.x = 2048 / 2; timeText.y = 1100; game.addChild(timeText); // Nutripoints message var gameNutripointsText = new Text2('¡Ganaste 2 Nutripoints por llegar al máximo de energía!', { size: 65, fill: 0x32CD32, font: "Impact" }); gameNutripointsText.anchor.set(0.5, 0.5); gameNutripointsText.x = 2048 / 2; gameNutripointsText.y = 1200; game.addChild(gameNutripointsText); var totalNutripointsText = new Text2('Total acumulado: ' + totalNutripoints + ' Nutripoints', { size: 55, fill: 0xFFD700, font: "Impact" }); totalNutripointsText.anchor.set(0.5, 0.5); totalNutripointsText.x = 2048 / 2; totalNutripointsText.y = 1300; game.addChild(totalNutripointsText); // Create animated restart button var restartButton = LK.getAsset('restartButton', { width: 700, height: 140, color: 0x32CD32, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); restartButton.x = 2048 / 2; restartButton.y = 1600; game.addChild(restartButton); var restartText = new Text2('Jugar de nuevo', { size: 80, fill: 0xFFFFFF, font: "Impact" }); restartText.anchor.set(0.5, 0.5); restartText.x = 2048 / 2; restartText.y = 1600; game.addChild(restartText); // Animate button with pulsing effect function animateVictoryRestartButton() { tween(restartButton, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(restartButton, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut, onFinish: animateVictoryRestartButton }); } }); tween(restartText, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(restartText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut }); } }); } animateVictoryRestartButton(); // Add click handler for restart restartButton.down = function () { showStartScreen(); }; restartText.down = function () { showStartScreen(); }; } // Show game over message when lives reach 0 function showGameOver() { var finalTime = storage.finalTime || Math.floor((LK.ticks - gameStartTime) / 60); // No Nutripoints awarded when not reaching maximum energy // Create full screen overlay var overlay = LK.getAsset('energyBarBg', { width: 2048, height: 2732, anchorX: 0, anchorY: 0 }); overlay.tint = 0x000000; overlay.alpha = 0.9; game.addChild(overlay); // Game Over title var gameOverText = new Text2('GAME OVER', { size: 150, fill: 0xFF0000, font: "Impact" }); gameOverText.anchor.set(0.5, 0.5); gameOverText.x = 2048 / 2; gameOverText.y = 600; game.addChild(gameOverText); // Score section removed // Time played section var timeText = new Text2('Tiempo jugado: ' + finalTime + ' segundos', { size: 60, fill: 0xFFFFFF, font: "Impact" }); timeText.anchor.set(0.5, 0.5); timeText.x = 2048 / 2; timeText.y = 800; game.addChild(timeText); // Nutripoints encouragement message var nutripointsEncourageText = new Text2('¡Sigue eligiendo bien para ganar Nutripoints!', { size: 65, fill: 0xFFD700, font: "Impact" }); nutripointsEncourageText.anchor.set(0.5, 0.5); nutripointsEncourageText.x = 2048 / 2; nutripointsEncourageText.y = 900; game.addChild(nutripointsEncourageText); // Add nutritional information section var mostConsumedText = new Text2('Alimento que más consumiste en esta partida', { size: 70, fill: 0x32CD32, font: "Impact" }); mostConsumedText.anchor.set(0.5, 0.5); mostConsumedText.x = 2048 / 2; mostConsumedText.y = 1050; game.addChild(mostConsumedText); var nutritionalInfo = getNutritionalInfo(); var nutritionTitleText = new Text2(nutritionalInfo.title, { size: 80, fill: 0xFFD700, font: "Impact" }); nutritionTitleText.anchor.set(0.5, 0.5); nutritionTitleText.x = 2048 / 2; nutritionTitleText.y = 1200; game.addChild(nutritionTitleText); var nutritionInfoText = new Text2(nutritionalInfo.info, { size: 55, fill: 0xFFFFFF, font: "Impact" }); nutritionInfoText.anchor.set(0.5, 0); nutritionInfoText.x = 2048 / 2; nutritionInfoText.y = 1250; game.addChild(nutritionInfoText); // Create animated restart button var restartButton = LK.getAsset('restartButton', { width: 700, height: 140, color: 0x32CD32, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); restartButton.x = 2048 / 2; restartButton.y = 1650; game.addChild(restartButton); var restartText = new Text2('Jugar de nuevo', { size: 80, fill: 0xFFFFFF, font: "Impact" }); restartText.anchor.set(0.5, 0.5); restartText.x = 2048 / 2; restartText.y = 1650; game.addChild(restartText); // Animate button with pulsing effect function animateGameOverRestartButton() { tween(restartButton, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(restartButton, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut, onFinish: animateGameOverRestartButton }); } }); tween(restartText, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(restartText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut }); } }); } animateGameOverRestartButton(); // Add click handler for restart restartButton.down = function () { showStartScreen(); }; restartText.down = function () { showStartScreen(); }; } // Show custom game over message for energy depletion function showCustomGameOver() { var finalEnergy = storage.finalEnergy || energy; var finalTime = storage.finalTime || Math.floor((LK.ticks - gameStartTime) / 60); var reason = storage.gameEndReason || 'fatiga'; var message = ''; if (finalEnergy >= 25) { message = '¡NutriMáster!'; } else if (finalEnergy >= 15) { message = '¡Buen cazador de nutrientes!'; } else { message = 'Sigue practicando, revisa tus elecciones'; } // No Nutripoints awarded when not reaching maximum energy // Create full screen overlay var overlay = LK.getAsset('energyBarBg', { width: 2048, height: 2732, anchorX: 0, anchorY: 0 }); overlay.tint = 0x000000; overlay.alpha = 0.9; game.addChild(overlay); // Title var titleText = new Text2('FATIGA, FALTA DE ENERGÍA', { size: 100, fill: 0xFFD700, font: "Impact" }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 400; game.addChild(titleText); // Score section removed // Time played section var timeText = new Text2('Tiempo jugado: ' + finalTime + ' segundos', { size: 70, fill: 0x00BFFF, font: "Impact" }); timeText.anchor.set(0.5, 0.5); timeText.x = 2048 / 2; timeText.y = 700; game.addChild(timeText); // Nutripoints encouragement message var nutripointsEncourageText = new Text2('¡Sigue eligiendo bien para ganar Nutripoints!', { size: 65, fill: 0xFFD700, font: "Impact" }); nutripointsEncourageText.anchor.set(0.5, 0.5); nutripointsEncourageText.x = 2048 / 2; nutripointsEncourageText.y = 800; game.addChild(nutripointsEncourageText); // Message section with color based on performance var messageColor = 0xFFFFFF; if (finalEnergy >= 25) { messageColor = 0xFFD700; // Gold for NutriMaster } else if (finalEnergy >= 15) { messageColor = 0x32CD32; // Green for good hunter } else { messageColor = 0xFF4500; // Orange for keep practicing } var messageText = new Text2(message, { size: 80, fill: messageColor, font: "Impact" }); messageText.anchor.set(0.5, 0.5); messageText.x = 2048 / 2; messageText.y = 900; game.addChild(messageText); // Add nutritional information section var mostConsumedText = new Text2('Alimento que más consumiste en esta partida', { size: 70, fill: 0x32CD32, font: "Impact" }); mostConsumedText.anchor.set(0.5, 0.5); mostConsumedText.x = 2048 / 2; mostConsumedText.y = 1000; game.addChild(mostConsumedText); var nutritionalInfo = getNutritionalInfo(); var nutritionTitleText = new Text2(nutritionalInfo.title, { size: 80, fill: 0xFFD700, font: "Impact" }); nutritionTitleText.anchor.set(0.5, 0.5); nutritionTitleText.x = 2048 / 2; nutritionTitleText.y = 1150; game.addChild(nutritionTitleText); var nutritionInfoText = new Text2(nutritionalInfo.info, { size: 55, fill: 0xFFFFFF, font: "Impact" }); nutritionInfoText.anchor.set(0.5, 0); nutritionInfoText.x = 2048 / 2; nutritionInfoText.y = 1200; game.addChild(nutritionInfoText); // Create animated restart button var restartButton = LK.getAsset('restartButton', { width: 700, height: 140, color: 0x32CD32, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); restartButton.x = 2048 / 2; restartButton.y = 1600; game.addChild(restartButton); var restartText = new Text2('Jugar de nuevo', { size: 80, fill: 0xFFFFFF, font: "Impact" }); restartText.anchor.set(0.5, 0.5); restartText.x = 2048 / 2; restartText.y = 1600; game.addChild(restartText); // Animate button with pulsing effect function animateRestartButton() { tween(restartButton, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(restartButton, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut, onFinish: animateRestartButton }); } }); tween(restartText, { scaleX: 1.1, scaleY: 1.1 }, { duration: 800, easing: tween.easeInOut, onFinish: function onFinish() { tween(restartText, { scaleX: 1.0, scaleY: 1.0 }, { duration: 800, easing: tween.easeInOut }); } }); } animateRestartButton(); // Add click handler for restart restartButton.down = function () { showStartScreen(); }; restartText.down = function () { showStartScreen(); }; } // Start countdown and restart game function startCountdown() { // Clear all game objects for (var i = fallingItems.length - 1; i >= 0; i--) { fallingItems[i].destroy(); } fallingItems = []; game.removeChildren(); // Reset all game variables energy = 15; lives = 3; fallSpeed = 350 / 60; lastSpeedIncrease = 0; lastWaterSpawn = 0; gameStartTime = 0; foodsCaught = 0; anxietyBombsActive = false; lastSpawnTime = 0; lastAnxietySpawnTime = 0; expertMessageShown = false; gameActive = true; // Reactivate game gameStarted = true; // Ensure game logic runs during countdown and game expertModeTimer = 0; // Reset expert mode timer gameNutripoints = 0; // Reset current game Nutripoints // Score reset removed // Clear GUI elements to reset them properly LK.gui.topLeft.removeChildren(); LK.gui.topRight.removeChildren(); LK.gui.top.removeChildren(); // Reset UI variable references totalNutripointsText = null; pauseButton = null; // Reset food counts foodCounts = { 'apple': 0, 'banana': 0, 'hardEgg': 0, 'broccoli': 0, 'carrot': 0, 'wholeBread': 0, 'waterBottle': 0 }; // Show countdown var countdownNumbers = [3, 2, 1]; var currentCount = 0; function showCountdownNumber() { if (currentCount < countdownNumbers.length) { var countText = new Text2(countdownNumbers[currentCount].toString(), { size: 250, fill: 0xFFFF00, font: "Impact" }); countText.anchor.set(0.5, 0.5); countText.x = 2048 / 2; countText.y = 2732 / 2; game.addChild(countText); // Animate countdown number tween(countText, { scaleX: 1.5, scaleY: 1.5, alpha: 0 }, { duration: 1000, onFinish: function onFinish() { countText.destroy(); currentCount++; if (currentCount < countdownNumbers.length) { showCountdownNumber(); } else { // Start new game initializeGame(); // Force UI update after initialization to show correct values updateUI(); } } }); } } showCountdownNumber(); } // Screen management functions function showStartScreen() { currentScreen = 'start'; gameStarted = false; // Reset game started state gamePaused = false; // Reset pause state game.removeChildren(); LK.gui.topLeft.removeChildren(); LK.gui.topRight.removeChildren(); if (!startScreen) { startScreen = new StartScreen(); } game.addChild(startScreen); } function handleStartScreenButton(buttonType) { switch (buttonType) { case 'PLAY': // Find the PLAY button and animate it for (var i = 0; i < startScreen.buttons.length; i++) { if (startScreen.buttons[i].type === 'PLAY') { var playButton = startScreen.buttons[i]; // Set gameStarted immediately to enable game logic gameStarted = true; // Animate button press tween(playButton.bg, { scaleX: 0.95, scaleY: 0.95, tint: 0x228B22 }, { duration: 150, onFinish: function onFinish() { tween(playButton.bg, { scaleX: 1.0, scaleY: 1.0, tint: 0x32CD32 }, { duration: 150, onFinish: function onFinish() { // Start game immediately after animation startGame(); } }); } }); tween(playButton.text, { scaleX: 0.95, scaleY: 0.95 }, { duration: 150, onFinish: function onFinish() { tween(playButton.text, { scaleX: 1.0, scaleY: 1.0 }, { duration: 150 }); } }); break; } } break; case 'MISIONES': showMissionsScreen(); break; case 'TIENDA': showStoreScreen(); break; case 'PREGUNTAS': showFAQScreen(); break; } } function startGame() { currentScreen = 'game'; game.removeChildren(); startCountdown(); } function showMissionsScreen() { currentScreen = 'missions'; game.removeChildren(); LK.gui.topLeft.removeChildren(); LK.gui.topRight.removeChildren(); if (!missionsScreen) { missionsScreen = new MissionsScreen(); } game.addChild(missionsScreen); updateMissionsDisplay(); } function showStoreScreen() { currentScreen = 'store'; game.removeChildren(); LK.gui.topLeft.removeChildren(); LK.gui.topRight.removeChildren(); if (!storeScreen) { storeScreen = new StoreScreen(); } game.addChild(storeScreen); updateStoreDisplay(); } function showFAQScreen() { currentScreen = 'faq'; game.removeChildren(); LK.gui.topLeft.removeChildren(); LK.gui.topRight.removeChildren(); if (!faqScreen) { faqScreen = new FAQScreen(); } game.addChild(faqScreen); updateFAQDisplay(); } // Mission system functions - handled by MissionManager class function updateMissionsDisplay() { if (!missionsScreen) return; missionsScreen.missionsContainer.removeChildren(); missionsScreen.progressBars = []; // Ensure missionManager and its activeMissions exist if (!missionManager || !missionManager.activeMissions) { if (missionManagerInstance) { missionManagerInstance.generateNewDailyMissions(); } } var activeMissions = null; // Safe access to activeMissions with multiple checks if (missionManager && missionManager.activeMissions && Array.isArray(missionManager.activeMissions)) { activeMissions = missionManager.activeMissions; } else if (missionManagerInstance && missionManagerInstance.activeMissions && Array.isArray(missionManagerInstance.activeMissions)) { activeMissions = missionManagerInstance.activeMissions; } else { activeMissions = []; } if (!activeMissions || activeMissions.length === 0) { if (missionManagerInstance) { missionManagerInstance.generateNewDailyMissions(); // Re-check after generation with safe access if (missionManager && missionManager.activeMissions && Array.isArray(missionManager.activeMissions)) { activeMissions = missionManager.activeMissions; } else if (missionManagerInstance && missionManagerInstance.activeMissions && Array.isArray(missionManagerInstance.activeMissions)) { activeMissions = missionManagerInstance.activeMissions; } else { activeMissions = []; } } } // Final safety check after all attempts if (!activeMissions || !Array.isArray(activeMissions) || activeMissions.length === 0) { // Create default empty state display var noMissionsText = new Text2('No hay misiones disponibles', { size: 60, fill: 0xFFFFFF, font: "Impact" }); noMissionsText.anchor.set(0.5, 0.5); noMissionsText.x = 2048 / 2; noMissionsText.y = 200; missionsScreen.missionsContainer.addChild(noMissionsText); return; } // Additional validation: check if array elements exist and are accessible var validMissionsCount = 0; if (activeMissions && Array.isArray(activeMissions) && activeMissions.length > 0) { for (var checkIndex = 0; checkIndex < activeMissions.length; checkIndex++) { if (checkIndex < activeMissions.length && activeMissions[checkIndex] && _typeof(activeMissions[checkIndex]) === 'object') { validMissionsCount++; } } } if (validMissionsCount === 0) { var noValidMissionsText = new Text2('Error: No se pudieron cargar las misiones', { size: 60, fill: 0xFF6B35, font: "Impact" }); noValidMissionsText.anchor.set(0.5, 0.5); noValidMissionsText.x = 2048 / 2; noValidMissionsText.y = 200; missionsScreen.missionsContainer.addChild(noValidMissionsText); return; } // Final safety check before loop if (!activeMissions || !Array.isArray(activeMissions) || activeMissions.length === 0) { return; } for (var i = 0; i < activeMissions.length; i++) { // Comprehensive safety check for array bounds and element existence if (!activeMissions || !Array.isArray(activeMissions) || i >= activeMissions.length) { continue; } // Safe access to array element with additional validation var mission = null; try { if (activeMissions[i] !== undefined && activeMissions[i] !== null) { mission = activeMissions[i]; } else { continue; } } catch (e) { continue; } // Safety check for mission object if (!mission || _typeof(mission) !== 'object') { continue; } // Ensure mission has required properties if (!mission.text || typeof mission.metaTotal === 'undefined' || typeof mission.avanceActual === 'undefined') { continue; } var missionBg = LK.getAsset('restartButton', { width: 1800, height: 280, anchorX: 0.5, anchorY: 0.5 }); missionBg.tint = mission.completada ? 0x27AE60 : 0x34495E; missionBg.x = 2048 / 2; missionBg.y = 50 + i * 320; // Adjusted Y position to start from 0 in scrollable container missionsScreen.missionsContainer.addChild(missionBg); var missionText = new Text2((mission.completada ? '✔️ ' : '') + mission.text, { size: 55, fill: 0xFFFFFF, font: "Impact" }); missionText.anchor.set(0.5, 0.5); missionText.x = 2048 / 2; missionText.y = 30 + i * 320; // Adjusted Y position missionsScreen.missionsContainer.addChild(missionText); // Progress bar background var progressBg = LK.getAsset('energyBarBg', { width: 450, height: 25, anchorX: 0.5, anchorY: 0.5 }); progressBg.tint = 0x666666; progressBg.alpha = 0.4; progressBg.x = 2048 / 2 - 225; progressBg.y = 100 + i * 320; // Adjusted Y position missionsScreen.missionsContainer.addChild(progressBg); // Progress bar fill var progressWidth = mission.avanceActual / mission.metaTotal * 450; var progressFill = LK.getAsset('energyBarFill', { width: progressWidth, height: 25, anchorX: 0, anchorY: 0.5 }); progressFill.tint = 0x4CAF50; progressFill.x = 2048 / 2 - 225; progressFill.y = 100 + i * 320; // Adjusted Y position missionsScreen.missionsContainer.addChild(progressFill); missionsScreen.progressBars.push(progressFill); // Progress text var progressText = new Text2(mission.avanceActual + ' / ' + mission.metaTotal, { size: 45, fill: 0xFFFFFF, font: "Impact" }); progressText.anchor.set(0.5, 0.5); progressText.x = 2048 / 2 + 250; progressText.y = 100 + i * 320; // Adjusted Y position missionsScreen.missionsContainer.addChild(progressText); if (mission.completada) { var rewardText = new Text2('Completada ✔️ +2 Nutripoints', { size: 45, fill: 0xFFD700, font: "Impact" }); rewardText.anchor.set(0.5, 0.5); rewardText.x = 2048 / 2; rewardText.y = 140 + i * 320; // Adjusted Y position missionsScreen.missionsContainer.addChild(rewardText); } } // Update scroll bounds after adding all missions if (missionsScreen.updateScrollBounds) { missionsScreen.updateScrollBounds(); } } // Store system functions function updateStoreDisplay() { if (!storeScreen) return; storeScreen.storeContainer.removeChildren(); var playerNutripoints = storage.totalNutripoints || 0; var ownedItems = storage.ownedItems || []; for (var i = 0; i < storeItems.length; i++) { var item = storeItems[i]; var owned = ownedItems.indexOf(item.id) !== -1; var canAfford = playerNutripoints >= item.costo; var itemBg = LK.getAsset('restartButton', { width: 700, height: 150, anchorX: 0.5, anchorY: 0.5 }); itemBg.tint = owned ? 0x27AE60 : canAfford ? 0x3498DB : 0x95A5A6; itemBg.x = i % 2 * 800 + 500; itemBg.y = 500 + Math.floor(i / 2) * 200; storeScreen.storeContainer.addChild(itemBg); var nameText = new Text2(item.nombre, { size: 45, fill: 0xFFFFFF, font: "Impact" }); nameText.anchor.set(0.5, 0.5); nameText.x = itemBg.x; nameText.y = itemBg.y - 20; storeScreen.storeContainer.addChild(nameText); var costText = new Text2(owned ? 'COMPRADO' : item.costo + ' Nutripoints', { size: 35, fill: owned ? 0x2ECC71 : canAfford ? 0xFFD700 : 0xE74C3C, font: "Impact" }); costText.anchor.set(0.5, 0.5); costText.x = itemBg.x; costText.y = itemBg.y + 20; storeScreen.storeContainer.addChild(costText); if (!owned && canAfford) { itemBg.itemData = item; (function (itemData) { itemBg.down = function (x, y, obj) { purchaseItem(itemData); }; })(item); } } } function purchaseItem(item) { if (!item || typeof item.costo === 'undefined') { console.error('Invalid item data in purchaseItem'); return; } var playerNutripoints = storage.totalNutripoints || 0; var ownedItems = storage.ownedItems || []; if (playerNutripoints >= item.costo && ownedItems.indexOf(item.id) === -1) { storage.totalNutripoints = playerNutripoints - item.costo; ownedItems.push(item.id); storage.ownedItems = ownedItems; // Show purchase popup var popup = LK.getAsset('restartButton', { width: 800, height: 200, anchorX: 0.5, anchorY: 0.5 }); popup.tint = 0x27AE60; popup.x = 2048 / 2; popup.y = 2732 / 2; game.addChild(popup); var popupText = new Text2('¡Nuevo artículo desbloqueado!', { size: 60, fill: 0xFFFFFF, font: "Impact" }); popupText.anchor.set(0.5, 0.5); popupText.x = 2048 / 2; popupText.y = 2732 / 2; game.addChild(popupText); LK.getSound('powerup').play(); // Remove popup after 2 seconds LK.setTimeout(function () { popup.destroy(); popupText.destroy(); updateStoreDisplay(); }, 2000); } } // FAQ system functions function updateFAQDisplay() { if (!faqScreen) return; // Initialize FAQ items with accordion functionality faqScreen.createFAQItems(); } // Initialize mission manager var missionManagerInstance = new MissionManager(); missionManagerInstance.init(); // Initialize mission tracking variables properly missionManager.gameStartTime = 0; missionManager.lastGaseosaTime = -60; // Start with -60 to allow immediate tracking missionManager.consecutiveWins = storage.consecutiveWins || 0; missionManager.falsosInCurrentGame = 0; missionManager.consecutiveHighEnergyWins = storage.consecutiveHighEnergyWins || 0; missionManager.continuousPlayTime = storage.continuousPlayTime || 0; // Initialize storage for persistent data totalNutripoints = storage.totalNutripoints || 0; // Pause menu functions function showPauseMenu() { if (!gameStarted || !gameActive) return; gamePaused = true; // Create overlay var overlay = LK.getAsset('energyBarBg', { width: 2048, height: 2732, anchorX: 0, anchorY: 0 }); overlay.tint = 0x000000; overlay.alpha = 0.8; game.addChild(overlay); // Pause menu container pauseMenu = new Container(); game.addChild(pauseMenu); // Title var titleText = new Text2('JUEGO PAUSADO', { size: 120, fill: 0xFFD700, font: "Impact" }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 800; pauseMenu.addChild(titleText); // Buttons data var buttonData = [{ text: 'REANUDAR', y: 1100, color: 0x27AE60, action: 'resume' }, { text: 'REINICIAR', y: 1300, color: 0xF39C12, action: 'restart' }, { text: 'MENÚ PRINCIPAL', y: 1500, color: 0xE74C3C, action: 'menu' }]; // Create buttons for (var i = 0; i < buttonData.length; i++) { var buttonBg = LK.getAsset('restartButton', { width: 600, height: 120, anchorX: 0.5, anchorY: 0.5 }); buttonBg.tint = buttonData[i].color; buttonBg.x = 2048 / 2; buttonBg.y = buttonData[i].y; pauseMenu.addChild(buttonBg); var buttonText = new Text2(buttonData[i].text, { size: 70, fill: 0xFFFFFF, font: "Impact" }); buttonText.anchor.set(0.5, 0.5); buttonText.x = 2048 / 2; buttonText.y = buttonData[i].y; pauseMenu.addChild(buttonText); // Add click handlers (function (action) { buttonBg.down = function () { handlePauseMenuAction(action); }; buttonText.down = function () { handlePauseMenuAction(action); }; })(buttonData[i].action); } // Store overlay reference for cleanup pauseMenu.overlay = overlay; } function handlePauseMenuAction(action) { switch (action) { case 'resume': resumeGame(); break; case 'restart': restartGame(); break; case 'menu': returnToMainMenu(); break; } } function resumeGame() { if (pauseMenu) { pauseMenu.overlay.destroy(); pauseMenu.destroy(); pauseMenu = null; } gamePaused = false; } function restartGame() { if (pauseMenu) { pauseMenu.overlay.destroy(); pauseMenu.destroy(); pauseMenu = null; } gamePaused = false; startGame(); } function returnToMainMenu() { if (pauseMenu) { pauseMenu.overlay.destroy(); pauseMenu.destroy(); pauseMenu = null; } gamePaused = false; gameActive = false; gameStarted = false; showStartScreen(); } // Initialize the start screen as the first state showStartScreen(); ;
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var FAQScreen = Container.expand(function () {
var self = Container.call(this);
// Create background
var bg = LK.getAsset('energyBarBg', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0
});
bg.tint = 0xF8F9FA;
self.addChild(bg);
// Create scrollable container for FAQ content
var scrollContainer = new Container();
self.addChild(scrollContainer);
// Title
var titleText = new Text2('PREGUNTAS FRECUENTES', {
size: 80,
fill: 0x2C3E50,
font: "Impact"
});
titleText.anchor.set(0.5, 0);
titleText.x = 2048 / 2;
titleText.y = 150;
scrollContainer.addChild(titleText);
self.faqContainer = new Container();
self.faqContainer.x = 0;
self.faqContainer.y = 300;
scrollContainer.addChild(self.faqContainer);
// FAQ state tracking
self.openFAQIndex = -1; // Track which FAQ is currently open
self.faqItems = []; // Store FAQ item references
// Create FAQ items
self.createFAQItems = function () {
self.faqContainer.removeChildren();
self.faqItems = [];
var currentY = 0;
var itemSpacing = 20;
for (var i = 0; i < faqData.length; i++) {
var faq = faqData[i];
var isOpen = self.openFAQIndex === i;
// Question container with shadow effect
var questionContainer = new Container();
questionContainer.y = currentY;
self.faqContainer.addChild(questionContainer);
// Question background with rounded appearance
var questionBg = LK.getAsset('restartButton', {
width: 1800,
height: 160,
anchorX: 0.5,
anchorY: 0
});
questionBg.tint = isOpen ? 0x3498DB : 0x34495E;
questionBg.x = 2048 / 2;
questionBg.y = 0;
questionContainer.addChild(questionBg);
// Expand/collapse icon
var iconText = new Text2(isOpen ? '⊖' : '⊕', {
size: 70,
fill: 0xFFFFFF,
font: "Impact"
});
iconText.anchor.set(0, 0.5);
iconText.x = 250;
iconText.y = 80;
questionContainer.addChild(iconText);
// Question text
var questionText = new Text2(faq.question, {
size: 58,
fill: 0xFFFFFF,
font: "Impact"
});
questionText.anchor.set(0, 0.5);
questionText.x = 350;
questionText.y = 80;
questionContainer.addChild(questionText);
// Answer container (initially hidden if not open)
var answerContainer = new Container();
answerContainer.y = 170;
answerContainer.alpha = isOpen ? 1 : 0;
answerContainer.visible = isOpen;
questionContainer.addChild(answerContainer);
// Answer background
var answerBg = LK.getAsset('restartButton', {
width: 1700,
height: isOpen ? 240 : 0,
anchorX: 0.5,
anchorY: 0
});
answerBg.tint = 0xECF0F1;
answerBg.x = 2048 / 2;
answerBg.y = 0;
answerContainer.addChild(answerBg);
// Answer text with proper wrapping
var answerText = new Text2(faq.answer, {
size: 50,
fill: 0x2C3E50,
font: "Impact",
wordWrap: true,
wordWrapWidth: 1600
});
answerText.anchor.set(0.5, 0);
answerText.x = 2048 / 2;
answerText.y = 30;
answerContainer.addChild(answerText);
// Store references
var faqItem = {
index: i,
questionContainer: questionContainer,
questionBg: questionBg,
iconText: iconText,
answerContainer: answerContainer,
answerBg: answerBg,
isOpen: isOpen
};
self.faqItems.push(faqItem);
// Add click handlers with closure
(function (itemIndex) {
questionBg.down = function () {
self.toggleFAQ(itemIndex);
};
iconText.down = function () {
self.toggleFAQ(itemIndex);
};
questionText.down = function () {
self.toggleFAQ(itemIndex);
};
})(i);
// Calculate next Y position
currentY += 160 + itemSpacing;
if (isOpen) {
currentY += 240 + itemSpacing;
}
}
};
// Toggle FAQ open/close
self.toggleFAQ = function (index) {
if (index === self.openFAQIndex) {
// Close currently open FAQ
self.closeFAQ(index);
self.openFAQIndex = -1;
} else {
// Close currently open FAQ if any
if (self.openFAQIndex >= 0) {
self.closeFAQ(self.openFAQIndex);
}
// Open new FAQ
self.openFAQ(index);
self.openFAQIndex = index;
}
};
// Open FAQ with animation
self.openFAQ = function (index) {
var item = self.faqItems[index];
if (!item) return;
// Update icon and background color
item.iconText.setText('⊖');
tween(item.questionBg, {
tint: 0x3498DB
}, {
duration: 200
});
// Show and animate answer container
item.answerContainer.visible = true;
item.answerContainer.alpha = 0;
// Animate answer background height
tween(item.answerBg, {
height: 240
}, {
duration: 300,
easing: tween.easeOut
});
// Fade in answer container
tween(item.answerContainer, {
alpha: 1
}, {
duration: 250,
onFinish: function onFinish() {
// Recreate all items to adjust positions
LK.setTimeout(function () {
self.createFAQItems();
}, 50);
}
});
};
// Close FAQ with animation
self.closeFAQ = function (index) {
var item = self.faqItems[index];
if (!item) return;
// Update icon and background color
item.iconText.setText('⊕');
tween(item.questionBg, {
tint: 0x34495E
}, {
duration: 200
});
// Fade out and hide answer container
tween(item.answerContainer, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
item.answerContainer.visible = false;
// Animate answer background height to 0
tween(item.answerBg, {
height: 0
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
// Recreate all items to adjust positions
LK.setTimeout(function () {
self.createFAQItems();
}, 50);
}
});
}
});
};
// Bottom back button
var bottomBackButton = LK.getAsset('restartButton', {
width: 400,
height: 100,
anchorX: 0.5,
anchorY: 0.5
});
bottomBackButton.tint = 0xFF6B35;
bottomBackButton.x = 2048 / 2;
bottomBackButton.y = 2600;
self.addChild(bottomBackButton);
var bottomBackText = new Text2('← VOLVER', {
size: 60,
fill: 0xFFFFFF,
font: "Impact"
});
bottomBackText.anchor.set(0.5, 0.5);
bottomBackText.x = 2048 / 2;
bottomBackText.y = 2600;
self.addChild(bottomBackText);
bottomBackButton.down = function () {
showStartScreen();
};
bottomBackText.down = function () {
showStartScreen();
};
return self;
});
var FallingItem = Container.expand(function (type, specificFood) {
var self = Container.call(this);
self.type = type;
self.specificFood = specificFood;
// Set different speeds based on type and add randomness
if (type === 'anxiety') {
self.speed = fallSpeed * 1.5; // Anxiety bombs fall faster
} else if (type === 'water') {
self.speed = fallSpeed * 0.8; // Water bottles fall slower
} else {
// Food items have variable speeds between 1.2x and 2.0x base speed (much faster)
var speedMultiplier = 1.2 + Math.random() * 0.8;
// Increase speed significantly during expert mode
if (anxietyBombsActive) {
speedMultiplier *= 2.2; // Make items fall 120% faster in expert mode
}
self.speed = fallSpeed * speedMultiplier;
}
var assetName = specificFood || 'waterBottle';
if (type === 'water') assetName = 'waterBottle';else if (type === 'anxiety') assetName = 'anxietyBomb';
var graphic = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.update = function () {
self.y += self.speed;
};
return self;
});
var MissionManager = Container.expand(function () {
var self = Container.call(this);
self.activeMissions = [];
self.init = function () {
self.loadActiveMissions();
};
self.loadActiveMissions = function () {
var today = new Date().toDateString();
var savedDate = storage.missionsDate;
if (savedDate !== today) {
self.generateNewDailyMissions();
} else {
var savedMissions = storage.activeMissions;
if (savedMissions && savedMissions.length > 0) {
self.activeMissions = [];
for (var i = 0; i < savedMissions.length; i++) {
self.activeMissions.push({
id: savedMissions['mission_' + i + '_id'],
text: savedMissions['mission_' + i + '_text'],
metaTotal: savedMissions['mission_' + i + '_metaTotal'],
type: savedMissions['mission_' + i + '_type'],
avanceActual: savedMissions['mission_' + i + '_avanceActual'] || 0,
completada: savedMissions['mission_' + i + '_completada'] || false
});
}
} else {
self.activeMissions = [];
}
missionManager.activeMissions = self.activeMissions;
}
};
self.generateNewDailyMissions = function () {
var shuffled = allMissions.slice();
for (var i = shuffled.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = shuffled[i];
shuffled[i] = shuffled[j];
shuffled[j] = temp;
}
self.activeMissions = shuffled.slice(0, 3).map(function (mission) {
return {
id: mission.id,
text: mission.text,
metaTotal: mission.metaTotal,
type: mission.type,
avanceActual: 0,
completada: false
};
});
missionManager.activeMissions = self.activeMissions;
var today = new Date().toDateString();
var storageData = {};
for (var i = 0; i < self.activeMissions.length; i++) {
var mission = self.activeMissions[i];
storageData['mission_' + i + '_id'] = mission.id;
storageData['mission_' + i + '_text'] = mission.text;
storageData['mission_' + i + '_metaTotal'] = mission.metaTotal;
storageData['mission_' + i + '_type'] = mission.type;
storageData['mission_' + i + '_avanceActual'] = mission.avanceActual;
storageData['mission_' + i + '_completada'] = mission.completada;
}
storageData.length = self.activeMissions.length;
storage.activeMissions = storageData;
storage.missionsDate = today;
};
self.emitEvent = function (eventType, data) {
for (var i = 0; i < self.activeMissions.length; i++) {
var mission = self.activeMissions[i];
if (mission.completada) continue;
var oldProgress = mission.avanceActual;
switch (mission.type) {
case "energia":
if (eventType === "energia_updated" && data.energia >= mission.metaTotal) {
mission.avanceActual = data.energia;
}
break;
case "frutas":
if (eventType === "fruta_atrapada") {
mission.avanceActual = Math.min(mission.avanceActual + 1, mission.metaTotal);
}
break;
case "tiempo_sin_gaseosas":
if (eventType === "frame_update" && data.gameTime >= 0) {
var timeSinceLastSoda = data.gameTime - missionManager.lastGaseosaTime;
mission.avanceActual = Math.min(timeSinceLastSoda, mission.metaTotal);
}
if (eventType === "gaseosa_atrapada") {
missionManager.lastGaseosaTime = data.gameTime;
mission.avanceActual = 0;
}
break;
case "nutripoints_total":
if (eventType === "nutripoints_updated") {
mission.avanceActual = Math.min(data.total, mission.metaTotal);
}
break;
case "agua":
if (eventType === "agua_atrapada") {
mission.avanceActual = Math.min(mission.avanceActual + 1, mission.metaTotal);
}
break;
case "partidas_consecutivas":
if (eventType === "partida_ganada") {
mission.avanceActual = Math.min(missionManager.consecutiveWins, mission.metaTotal);
}
break;
case "partida_vidas":
if (eventType === "partida_ganada" && data.vidasRestantes >= 3) {
mission.avanceActual = Math.min(mission.avanceActual + 1, mission.metaTotal);
}
break;
case "falsos_ganar":
if (eventType === "partida_ganada" && missionManager.falsosInCurrentGame >= 3) {
mission.avanceActual = Math.min(mission.avanceActual + 1, mission.metaTotal);
}
break;
case "partidas_energia_25":
if (eventType === "partida_ganada" && data.energia >= 25) {
mission.avanceActual = Math.min(missionManager.consecutiveHighEnergyWins, mission.metaTotal);
}
break;
case "tiempo_continuo":
if (eventType === "frame_update") {
var playTime = data.gameTime;
mission.avanceActual = Math.min(playTime, mission.metaTotal);
}
break;
}
// Animate progress bar if progress changed
if (oldProgress !== mission.avanceActual) {
self.animateProgressBar(i, oldProgress, mission.avanceActual);
}
// Check if mission completed
if (!mission.completada && mission.avanceActual >= mission.metaTotal) {
mission.completada = true;
sumarNutriPoints(2);
self.showMissionCompleted(mission);
// Replace completed mission with a new one after a short delay
LK.setTimeout(function () {
self.replaceCompletedMission(i);
// Refresh missions display if currently viewing missions
if (currentScreen === 'missions') {
updateMissionsDisplay();
}
}, 3000); // Wait 3 seconds before replacing
}
}
missionManager.activeMissions = self.activeMissions;
var storageData = {};
for (var i = 0; i < self.activeMissions.length; i++) {
var mission = self.activeMissions[i];
storageData['mission_' + i + '_id'] = mission.id;
storageData['mission_' + i + '_text'] = mission.text;
storageData['mission_' + i + '_metaTotal'] = mission.metaTotal;
storageData['mission_' + i + '_type'] = mission.type;
storageData['mission_' + i + '_avanceActual'] = mission.avanceActual;
storageData['mission_' + i + '_completada'] = mission.completada;
}
storageData.length = self.activeMissions.length;
storage.activeMissions = storageData;
};
self.animateProgressBar = function (missionIndex, oldProgress, newProgress) {
// Find progress bar for this mission and animate it
if (currentScreen === 'missions' && missionsScreen && missionsScreen.progressBars) {
var progressBar = missionsScreen.progressBars[missionIndex];
if (progressBar) {
var mission = self.activeMissions[missionIndex];
var newWidth = Math.min(newProgress / mission.metaTotal * 450, 450);
tween(progressBar, {
width: newWidth
}, {
duration: 300,
easing: tween.easeOut
});
}
}
};
self.replaceCompletedMission = function (missionIndex) {
// Get available missions that are not currently active
var availableMissions = [];
for (var i = 0; i < allMissions.length; i++) {
var isActive = false;
for (var j = 0; j < self.activeMissions.length; j++) {
if (self.activeMissions[j].id === allMissions[i].id) {
isActive = true;
break;
}
}
if (!isActive) {
availableMissions.push(allMissions[i]);
}
}
// If we have available missions, replace the completed one
if (availableMissions.length > 0) {
var randomIndex = Math.floor(Math.random() * availableMissions.length);
var newMission = availableMissions[randomIndex];
self.activeMissions[missionIndex] = {
id: newMission.id,
text: newMission.text,
metaTotal: newMission.metaTotal,
type: newMission.type,
avanceActual: 0,
completada: false
};
// Save updated missions
self.saveMissions();
}
};
self.saveMissions = function () {
var storageData = {};
for (var i = 0; i < self.activeMissions.length; i++) {
var mission = self.activeMissions[i];
storageData['mission_' + i + '_id'] = mission.id;
storageData['mission_' + i + '_text'] = mission.text;
storageData['mission_' + i + '_metaTotal'] = mission.metaTotal;
storageData['mission_' + i + '_type'] = mission.type;
storageData['mission_' + i + '_avanceActual'] = mission.avanceActual;
storageData['mission_' + i + '_completada'] = mission.completada;
}
storageData.length = self.activeMissions.length;
storage.activeMissions = storageData;
missionManager.activeMissions = self.activeMissions;
};
self.showMissionCompleted = function (mission) {
if (!gameActive) return;
// Create mission completed banner
var banner = LK.getAsset('restartButton', {
width: 800,
height: 120,
anchorX: 0.5,
anchorY: 0.5
});
banner.tint = 0x4CAF50;
banner.alpha = 0;
banner.x = 2048 / 2;
banner.y = 200;
game.addChild(banner);
var bannerText = new Text2('¡Misión cumplida: ' + mission.text.substring(0, 20) + '... +2 NP!', {
size: 35,
fill: 0xFFFFFF,
font: "Impact"
});
bannerText.anchor.set(0.5, 0.5);
bannerText.x = 2048 / 2;
bannerText.y = 200;
bannerText.alpha = 0;
game.addChild(bannerText);
// Play success sound
LK.getSound('powerup').play();
// Animate banner
tween(banner, {
alpha: 0.9
}, {
duration: 250,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(banner, {
alpha: 0
}, {
duration: 250,
onFinish: function onFinish() {
banner.destroy();
}
});
tween(bannerText, {
alpha: 0
}, {
duration: 250,
onFinish: function onFinish() {
bannerText.destroy();
}
});
}, 2500);
}
});
tween(bannerText, {
alpha: 1
}, {
duration: 250
});
};
return self;
});
var MissionsScreen = Container.expand(function () {
var self = Container.call(this);
// Create background
var bg = LK.getAsset('energyBarBg', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0
});
bg.tint = 0x2C3E50;
bg.alpha = 0.95;
self.addChild(bg);
// Title
var titleText = new Text2('MISIONES DIARIAS', {
size: 100,
fill: 0xFFD700,
font: "Impact"
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 300;
self.addChild(titleText);
// Create scrollable container for missions
var scrollableArea = new Container();
scrollableArea.x = 0;
scrollableArea.y = 450; // Start below title
scrollableArea.scrollY = 0; // Track scroll position
self.addChild(scrollableArea);
// Create mask for scrollable area (visible area)
var scrollMask = LK.getAsset('energyBarBg', {
width: 2048,
height: 2000,
// Height available for scrolling (from y=450 to y=2450)
anchorX: 0,
anchorY: 0
});
scrollMask.x = 0;
scrollMask.y = 450;
scrollMask.alpha = 0; // Invisible mask
self.addChild(scrollMask);
scrollableArea.mask = scrollMask;
self.missionsContainer = new Container();
scrollableArea.addChild(self.missionsContainer);
// Store references for scrolling
self.scrollableArea = scrollableArea;
self.maxScrollY = 0; // Will be calculated based on content
self.scrollMask = scrollMask;
// Add scroll functionality
self.enableScrolling = function () {
// Touch/mouse wheel scrolling
var isDragging = false;
var lastY = 0;
var scrollSpeed = 2;
scrollableArea.down = function (x, y, obj) {
isDragging = true;
lastY = y;
};
scrollableArea.move = function (x, y, obj) {
if (isDragging) {
var deltaY = y - lastY;
self.scroll(deltaY * scrollSpeed);
lastY = y;
}
};
scrollableArea.up = function (x, y, obj) {
isDragging = false;
};
// Also enable scrolling on the background
bg.down = function (x, y, obj) {
isDragging = true;
lastY = y;
};
bg.move = function (x, y, obj) {
if (isDragging && y > 450 && y < 2450) {
// Only scroll in missions area
var deltaY = y - lastY;
self.scroll(deltaY * scrollSpeed);
lastY = y;
}
};
bg.up = function (x, y, obj) {
isDragging = false;
};
};
// Scroll function
self.scroll = function (deltaY) {
var newScrollY = self.scrollableArea.scrollY + deltaY;
// Calculate max scroll based on content height
var contentHeight = self.missionsContainer.height || 0;
var visibleHeight = 2000; // Height of visible area
self.maxScrollY = Math.max(0, contentHeight - visibleHeight);
// Constrain scroll within bounds
newScrollY = Math.max(-self.maxScrollY, Math.min(0, newScrollY));
self.scrollableArea.scrollY = newScrollY;
self.scrollableArea.y = 450 + newScrollY;
};
// Update content height calculation
self.updateScrollBounds = function () {
// Calculate total content height based on missions
var activeMissions = missionManager.activeMissions;
if (activeMissions && activeMissions.length > 0) {
var totalHeight = activeMissions.length * 320 + 100; // Each mission is 320px + padding
var visibleHeight = 2000;
self.maxScrollY = Math.max(0, totalHeight - visibleHeight);
// Reset scroll to top when content updates
self.scrollableArea.scrollY = 0;
self.scrollableArea.y = 450;
}
};
// Enable scrolling
self.enableScrolling();
// Bottom back button
var bottomBackButton = LK.getAsset('restartButton', {
width: 400,
height: 100,
anchorX: 0.5,
anchorY: 0.5
});
bottomBackButton.tint = 0xFF6B35;
bottomBackButton.x = 2048 / 2;
bottomBackButton.y = 2600;
self.addChild(bottomBackButton);
var bottomBackText = new Text2('← VOLVER', {
size: 60,
fill: 0xFFFFFF,
font: "Impact"
});
bottomBackText.anchor.set(0.5, 0.5);
bottomBackText.x = 2048 / 2;
bottomBackText.y = 2600;
self.addChild(bottomBackText);
bottomBackButton.down = function () {
showStartScreen();
};
bottomBackText.down = function () {
showStartScreen();
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerBody = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 1.0
});
var basket = self.attachAsset('basket', {
anchorX: 0.5,
anchorY: 0.5,
y: -110
});
self.speed = 8;
self.targetX = self.x;
self.update = function () {
var dx = self.targetX - self.x;
if (Math.abs(dx) > 5) {
self.x += dx * 0.15;
} else {
self.x = self.targetX;
}
// Keep player within bounds
if (self.x < 150) self.x = 150;
if (self.x > 2048 - 150) self.x = 2048 - 150;
};
self.moveTo = function (targetX) {
self.targetX = targetX;
};
return self;
});
var StartScreen = Container.expand(function () {
var self = Container.call(this);
// Create background
var bg = LK.getAsset('energyBarBg', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0
});
bg.tint = 0x5d6c16;
self.addChild(bg);
// Game title
var titleText = new Text2('Caza-ingredientes', {
size: 120,
fill: 0xFFD700,
font: "Impact"
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 400;
self.addChild(titleText);
// Nutripoints display on start screen
var nutripointsDisplay = new Text2('Nutripoints: ' + (storage.totalNutripoints || 0), {
size: 75,
fill: 0x32CD32,
font: "Impact"
});
nutripointsDisplay.anchor.set(0.5, 0.5);
nutripointsDisplay.x = 2048 / 2;
nutripointsDisplay.y = 500;
self.addChild(nutripointsDisplay);
// Store reference for updates
self.nutripointsDisplay = nutripointsDisplay;
var subtitleText = new Text2('Elige bien, vive mejor', {
size: 80,
fill: 0x32CD32,
font: "Impact"
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 2048 / 2;
subtitleText.y = 580;
self.addChild(subtitleText);
// Create buttons
var buttonProps = [{
text: 'PLAY',
y: 850,
color: 0x32CD32
}, {
text: 'MISIONES',
y: 1050,
color: 0xFF6B35
}, {
text: 'TIENDA',
y: 1250,
color: 0x4ECDC4
}, {
text: 'PREGUNTAS',
y: 1450,
color: 0x9B59B6
}];
self.buttons = [];
for (var i = 0; i < buttonProps.length; i++) {
var buttonBg = LK.getAsset('restartButton', {
width: 600,
height: 120,
anchorX: 0.5,
anchorY: 0.5
});
buttonBg.tint = buttonProps[i].color;
buttonBg.x = 2048 / 2;
buttonBg.y = buttonProps[i].y;
self.addChild(buttonBg);
var buttonText = new Text2(buttonProps[i].text, {
size: 70,
fill: 0xFFFFFF,
font: "Impact"
});
buttonText.anchor.set(0.5, 0.5);
buttonText.x = 2048 / 2;
buttonText.y = buttonProps[i].y;
self.addChild(buttonText);
buttonBg.buttonType = buttonProps[i].text;
buttonText.buttonType = buttonProps[i].text;
self.buttons.push({
bg: buttonBg,
text: buttonText,
type: buttonProps[i].text
});
}
// Button click handlers
for (var j = 0; j < self.buttons.length; j++) {
(function (button) {
button.bg.down = function (x, y, obj) {
handleStartScreenButton(button.type);
};
button.text.down = function (x, y, obj) {
handleStartScreenButton(button.type);
};
})(self.buttons[j]);
}
return self;
});
var StoreScreen = Container.expand(function () {
var self = Container.call(this);
// Create background
var bg = LK.getAsset('energyBarBg', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0
});
bg.tint = 0x2C3E50;
bg.alpha = 0.95;
self.addChild(bg);
// Title
var titleText = new Text2('TIENDA', {
size: 100,
fill: 0xFFD700,
font: "Impact"
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 250;
self.addChild(titleText);
// Nutripoints display
var nutripointsDisplay = new Text2('Nutripoints: ' + (storage.totalNutripoints || 0), {
size: 60,
fill: 0x32CD32,
font: "Impact"
});
nutripointsDisplay.anchor.set(0.5, 0.5);
nutripointsDisplay.x = 2048 / 2;
nutripointsDisplay.y = 350;
self.addChild(nutripointsDisplay);
// Store reference for updates
self.nutripointsDisplay = nutripointsDisplay;
self.storeContainer = new Container();
self.addChild(self.storeContainer);
// Bottom back button
var bottomBackButton = LK.getAsset('restartButton', {
width: 400,
height: 100,
anchorX: 0.5,
anchorY: 0.5
});
bottomBackButton.tint = 0xFF6B35;
bottomBackButton.x = 2048 / 2;
bottomBackButton.y = 2600;
self.addChild(bottomBackButton);
var bottomBackText = new Text2('← VOLVER', {
size: 60,
fill: 0xFFFFFF,
font: "Impact"
});
bottomBackText.anchor.set(0.5, 0.5);
bottomBackText.x = 2048 / 2;
bottomBackText.y = 2600;
self.addChild(bottomBackText);
bottomBackButton.down = function () {
showStartScreen();
};
bottomBackText.down = function () {
showStartScreen();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
// Game state management
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
var currentScreen = 'start'; // 'start', 'game', 'missions', 'store', 'faq'
var gameStarted = false; // Track if game has been started via PLAY button
var gamePaused = false; // Track if game is paused
var pauseButton;
var pauseMenu;
var startScreen;
var missionsScreen;
var storeScreen;
var faqScreen;
// Mission system
var allMissions = [{
id: "energia_20",
text: "Alcanza 20 de Energía en una sola partida.",
metaTotal: 20,
type: "energia"
}, {
id: "frutas_10",
text: "Atrapa 10 frutas o verduras sanas en una partida.",
metaTotal: 10,
type: "frutas"
}, {
id: "evitar_gaseosas_60",
text: "Evita TODAS las gaseosas durante 60 segundos.",
metaTotal: 60,
type: "tiempo_sin_gaseosas"
}, {
id: "nutripoints_6",
text: "Consigue 6 Nutripoints en total.",
metaTotal: 6,
type: "nutripoints_total"
}, {
id: "agua_5",
text: "Recoge 5 botellas de agua (power-ups) en una sesión.",
metaTotal: 5,
type: "agua"
}, {
id: "partidas_3_sin_perder",
text: "Juega 3 partidas seguidas sin perder una vida.",
metaTotal: 3,
type: "partidas_consecutivas"
}, {
id: "partida_3_vidas",
text: "Completa una partida con al menos 3 vidas restantes.",
metaTotal: 1,
type: "partida_vidas"
}, {
id: "falsos_3_ganar",
text: "Atrapa 3 alimentos 'falsos sanos' y aún así gana.",
metaTotal: 3,
type: "falsos_ganar"
}, {
id: "energia_25_2_partidas",
text: "Gana 2 partidas consecutivas con Energía ≥25.",
metaTotal: 2,
type: "partidas_energia_25"
}, {
id: "tiempo_5_min",
text: "Juega durante 5 min. continuos sin colapsar.",
metaTotal: 300,
type: "tiempo_continuo"
}];
// Store items
var storeItems = [{
id: "skin_rojo",
nombre: "Skin Roja",
costo: 5,
tipo: "skin"
}, {
id: "skin_verde",
nombre: "Skin Verde",
costo: 5,
tipo: "skin"
}, {
id: "fondo_parque",
nombre: "Fondo Parque",
costo: 8,
tipo: "fondo"
}, {
id: "fondo_playa",
nombre: "Fondo Playa",
costo: 10,
tipo: "fondo"
}];
// FAQ data
var faqData = [{
question: "¿Cómo se juega \"Caza-ingredientes\"?",
answer: "Mueve tu avatar a izquierda y derecha y atrapa solo los alimentos saludables para sumar Energía. Evita los ultraprocesados y trampas."
}, {
question: "¿Para qué sirve la barra de Energía?",
answer: "Representa tu nivel de salud en el juego. Si llega a 0, pierdes. Si llegas a 30, ganas Nutripoints extra."
}, {
question: "¿Qué son los Nutripoints y cómo se consiguen?",
answer: "Son puntos que obtienes al ganar con Energía completa o cumpliendo misiones. Sirven para comprar skins y fondos en la Tienda."
}, {
question: "¿Cómo funciona la Tienda?",
answer: "En la Tienda puedes cambiar Nutripoints por apariencias nuevas para tu avatar o fondos temáticos para el juego."
}, {
question: "¿Cómo se completan las misiones?",
answer: "Ve a MISIONES, revisa las tareas diarias y juega hasta lograr cada objetivo. Al cumplirlas, recibes Nutripoints automáticamente."
}];
// Game elements
// Fake healthy foods
// Junk foods
// Healthy foods
// Game variables
// Healthy Foods - Fruits
// Healthy Foods - Vegetables
// Healthy Foods - Proteins & Grains
// Junk Foods
// Fake Healthy Foods
var player;
var fallingItems = [];
var energy = 15;
var lives = 3;
var fallSpeed = 350 / 60; // 350px/s converted to pixels per frame (much faster)
var lastSpeedIncrease = 0;
var lastWaterSpawn = 0;
var gameStartTime = 0;
var foodsCaught = 0;
var anxietyBombsActive = false;
var lastSpawnTime = 0;
var lastAnxietySpawnTime = 0;
var expertMessageShown = false;
var gameActive = true; // Track if game is active
var expertModeTimer = 0; // Timer to track when expert mode should activate (20 seconds)
var expertModeStartTime = 1200; // 20 seconds * 60 fps = 1200 frames
// Nutripoints system variables and initialization
function initializeNutripoints() {
// Check if this is first time installation
if (storage.totalNutripoints === undefined) {
storage.totalNutripoints = 0;
}
// Check for daily login bonus
var today = new Date().toISOString().split('T')[0]; // Get YYYY-MM-DD format
var lastLoginDate = storage.lastLoginDate;
if (lastLoginDate !== today) {
// Award daily login bonus
storage.totalNutripoints = (storage.totalNutripoints || 0) + 1;
storage.lastLoginDate = today;
// Show login bonus message (non-intrusive)
if (lastLoginDate) {
// Don't show on first install, only subsequent days
LK.setTimeout(function () {
showLoginBonusMessage();
}, 1000);
}
}
}
// Global function to add nutripoints
function sumarNutriPoints(cantidad) {
totalNutripoints += cantidad;
storage.totalNutripoints = totalNutripoints;
// Update UI immediately
updateNutripointsDisplay();
}
// Function to show login bonus message
function showLoginBonusMessage() {
if (!gameStarted) {
// Only show on start screen
var banner = LK.getAsset('restartButton', {
width: 600,
height: 80,
anchorX: 0.5,
anchorY: 0.5
});
banner.tint = 0x32CD32;
banner.alpha = 0;
banner.x = 2048 / 2;
banner.y = 650;
if (startScreen) {
startScreen.addChild(banner);
var bannerText = new Text2('¡Has ganado 1 Nutripoint por iniciar hoy!', {
size: 45,
fill: 0xFFFFFF,
font: "Impact"
});
bannerText.anchor.set(0.5, 0.5);
bannerText.x = 2048 / 2;
bannerText.y = 650;
bannerText.alpha = 0;
startScreen.addChild(bannerText);
// Animate banner
tween(banner, {
alpha: 0.9
}, {
duration: 500,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(banner, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
banner.destroy();
}
});
tween(bannerText, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
bannerText.destroy();
}
});
}, 3000);
}
});
tween(bannerText, {
alpha: 1
}, {
duration: 500
});
}
}
}
// Function to update nutripoints display across all screens
function updateNutripointsDisplay() {
// Update start screen display
if (startScreen && startScreen.nutripointsDisplay) {
startScreen.nutripointsDisplay.setText('Nutripoints: ' + totalNutripoints);
}
// Update store screen display
if (storeScreen && storeScreen.nutripointsDisplay) {
storeScreen.nutripointsDisplay.setText('Nutripoints: ' + totalNutripoints);
}
// Update game UI display
if (totalNutripointsText) {
totalNutripointsText.setText('Nutripoints: ' + totalNutripoints);
}
}
// Initialize nutripoints system
initializeNutripoints();
var totalNutripoints = storage.totalNutripoints || 0;
var gameNutripoints = 0; // Points earned in current game
// Mission tracking variables
var missionManager = {
activeMissions: [],
gameStartTime: 0,
lastGaseosaTime: 0,
consecutiveWins: 0,
falsosInCurrentGame: 0,
consecutiveHighEnergyWins: 0,
continuousPlayTime: 0
};
// Initialize mission progress from storage
var missionProgress = storage.missionProgress || {};
// Food tracking variables
var foodCounts = {
'apple': 0,
'banana': 0,
'hardEgg': 0,
'broccoli': 0,
'carrot': 0,
'wholeBread': 0,
'waterBottle': 0
};
// UI elements
var livesText;
var scoreText;
var energyText;
var energyBarBg;
var energyBarFill;
var nutripointsText;
var totalNutripointsText;
// Initialize UI
function initializeUI() {
// Energy text with larger size
energyText = new Text2('Energía: 15/30', {
size: 72,
fill: 0xFFFFFF,
font: "Impact"
});
energyText.anchor.set(0, 0);
LK.gui.topLeft.addChild(energyText);
energyText.x = 150;
energyText.y = 20;
// Energy bar background
energyBarBg = LK.getAsset('energyBarBg', {
anchorX: 0,
anchorY: 0
});
LK.gui.topLeft.addChild(energyBarBg);
energyBarBg.x = 150;
energyBarBg.y = 100;
// Energy bar fill
energyBarFill = LK.getAsset('energyBarFill', {
anchorX: 0,
anchorY: 0
});
LK.gui.topLeft.addChild(energyBarFill);
energyBarFill.x = 150;
energyBarFill.y = 100;
// Lives text with larger size
livesText = new Text2('Vidas: 3', {
size: 84,
fill: 0xFF0000,
font: "Impact"
});
livesText.anchor.set(1, 0);
LK.gui.topRight.addChild(livesText);
livesText.x = -20;
livesText.y = 20;
// Total Nutripoints display (made larger)
totalNutripointsText = new Text2('Nutripoints: ' + totalNutripoints, {
size: 72,
fill: 0x32CD32,
font: "Impact"
});
totalNutripointsText.anchor.set(1, 0);
LK.gui.topRight.addChild(totalNutripointsText);
totalNutripointsText.x = -20;
totalNutripointsText.y = 120;
// Pause button
pauseButton = LK.getAsset('pauseButton', {
anchorX: 0.5,
anchorY: 0.5
});
pauseButton.x = 2048 - 60;
pauseButton.y = 300;
LK.gui.topRight.addChild(pauseButton);
var pauseText = new Text2('⏸', {
size: 50,
fill: 0xFFFFFF,
font: "Impact"
});
pauseText.anchor.set(0.5, 0.5);
pauseText.x = 2048 - 60;
pauseText.y = 300;
LK.gui.topRight.addChild(pauseText);
pauseButton.down = function () {
showPauseMenu();
};
pauseText.down = function () {
showPauseMenu();
};
// Score text removed
}
// Update UI
function updateUI() {
if (energyText) energyText.setText('Energía: ' + energy + '/30');
if (livesText) livesText.setText('Vidas: ' + lives);
if (totalNutripointsText) totalNutripointsText.setText('Nutripoints: ' + totalNutripoints);
// Score text update removed
// Update energy bar fill based on current energy (0-30 range)
if (energyBarFill) {
var energyPercentage = energy / 30;
energyBarFill.width = 400 * energyPercentage;
// Change energy bar color based on energy level
if (energy >= 20) {
energyBarFill.tint = 0x00ff00; // Green for high energy
} else if (energy >= 10) {
energyBarFill.tint = 0xffff00; // Yellow for medium energy
} else {
energyBarFill.tint = 0xff0000; // Red for low energy
}
}
}
// Flash effect
function flashScreen(color) {
LK.effects.flashScreen(color, 300);
}
// Food arrays for variety - exactly 10 sprite types + 2 fake healthy
var healthyFoods = ['banana', 'apple', 'carrot', 'broccoli', 'wholeBread', 'hardEgg'];
var junkFoods = ['soda', 'chips', 'candy', 'burger'];
var fakeFoods = ['cerealBar', 'flavoredYogurt'];
// Spawn falling item
function spawnFallingItem() {
var type = 'healthy';
var specificFood = null;
var rand = Math.random();
if (foodsCaught > 0 && foodsCaught % 20 === 0 && lastWaterSpawn !== foodsCaught) {
type = 'water';
lastWaterSpawn = foodsCaught;
} else if (rand < 0.3) {
type = 'junk';
specificFood = junkFoods[Math.floor(Math.random() * junkFoods.length)];
} else if (rand < 0.5) {
type = 'fake';
specificFood = fakeFoods[Math.floor(Math.random() * fakeFoods.length)];
} else {
type = 'healthy';
specificFood = healthyFoods[Math.floor(Math.random() * healthyFoods.length)];
}
var item = new FallingItem(type, specificFood);
item.x = Math.random() * (2048 - 350) + 175;
item.y = -175;
fallingItems.push(item);
game.addChild(item);
}
// Spawn anxiety bomb
function spawnAnxietyBomb() {
var item = new FallingItem('anxiety', null);
item.x = Math.random() * (2048 - 350) + 175;
item.y = -175;
fallingItems.push(item);
game.addChild(item);
}
// Helper function for player visual feedback
function playerFeedback(color, duration, scaleEffect) {
if (scaleEffect) {
tween(player, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: duration,
onFinish: function onFinish() {
tween(player, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: duration
});
}
});
} else {
tween(player, {
tint: color
}, {
duration: duration,
onFinish: function onFinish() {
tween(player, {
tint: 0xFFFFFF
}, {
duration: duration
});
}
});
}
}
// Helper function for vibration feedback
function vibrateDevice() {
if (navigator && navigator.vibrate) {
navigator.vibrate(100);
}
}
// Handle item collision
function handleItemCollision(item) {
switch (item.type) {
case 'healthy':
energy = Math.min(30, energy + 1);
// Score increment removed
LK.getSound('ping').play();
flashScreen(0x32CD32);
playerFeedback(0x32CD32, 100, false);
foodsCaught++;
// Track healthy food counts
if (item.specificFood && foodCounts.hasOwnProperty(item.specificFood)) {
foodCounts[item.specificFood]++;
}
// Emit mission event
missionManagerInstance.emitEvent("fruta_atrapada", {});
missionManagerInstance.emitEvent("energia_updated", {
energia: energy
});
break;
case 'junk':
lives--;
energy = Math.max(0, energy - 2);
LK.getSound('buzz').play();
vibrateDevice();
flashScreen(0xFF4500);
playerFeedback(0xFF4500, 100, false);
// Emit mission event for soda specifically
if (item.specificFood === 'soda') {
var gameTime = (LK.ticks - gameStartTime) / 60;
missionManagerInstance.emitEvent("gaseosa_atrapada", {
gameTime: gameTime
});
}
missionManagerInstance.emitEvent("energia_updated", {
energia: energy
});
break;
case 'fake':
energy = Math.max(0, energy - 2);
LK.getSound('buzz').play();
vibrateDevice();
flashScreen(0xFFD700);
playerFeedback(0xFFD700, 100, false);
missionManager.falsosInCurrentGame++;
missionManagerInstance.emitEvent("energia_updated", {
energia: energy
});
break;
case 'water':
energy = Math.min(30, energy + 3);
// Score increment removed
LK.getSound('powerup').play();
flashScreen(0x00BFFF);
playerFeedback(0x00BFFF, 150, true);
// Track water bottle counts
foodCounts['waterBottle']++;
// Emit mission events
missionManagerInstance.emitEvent("agua_atrapada", {});
missionManagerInstance.emitEvent("energia_updated", {
energia: energy
});
break;
case 'anxiety':
energy = Math.max(0, energy - 5);
LK.getSound('explosion').play();
vibrateDevice();
flashScreen(0x8B008B);
playerFeedback(0x8B008B, 300, false);
missionManagerInstance.emitEvent("energia_updated", {
energia: energy
});
break;
}
// Update nutripoints mission
missionManagerInstance.emitEvent("nutripoints_updated", {
total: totalNutripoints
});
}
// Initialize game
function initializeGame() {
gameStartTime = LK.ticks;
// Initialize mission tracking for this game
missionManager.gameStartTime = gameStartTime;
missionManager.falsosInCurrentGame = 0;
// Create player
player = new Player();
player.x = 2048 / 2;
player.y = 2732 - 100;
game.addChild(player);
// Initialize UI
initializeUI();
updateUI();
}
// Game input handling
game.down = function (x, y, obj) {
if (!player) return; // Check if player exists
var gamePos = game.toLocal({
x: x,
y: y
});
player.moveTo(gamePos.x);
};
game.move = function (x, y, obj) {
if (!player) return; // Check if player exists
var gamePos = game.toLocal({
x: x,
y: y
});
player.moveTo(gamePos.x);
};
// Main game update loop
game.update = function () {
// Don't update game logic if game hasn't started, is not active, or is paused
if (!gameStarted || !gameActive || gamePaused) {
return;
}
var currentTime = LK.ticks;
var gameTime = (currentTime - gameStartTime) / 60; // Convert to seconds
// Increase speed every 15 seconds
if (gameTime - lastSpeedIncrease >= 15) {
fallSpeed += 20 / 60; // Increase by 20px/s (double the previous increment)
lastSpeedIncrease = gameTime;
}
// Increment expert mode timer
expertModeTimer++;
// Activate anxiety bombs after 20 seconds (1200 frames)
if (expertModeTimer >= expertModeStartTime && !anxietyBombsActive) {
anxietyBombsActive = true;
lastAnxietySpawnTime = currentTime;
// Only show expert message when expert mode activates
if (expertModeTimer >= expertModeStartTime && !expertMessageShown) {
expertMessageShown = true;
// Create full screen overlay for expert message
var expertOverlay = LK.getAsset('basket', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0
});
expertOverlay.tint = 0x000000;
expertOverlay.alpha = 0.9;
game.addChild(expertOverlay);
// Show expert challenge message with attractive styling
var expertText = new Text2('¡RETO EXPERTO!', {
size: 150,
fill: 0xFFD700,
font: "Impact"
});
expertText.anchor.set(0.5, 0.5);
expertText.x = 2048 / 2;
expertText.y = 2732 / 2 - 100;
game.addChild(expertText);
// Add subtitle text
var subtitleText = new Text2('¡Los alimentos caen más rápido!', {
size: 75,
fill: 0xFF4500,
font: "Impact"
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 2048 / 2;
subtitleText.y = 2732 / 2 + 50;
game.addChild(subtitleText);
// Animate expert message with pulsing effect
tween(expertText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(expertText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 500,
easing: tween.easeInOut
});
}
});
// Animate and remove message after 4 seconds
tween(expertOverlay, {
alpha: 0
}, {
duration: 4000,
onFinish: function onFinish() {
expertOverlay.destroy();
}
});
tween(expertText, {
alpha: 0
}, {
duration: 4000,
onFinish: function onFinish() {
expertText.destroy();
}
});
tween(subtitleText, {
alpha: 0
}, {
duration: 4000,
onFinish: function onFinish() {
subtitleText.destroy();
}
});
}
}
// Spawn items every 1.5 seconds
if (currentTime - lastSpawnTime >= 90) {
// 1.5 * 60 = 90 frames
// Spawn 2-3 items at once for more food variety
var itemsToSpawn = 2 + Math.floor(Math.random() * 2); // 2 or 3 items
for (var s = 0; s < itemsToSpawn; s++) {
spawnFallingItem();
}
lastSpawnTime = currentTime;
}
// Spawn anxiety bombs every 40 seconds after activation
if (anxietyBombsActive && currentTime - lastAnxietySpawnTime >= 2400) {
// 40 * 60 = 2400 frames
spawnAnxietyBomb();
lastAnxietySpawnTime = currentTime;
}
// Update falling items
for (var i = fallingItems.length - 1; i >= 0; i--) {
var item = fallingItems[i];
// Check collision with player
if (item.intersects(player)) {
handleItemCollision(item);
item.destroy();
fallingItems.splice(i, 1);
continue;
}
// Remove items that fall off screen
if (item.y > 2732 + 350) {
item.destroy();
fallingItems.splice(i, 1);
}
}
// Update UI
updateUI();
// Emit frame update for missions
if (gameActive && gameStarted) {
var gameTime = (LK.ticks - gameStartTime) / 60;
missionManagerInstance.emitEvent("frame_update", {
gameTime: gameTime
});
}
// Check game over conditions
if (energy >= 30) {
// Store final stats for victory
storage.finalEnergy = energy;
storage.finalTime = Math.floor(gameTime);
storage.gameEndReason = 'victoria';
// Track mission progress for winning with high energy
missionManager.consecutiveWins++;
if (energy >= 25) {
missionManager.consecutiveHighEnergyWins++;
}
storage.consecutiveWins = missionManager.consecutiveWins;
storage.consecutiveHighEnergyWins = missionManager.consecutiveHighEnergyWins;
gameActive = false; // Stop game updates
showVictoryMessage();
} else if (lives <= 0) {
// Store final stats when lives reach 0
storage.finalEnergy = energy;
storage.finalTime = Math.floor(gameTime);
storage.gameEndReason = 'colapso';
// Reset consecutive wins on game over
missionManager.consecutiveWins = 0;
missionManager.consecutiveHighEnergyWins = 0;
storage.consecutiveWins = 0;
storage.consecutiveHighEnergyWins = 0;
gameActive = false; // Stop game updates
showGameOver();
} else if (energy <= 0) {
// Store final stats
storage.finalEnergy = energy;
storage.finalTime = Math.floor(gameTime);
storage.gameEndReason = 'fatiga';
// Reset consecutive wins on game over
missionManager.consecutiveWins = 0;
missionManager.consecutiveHighEnergyWins = 0;
storage.consecutiveWins = 0;
storage.consecutiveHighEnergyWins = 0;
gameActive = false; // Stop game updates
showCustomGameOver();
}
};
// Get nutritional information for the most caught food
function getNutritionalInfo() {
var maxCount = 0;
var mostCaughtFood = null;
// Find the food with highest count
for (var food in foodCounts) {
if (foodCounts[food] > maxCount) {
maxCount = foodCounts[food];
mostCaughtFood = food;
}
}
if (!mostCaughtFood || maxCount === 0) {
return {
title: "¡Sigue practicando!",
info: "Intenta atrapar más alimentos saludables la próxima vez."
};
}
var nutritionalData = {
'apple': {
title: "Manzana (1 unidad mediana)",
info: "✅ Rica en fibra (4g), mejora la digestión.\n✅ Aporta vitamina C (8% de la recomendación diaria).\n✅ Tiene antioxidantes que protegen las células.\n⚖️ Solo 95 kcal y 0 grasa."
},
'banana': {
title: "Plátano (1 unidad mediana)",
info: "✅ Rico en potasio (400–450 mg), ideal para los músculos.\n✅ Contiene vitamina B6, que ayuda al sistema nervioso.\n✅ Da energía rápida gracias a sus azúcares naturales."
},
'hardEgg': {
title: "Huevo duro (1 unidad)",
info: "✅ Aporta proteínas completas (6g por huevo).\n✅ Rico en colina, esencial para la memoria y el cerebro.\n✅ Contiene vitamina D y hierro.\n⚠️ Contiene algo de colesterol, pero no es dañino en jóvenes sanos."
},
'broccoli': {
title: "Brócoli (1 taza cocida)",
info: "✅ Altísimo en vitamina C y vitamina K.\n✅ Fuente de fibra y antioxidantes.\n✅ Tiene compuestos que ayudan a prevenir el cáncer."
},
'carrot': {
title: "Zanahoria (1 mediana cruda)",
info: "✅ Altísima en betacaroteno (vitamina A), buena para la vista.\n✅ Solo 25 kcal y con fibra.\n✅ Rica en antioxidantes, fortalece el sistema inmune."
},
'wholeBread': {
title: "Pan integral (1 rebanada)",
info: "✅ Buena fuente de fibra (2–3 g por porción).\n✅ Aporta carbohidratos complejos que dan energía duradera.\n✅ Tiene hierro y vitaminas del grupo B."
},
'waterBottle': {
title: "Agua (1 vaso / 240ml)",
info: "✅ Hidratación esencial para todo el cuerpo.\n✅ Regula la temperatura, transporta nutrientes y limpia toxinas.\n✅ 0 calorías, 0 azúcar, 100% necesaria."
}
};
return nutritionalData[mostCaughtFood] || {
title: "¡Sigue practicando!",
info: "Intenta atrapar más alimentos saludables la próxima vez."
};
}
// Show victory message when energy reaches 30
function showVictoryMessage() {
var finalTime = storage.finalTime || Math.floor((LK.ticks - gameStartTime) / 60);
// Emit mission events for winning the game
missionManagerInstance.emitEvent("partida_ganada", {
energia: energy,
vidasRestantes: lives
});
// Award Nutripoints only for reaching maximum energy
if (energy >= 30) {
gameNutripoints = 2; // Award 2 Nutripoints for completing with max energy
sumarNutriPoints(gameNutripoints);
}
// Create full screen overlay
var overlay = LK.getAsset('energyBarBg', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0
});
overlay.tint = 0x000000;
overlay.alpha = 0.9;
game.addChild(overlay);
// Victory title
var titleText = new Text2('¡FELICITACIONES!', {
size: 120,
fill: 0xFFD700,
font: "Impact"
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 400;
game.addChild(titleText);
// Victory message
var messageText = new Text2('¡Alcanzaste el nivel máximo de energía saludable!', {
size: 70,
fill: 0x32CD32,
font: "Impact"
});
messageText.anchor.set(0.5, 0.5);
messageText.x = 2048 / 2;
messageText.y = 600;
game.addChild(messageText);
// Additional message lines
var message2Text = new Text2('Tu cuerpo y tu mente están listas para todo.', {
size: 60,
fill: 0x00BFFF,
font: "Impact"
});
message2Text.anchor.set(0.5, 0.5);
message2Text.x = 2048 / 2;
message2Text.y = 750;
game.addChild(message2Text);
var message3Text = new Text2('Elegiste bien, vivís mejor.', {
size: 60,
fill: 0xFF69B4,
font: "Impact"
});
message3Text.anchor.set(0.5, 0.5);
message3Text.x = 2048 / 2;
message3Text.y = 900;
game.addChild(message3Text);
// Score section removed
// Time played section
var timeText = new Text2('Tiempo jugado: ' + finalTime + ' segundos', {
size: 60,
fill: 0xFFFFFF,
font: "Impact"
});
timeText.anchor.set(0.5, 0.5);
timeText.x = 2048 / 2;
timeText.y = 1100;
game.addChild(timeText);
// Nutripoints message
var gameNutripointsText = new Text2('¡Ganaste 2 Nutripoints por llegar al máximo de energía!', {
size: 65,
fill: 0x32CD32,
font: "Impact"
});
gameNutripointsText.anchor.set(0.5, 0.5);
gameNutripointsText.x = 2048 / 2;
gameNutripointsText.y = 1200;
game.addChild(gameNutripointsText);
var totalNutripointsText = new Text2('Total acumulado: ' + totalNutripoints + ' Nutripoints', {
size: 55,
fill: 0xFFD700,
font: "Impact"
});
totalNutripointsText.anchor.set(0.5, 0.5);
totalNutripointsText.x = 2048 / 2;
totalNutripointsText.y = 1300;
game.addChild(totalNutripointsText);
// Create animated restart button
var restartButton = LK.getAsset('restartButton', {
width: 700,
height: 140,
color: 0x32CD32,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
restartButton.x = 2048 / 2;
restartButton.y = 1600;
game.addChild(restartButton);
var restartText = new Text2('Jugar de nuevo', {
size: 80,
fill: 0xFFFFFF,
font: "Impact"
});
restartText.anchor.set(0.5, 0.5);
restartText.x = 2048 / 2;
restartText.y = 1600;
game.addChild(restartText);
// Animate button with pulsing effect
function animateVictoryRestartButton() {
tween(restartButton, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(restartButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: animateVictoryRestartButton
});
}
});
tween(restartText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(restartText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut
});
}
});
}
animateVictoryRestartButton();
// Add click handler for restart
restartButton.down = function () {
showStartScreen();
};
restartText.down = function () {
showStartScreen();
};
}
// Show game over message when lives reach 0
function showGameOver() {
var finalTime = storage.finalTime || Math.floor((LK.ticks - gameStartTime) / 60);
// No Nutripoints awarded when not reaching maximum energy
// Create full screen overlay
var overlay = LK.getAsset('energyBarBg', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0
});
overlay.tint = 0x000000;
overlay.alpha = 0.9;
game.addChild(overlay);
// Game Over title
var gameOverText = new Text2('GAME OVER', {
size: 150,
fill: 0xFF0000,
font: "Impact"
});
gameOverText.anchor.set(0.5, 0.5);
gameOverText.x = 2048 / 2;
gameOverText.y = 600;
game.addChild(gameOverText);
// Score section removed
// Time played section
var timeText = new Text2('Tiempo jugado: ' + finalTime + ' segundos', {
size: 60,
fill: 0xFFFFFF,
font: "Impact"
});
timeText.anchor.set(0.5, 0.5);
timeText.x = 2048 / 2;
timeText.y = 800;
game.addChild(timeText);
// Nutripoints encouragement message
var nutripointsEncourageText = new Text2('¡Sigue eligiendo bien para ganar Nutripoints!', {
size: 65,
fill: 0xFFD700,
font: "Impact"
});
nutripointsEncourageText.anchor.set(0.5, 0.5);
nutripointsEncourageText.x = 2048 / 2;
nutripointsEncourageText.y = 900;
game.addChild(nutripointsEncourageText);
// Add nutritional information section
var mostConsumedText = new Text2('Alimento que más consumiste en esta partida', {
size: 70,
fill: 0x32CD32,
font: "Impact"
});
mostConsumedText.anchor.set(0.5, 0.5);
mostConsumedText.x = 2048 / 2;
mostConsumedText.y = 1050;
game.addChild(mostConsumedText);
var nutritionalInfo = getNutritionalInfo();
var nutritionTitleText = new Text2(nutritionalInfo.title, {
size: 80,
fill: 0xFFD700,
font: "Impact"
});
nutritionTitleText.anchor.set(0.5, 0.5);
nutritionTitleText.x = 2048 / 2;
nutritionTitleText.y = 1200;
game.addChild(nutritionTitleText);
var nutritionInfoText = new Text2(nutritionalInfo.info, {
size: 55,
fill: 0xFFFFFF,
font: "Impact"
});
nutritionInfoText.anchor.set(0.5, 0);
nutritionInfoText.x = 2048 / 2;
nutritionInfoText.y = 1250;
game.addChild(nutritionInfoText);
// Create animated restart button
var restartButton = LK.getAsset('restartButton', {
width: 700,
height: 140,
color: 0x32CD32,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
restartButton.x = 2048 / 2;
restartButton.y = 1650;
game.addChild(restartButton);
var restartText = new Text2('Jugar de nuevo', {
size: 80,
fill: 0xFFFFFF,
font: "Impact"
});
restartText.anchor.set(0.5, 0.5);
restartText.x = 2048 / 2;
restartText.y = 1650;
game.addChild(restartText);
// Animate button with pulsing effect
function animateGameOverRestartButton() {
tween(restartButton, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(restartButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: animateGameOverRestartButton
});
}
});
tween(restartText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(restartText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut
});
}
});
}
animateGameOverRestartButton();
// Add click handler for restart
restartButton.down = function () {
showStartScreen();
};
restartText.down = function () {
showStartScreen();
};
}
// Show custom game over message for energy depletion
function showCustomGameOver() {
var finalEnergy = storage.finalEnergy || energy;
var finalTime = storage.finalTime || Math.floor((LK.ticks - gameStartTime) / 60);
var reason = storage.gameEndReason || 'fatiga';
var message = '';
if (finalEnergy >= 25) {
message = '¡NutriMáster!';
} else if (finalEnergy >= 15) {
message = '¡Buen cazador de nutrientes!';
} else {
message = 'Sigue practicando, revisa tus elecciones';
}
// No Nutripoints awarded when not reaching maximum energy
// Create full screen overlay
var overlay = LK.getAsset('energyBarBg', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0
});
overlay.tint = 0x000000;
overlay.alpha = 0.9;
game.addChild(overlay);
// Title
var titleText = new Text2('FATIGA, FALTA DE ENERGÍA', {
size: 100,
fill: 0xFFD700,
font: "Impact"
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 400;
game.addChild(titleText);
// Score section removed
// Time played section
var timeText = new Text2('Tiempo jugado: ' + finalTime + ' segundos', {
size: 70,
fill: 0x00BFFF,
font: "Impact"
});
timeText.anchor.set(0.5, 0.5);
timeText.x = 2048 / 2;
timeText.y = 700;
game.addChild(timeText);
// Nutripoints encouragement message
var nutripointsEncourageText = new Text2('¡Sigue eligiendo bien para ganar Nutripoints!', {
size: 65,
fill: 0xFFD700,
font: "Impact"
});
nutripointsEncourageText.anchor.set(0.5, 0.5);
nutripointsEncourageText.x = 2048 / 2;
nutripointsEncourageText.y = 800;
game.addChild(nutripointsEncourageText);
// Message section with color based on performance
var messageColor = 0xFFFFFF;
if (finalEnergy >= 25) {
messageColor = 0xFFD700; // Gold for NutriMaster
} else if (finalEnergy >= 15) {
messageColor = 0x32CD32; // Green for good hunter
} else {
messageColor = 0xFF4500; // Orange for keep practicing
}
var messageText = new Text2(message, {
size: 80,
fill: messageColor,
font: "Impact"
});
messageText.anchor.set(0.5, 0.5);
messageText.x = 2048 / 2;
messageText.y = 900;
game.addChild(messageText);
// Add nutritional information section
var mostConsumedText = new Text2('Alimento que más consumiste en esta partida', {
size: 70,
fill: 0x32CD32,
font: "Impact"
});
mostConsumedText.anchor.set(0.5, 0.5);
mostConsumedText.x = 2048 / 2;
mostConsumedText.y = 1000;
game.addChild(mostConsumedText);
var nutritionalInfo = getNutritionalInfo();
var nutritionTitleText = new Text2(nutritionalInfo.title, {
size: 80,
fill: 0xFFD700,
font: "Impact"
});
nutritionTitleText.anchor.set(0.5, 0.5);
nutritionTitleText.x = 2048 / 2;
nutritionTitleText.y = 1150;
game.addChild(nutritionTitleText);
var nutritionInfoText = new Text2(nutritionalInfo.info, {
size: 55,
fill: 0xFFFFFF,
font: "Impact"
});
nutritionInfoText.anchor.set(0.5, 0);
nutritionInfoText.x = 2048 / 2;
nutritionInfoText.y = 1200;
game.addChild(nutritionInfoText);
// Create animated restart button
var restartButton = LK.getAsset('restartButton', {
width: 700,
height: 140,
color: 0x32CD32,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
restartButton.x = 2048 / 2;
restartButton.y = 1600;
game.addChild(restartButton);
var restartText = new Text2('Jugar de nuevo', {
size: 80,
fill: 0xFFFFFF,
font: "Impact"
});
restartText.anchor.set(0.5, 0.5);
restartText.x = 2048 / 2;
restartText.y = 1600;
game.addChild(restartText);
// Animate button with pulsing effect
function animateRestartButton() {
tween(restartButton, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(restartButton, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: animateRestartButton
});
}
});
tween(restartText, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 800,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(restartText, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 800,
easing: tween.easeInOut
});
}
});
}
animateRestartButton();
// Add click handler for restart
restartButton.down = function () {
showStartScreen();
};
restartText.down = function () {
showStartScreen();
};
}
// Start countdown and restart game
function startCountdown() {
// Clear all game objects
for (var i = fallingItems.length - 1; i >= 0; i--) {
fallingItems[i].destroy();
}
fallingItems = [];
game.removeChildren();
// Reset all game variables
energy = 15;
lives = 3;
fallSpeed = 350 / 60;
lastSpeedIncrease = 0;
lastWaterSpawn = 0;
gameStartTime = 0;
foodsCaught = 0;
anxietyBombsActive = false;
lastSpawnTime = 0;
lastAnxietySpawnTime = 0;
expertMessageShown = false;
gameActive = true; // Reactivate game
gameStarted = true; // Ensure game logic runs during countdown and game
expertModeTimer = 0; // Reset expert mode timer
gameNutripoints = 0; // Reset current game Nutripoints
// Score reset removed
// Clear GUI elements to reset them properly
LK.gui.topLeft.removeChildren();
LK.gui.topRight.removeChildren();
LK.gui.top.removeChildren();
// Reset UI variable references
totalNutripointsText = null;
pauseButton = null;
// Reset food counts
foodCounts = {
'apple': 0,
'banana': 0,
'hardEgg': 0,
'broccoli': 0,
'carrot': 0,
'wholeBread': 0,
'waterBottle': 0
};
// Show countdown
var countdownNumbers = [3, 2, 1];
var currentCount = 0;
function showCountdownNumber() {
if (currentCount < countdownNumbers.length) {
var countText = new Text2(countdownNumbers[currentCount].toString(), {
size: 250,
fill: 0xFFFF00,
font: "Impact"
});
countText.anchor.set(0.5, 0.5);
countText.x = 2048 / 2;
countText.y = 2732 / 2;
game.addChild(countText);
// Animate countdown number
tween(countText, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
countText.destroy();
currentCount++;
if (currentCount < countdownNumbers.length) {
showCountdownNumber();
} else {
// Start new game
initializeGame();
// Force UI update after initialization to show correct values
updateUI();
}
}
});
}
}
showCountdownNumber();
}
// Screen management functions
function showStartScreen() {
currentScreen = 'start';
gameStarted = false; // Reset game started state
gamePaused = false; // Reset pause state
game.removeChildren();
LK.gui.topLeft.removeChildren();
LK.gui.topRight.removeChildren();
if (!startScreen) {
startScreen = new StartScreen();
}
game.addChild(startScreen);
}
function handleStartScreenButton(buttonType) {
switch (buttonType) {
case 'PLAY':
// Find the PLAY button and animate it
for (var i = 0; i < startScreen.buttons.length; i++) {
if (startScreen.buttons[i].type === 'PLAY') {
var playButton = startScreen.buttons[i];
// Set gameStarted immediately to enable game logic
gameStarted = true;
// Animate button press
tween(playButton.bg, {
scaleX: 0.95,
scaleY: 0.95,
tint: 0x228B22
}, {
duration: 150,
onFinish: function onFinish() {
tween(playButton.bg, {
scaleX: 1.0,
scaleY: 1.0,
tint: 0x32CD32
}, {
duration: 150,
onFinish: function onFinish() {
// Start game immediately after animation
startGame();
}
});
}
});
tween(playButton.text, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 150,
onFinish: function onFinish() {
tween(playButton.text, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 150
});
}
});
break;
}
}
break;
case 'MISIONES':
showMissionsScreen();
break;
case 'TIENDA':
showStoreScreen();
break;
case 'PREGUNTAS':
showFAQScreen();
break;
}
}
function startGame() {
currentScreen = 'game';
game.removeChildren();
startCountdown();
}
function showMissionsScreen() {
currentScreen = 'missions';
game.removeChildren();
LK.gui.topLeft.removeChildren();
LK.gui.topRight.removeChildren();
if (!missionsScreen) {
missionsScreen = new MissionsScreen();
}
game.addChild(missionsScreen);
updateMissionsDisplay();
}
function showStoreScreen() {
currentScreen = 'store';
game.removeChildren();
LK.gui.topLeft.removeChildren();
LK.gui.topRight.removeChildren();
if (!storeScreen) {
storeScreen = new StoreScreen();
}
game.addChild(storeScreen);
updateStoreDisplay();
}
function showFAQScreen() {
currentScreen = 'faq';
game.removeChildren();
LK.gui.topLeft.removeChildren();
LK.gui.topRight.removeChildren();
if (!faqScreen) {
faqScreen = new FAQScreen();
}
game.addChild(faqScreen);
updateFAQDisplay();
}
// Mission system functions - handled by MissionManager class
function updateMissionsDisplay() {
if (!missionsScreen) return;
missionsScreen.missionsContainer.removeChildren();
missionsScreen.progressBars = [];
// Ensure missionManager and its activeMissions exist
if (!missionManager || !missionManager.activeMissions) {
if (missionManagerInstance) {
missionManagerInstance.generateNewDailyMissions();
}
}
var activeMissions = null;
// Safe access to activeMissions with multiple checks
if (missionManager && missionManager.activeMissions && Array.isArray(missionManager.activeMissions)) {
activeMissions = missionManager.activeMissions;
} else if (missionManagerInstance && missionManagerInstance.activeMissions && Array.isArray(missionManagerInstance.activeMissions)) {
activeMissions = missionManagerInstance.activeMissions;
} else {
activeMissions = [];
}
if (!activeMissions || activeMissions.length === 0) {
if (missionManagerInstance) {
missionManagerInstance.generateNewDailyMissions();
// Re-check after generation with safe access
if (missionManager && missionManager.activeMissions && Array.isArray(missionManager.activeMissions)) {
activeMissions = missionManager.activeMissions;
} else if (missionManagerInstance && missionManagerInstance.activeMissions && Array.isArray(missionManagerInstance.activeMissions)) {
activeMissions = missionManagerInstance.activeMissions;
} else {
activeMissions = [];
}
}
}
// Final safety check after all attempts
if (!activeMissions || !Array.isArray(activeMissions) || activeMissions.length === 0) {
// Create default empty state display
var noMissionsText = new Text2('No hay misiones disponibles', {
size: 60,
fill: 0xFFFFFF,
font: "Impact"
});
noMissionsText.anchor.set(0.5, 0.5);
noMissionsText.x = 2048 / 2;
noMissionsText.y = 200;
missionsScreen.missionsContainer.addChild(noMissionsText);
return;
}
// Additional validation: check if array elements exist and are accessible
var validMissionsCount = 0;
if (activeMissions && Array.isArray(activeMissions) && activeMissions.length > 0) {
for (var checkIndex = 0; checkIndex < activeMissions.length; checkIndex++) {
if (checkIndex < activeMissions.length && activeMissions[checkIndex] && _typeof(activeMissions[checkIndex]) === 'object') {
validMissionsCount++;
}
}
}
if (validMissionsCount === 0) {
var noValidMissionsText = new Text2('Error: No se pudieron cargar las misiones', {
size: 60,
fill: 0xFF6B35,
font: "Impact"
});
noValidMissionsText.anchor.set(0.5, 0.5);
noValidMissionsText.x = 2048 / 2;
noValidMissionsText.y = 200;
missionsScreen.missionsContainer.addChild(noValidMissionsText);
return;
}
// Final safety check before loop
if (!activeMissions || !Array.isArray(activeMissions) || activeMissions.length === 0) {
return;
}
for (var i = 0; i < activeMissions.length; i++) {
// Comprehensive safety check for array bounds and element existence
if (!activeMissions || !Array.isArray(activeMissions) || i >= activeMissions.length) {
continue;
}
// Safe access to array element with additional validation
var mission = null;
try {
if (activeMissions[i] !== undefined && activeMissions[i] !== null) {
mission = activeMissions[i];
} else {
continue;
}
} catch (e) {
continue;
}
// Safety check for mission object
if (!mission || _typeof(mission) !== 'object') {
continue;
}
// Ensure mission has required properties
if (!mission.text || typeof mission.metaTotal === 'undefined' || typeof mission.avanceActual === 'undefined') {
continue;
}
var missionBg = LK.getAsset('restartButton', {
width: 1800,
height: 280,
anchorX: 0.5,
anchorY: 0.5
});
missionBg.tint = mission.completada ? 0x27AE60 : 0x34495E;
missionBg.x = 2048 / 2;
missionBg.y = 50 + i * 320; // Adjusted Y position to start from 0 in scrollable container
missionsScreen.missionsContainer.addChild(missionBg);
var missionText = new Text2((mission.completada ? '✔️ ' : '') + mission.text, {
size: 55,
fill: 0xFFFFFF,
font: "Impact"
});
missionText.anchor.set(0.5, 0.5);
missionText.x = 2048 / 2;
missionText.y = 30 + i * 320; // Adjusted Y position
missionsScreen.missionsContainer.addChild(missionText);
// Progress bar background
var progressBg = LK.getAsset('energyBarBg', {
width: 450,
height: 25,
anchorX: 0.5,
anchorY: 0.5
});
progressBg.tint = 0x666666;
progressBg.alpha = 0.4;
progressBg.x = 2048 / 2 - 225;
progressBg.y = 100 + i * 320; // Adjusted Y position
missionsScreen.missionsContainer.addChild(progressBg);
// Progress bar fill
var progressWidth = mission.avanceActual / mission.metaTotal * 450;
var progressFill = LK.getAsset('energyBarFill', {
width: progressWidth,
height: 25,
anchorX: 0,
anchorY: 0.5
});
progressFill.tint = 0x4CAF50;
progressFill.x = 2048 / 2 - 225;
progressFill.y = 100 + i * 320; // Adjusted Y position
missionsScreen.missionsContainer.addChild(progressFill);
missionsScreen.progressBars.push(progressFill);
// Progress text
var progressText = new Text2(mission.avanceActual + ' / ' + mission.metaTotal, {
size: 45,
fill: 0xFFFFFF,
font: "Impact"
});
progressText.anchor.set(0.5, 0.5);
progressText.x = 2048 / 2 + 250;
progressText.y = 100 + i * 320; // Adjusted Y position
missionsScreen.missionsContainer.addChild(progressText);
if (mission.completada) {
var rewardText = new Text2('Completada ✔️ +2 Nutripoints', {
size: 45,
fill: 0xFFD700,
font: "Impact"
});
rewardText.anchor.set(0.5, 0.5);
rewardText.x = 2048 / 2;
rewardText.y = 140 + i * 320; // Adjusted Y position
missionsScreen.missionsContainer.addChild(rewardText);
}
}
// Update scroll bounds after adding all missions
if (missionsScreen.updateScrollBounds) {
missionsScreen.updateScrollBounds();
}
}
// Store system functions
function updateStoreDisplay() {
if (!storeScreen) return;
storeScreen.storeContainer.removeChildren();
var playerNutripoints = storage.totalNutripoints || 0;
var ownedItems = storage.ownedItems || [];
for (var i = 0; i < storeItems.length; i++) {
var item = storeItems[i];
var owned = ownedItems.indexOf(item.id) !== -1;
var canAfford = playerNutripoints >= item.costo;
var itemBg = LK.getAsset('restartButton', {
width: 700,
height: 150,
anchorX: 0.5,
anchorY: 0.5
});
itemBg.tint = owned ? 0x27AE60 : canAfford ? 0x3498DB : 0x95A5A6;
itemBg.x = i % 2 * 800 + 500;
itemBg.y = 500 + Math.floor(i / 2) * 200;
storeScreen.storeContainer.addChild(itemBg);
var nameText = new Text2(item.nombre, {
size: 45,
fill: 0xFFFFFF,
font: "Impact"
});
nameText.anchor.set(0.5, 0.5);
nameText.x = itemBg.x;
nameText.y = itemBg.y - 20;
storeScreen.storeContainer.addChild(nameText);
var costText = new Text2(owned ? 'COMPRADO' : item.costo + ' Nutripoints', {
size: 35,
fill: owned ? 0x2ECC71 : canAfford ? 0xFFD700 : 0xE74C3C,
font: "Impact"
});
costText.anchor.set(0.5, 0.5);
costText.x = itemBg.x;
costText.y = itemBg.y + 20;
storeScreen.storeContainer.addChild(costText);
if (!owned && canAfford) {
itemBg.itemData = item;
(function (itemData) {
itemBg.down = function (x, y, obj) {
purchaseItem(itemData);
};
})(item);
}
}
}
function purchaseItem(item) {
if (!item || typeof item.costo === 'undefined') {
console.error('Invalid item data in purchaseItem');
return;
}
var playerNutripoints = storage.totalNutripoints || 0;
var ownedItems = storage.ownedItems || [];
if (playerNutripoints >= item.costo && ownedItems.indexOf(item.id) === -1) {
storage.totalNutripoints = playerNutripoints - item.costo;
ownedItems.push(item.id);
storage.ownedItems = ownedItems;
// Show purchase popup
var popup = LK.getAsset('restartButton', {
width: 800,
height: 200,
anchorX: 0.5,
anchorY: 0.5
});
popup.tint = 0x27AE60;
popup.x = 2048 / 2;
popup.y = 2732 / 2;
game.addChild(popup);
var popupText = new Text2('¡Nuevo artículo desbloqueado!', {
size: 60,
fill: 0xFFFFFF,
font: "Impact"
});
popupText.anchor.set(0.5, 0.5);
popupText.x = 2048 / 2;
popupText.y = 2732 / 2;
game.addChild(popupText);
LK.getSound('powerup').play();
// Remove popup after 2 seconds
LK.setTimeout(function () {
popup.destroy();
popupText.destroy();
updateStoreDisplay();
}, 2000);
}
}
// FAQ system functions
function updateFAQDisplay() {
if (!faqScreen) return;
// Initialize FAQ items with accordion functionality
faqScreen.createFAQItems();
}
// Initialize mission manager
var missionManagerInstance = new MissionManager();
missionManagerInstance.init();
// Initialize mission tracking variables properly
missionManager.gameStartTime = 0;
missionManager.lastGaseosaTime = -60; // Start with -60 to allow immediate tracking
missionManager.consecutiveWins = storage.consecutiveWins || 0;
missionManager.falsosInCurrentGame = 0;
missionManager.consecutiveHighEnergyWins = storage.consecutiveHighEnergyWins || 0;
missionManager.continuousPlayTime = storage.continuousPlayTime || 0;
// Initialize storage for persistent data
totalNutripoints = storage.totalNutripoints || 0;
// Pause menu functions
function showPauseMenu() {
if (!gameStarted || !gameActive) return;
gamePaused = true;
// Create overlay
var overlay = LK.getAsset('energyBarBg', {
width: 2048,
height: 2732,
anchorX: 0,
anchorY: 0
});
overlay.tint = 0x000000;
overlay.alpha = 0.8;
game.addChild(overlay);
// Pause menu container
pauseMenu = new Container();
game.addChild(pauseMenu);
// Title
var titleText = new Text2('JUEGO PAUSADO', {
size: 120,
fill: 0xFFD700,
font: "Impact"
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 800;
pauseMenu.addChild(titleText);
// Buttons data
var buttonData = [{
text: 'REANUDAR',
y: 1100,
color: 0x27AE60,
action: 'resume'
}, {
text: 'REINICIAR',
y: 1300,
color: 0xF39C12,
action: 'restart'
}, {
text: 'MENÚ PRINCIPAL',
y: 1500,
color: 0xE74C3C,
action: 'menu'
}];
// Create buttons
for (var i = 0; i < buttonData.length; i++) {
var buttonBg = LK.getAsset('restartButton', {
width: 600,
height: 120,
anchorX: 0.5,
anchorY: 0.5
});
buttonBg.tint = buttonData[i].color;
buttonBg.x = 2048 / 2;
buttonBg.y = buttonData[i].y;
pauseMenu.addChild(buttonBg);
var buttonText = new Text2(buttonData[i].text, {
size: 70,
fill: 0xFFFFFF,
font: "Impact"
});
buttonText.anchor.set(0.5, 0.5);
buttonText.x = 2048 / 2;
buttonText.y = buttonData[i].y;
pauseMenu.addChild(buttonText);
// Add click handlers
(function (action) {
buttonBg.down = function () {
handlePauseMenuAction(action);
};
buttonText.down = function () {
handlePauseMenuAction(action);
};
})(buttonData[i].action);
}
// Store overlay reference for cleanup
pauseMenu.overlay = overlay;
}
function handlePauseMenuAction(action) {
switch (action) {
case 'resume':
resumeGame();
break;
case 'restart':
restartGame();
break;
case 'menu':
returnToMainMenu();
break;
}
}
function resumeGame() {
if (pauseMenu) {
pauseMenu.overlay.destroy();
pauseMenu.destroy();
pauseMenu = null;
}
gamePaused = false;
}
function restartGame() {
if (pauseMenu) {
pauseMenu.overlay.destroy();
pauseMenu.destroy();
pauseMenu = null;
}
gamePaused = false;
startGame();
}
function returnToMainMenu() {
if (pauseMenu) {
pauseMenu.overlay.destroy();
pauseMenu.destroy();
pauseMenu = null;
}
gamePaused = false;
gameActive = false;
gameStarted = false;
showStartScreen();
}
// Initialize the start screen as the first state
showStartScreen();
;