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 _typeof8(o) { "@babel/helpers - typeof"; return _typeof8 = "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; }, _typeof8(o); } function _typeof7(o) { "@babel/helpers - typeof"; return _typeof7 = "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; }, _typeof7(o); } function _typeof6(o) { "@babel/helpers - typeof"; return _typeof6 = "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; }, _typeof6(o); } function _typeof5(o) { "@babel/helpers - typeof"; return _typeof5 = "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; }, _typeof5(o); } function _typeof4(o) { "@babel/helpers - typeof"; return _typeof4 = "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; }, _typeof4(o); } function _typeof3(o) { "@babel/helpers - typeof"; return _typeof3 = "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; }, _typeof3(o); } function _typeof2(o) { "@babel/helpers - typeof"; return _typeof2 = "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; }, _typeof2(o); } 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); } } // Function to reset all user progress data function resetAllUserProgress() { // Clear all mission-related storage storage.activeMissions = null; storage.missionsDate = null; storage.missionProgress = null; storage.consecutiveWins = null; storage.consecutiveHighEnergyWins = null; storage.continuousPlayTime = null; // Clear all nutripoints storage.totalNutripoints = 0; storage.lastLoginDate = null; // Clear all store data storage.ownedItems = null; // Clear any other game progress data storage.finalEnergy = null; storage.finalTime = null; storage.gameEndReason = null; // Reset local variables totalNutripoints = 0; gameNutripoints = 0; // Reset mission manager state if (missionManager) { missionManager.consecutiveWins = 0; missionManager.consecutiveHighEnergyWins = 0; missionManager.continuousPlayTime = 0; missionManager.falsosInCurrentGame = 0; missionManager.lastGaseosaTime = -60; missionManager.activeMissions = []; } // Regenerate fresh missions if (missionManagerInstance) { missionManagerInstance.generateNewDailyMissions(); } } // 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); // Update nutripoints display to reflect current (possibly reset) values if (startScreen && startScreen.nutripointsDisplay) { startScreen.nutripointsDisplay.setText('Nutripoints: ' + totalNutripoints); } } 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() { // Reset all user progress for fresh start resetAllUserProgress(); 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 - enhanced validation 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 comprehensive safety check before any array access try { // Validate the array structure completely if (!activeMissions || _typeof8(activeMissions) !== 'object' || !Array.isArray(activeMissions)) { console.error('activeMissions is not a valid array'); return; } // Check array length and first element access safety if (activeMissions.length === 0) { console.error('activeMissions array is empty'); return; } // Test safe access to first element if it exists if (activeMissions.length > 0) { var testElement = activeMissions[0]; if (testElement === undefined || testElement === null) { console.error('First mission element is undefined or null'); return; } } } catch (error) { console.error('Error in activeMissions validation:', error); 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++) { // Enhanced safety checks for array access if (checkIndex >= 0 && checkIndex < activeMissions.length && activeMissions.hasOwnProperty(checkIndex) && activeMissions[checkIndex] !== undefined && activeMissions[checkIndex] !== null && 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 validation before loop if (!activeMissions || !Array.isArray(activeMissions) || activeMissions.length === 0) { return; } // Additional safety check for array integrity var safeArrayLength = 0; try { if (activeMissions && Array.isArray(activeMissions)) { safeArrayLength = activeMissions.length; } } catch (e) { console.error('Error checking array length:', e); return; } if (safeArrayLength === 0) { return; } // Create a safe copy of the array to prevent modification during iteration var safeMissions = []; try { // Validate activeMissions before copying if (!activeMissions || !Array.isArray(activeMissions) || activeMissions.length === 0) { console.error('activeMissions is invalid for copying'); return; } // Copy missions with full validation for (var copyIndex = 0; copyIndex < activeMissions.length; copyIndex++) { var missionToCopy = null; try { // Enhanced bounds checking with additional safety - check if array element exists before accessing if (activeMissions && Array.isArray(activeMissions) && copyIndex >= 0 && copyIndex < activeMissions.length && activeMissions.hasOwnProperty && activeMissions.hasOwnProperty(copyIndex) && copyIndex in activeMissions && activeMissions[copyIndex] !== undefined && activeMissions[copyIndex] !== null && _typeof6(activeMissions[copyIndex]) === 'object') { // Additional check to prevent accessing undefined array elements if (activeMissions[copyIndex] && activeMissions[copyIndex].hasOwnProperty && typeof activeMissions[copyIndex].hasOwnProperty === 'function') { missionToCopy = activeMissions[copyIndex]; // Validate mission structure with enhanced safety if (missionToCopy && _typeof6(missionToCopy) === 'object' && missionToCopy.hasOwnProperty('text') && missionToCopy.hasOwnProperty('metaTotal') && missionToCopy.hasOwnProperty('avanceActual') && missionToCopy.text !== undefined && missionToCopy.metaTotal !== undefined && missionToCopy.avanceActual !== undefined) { safeMissions.push(missionToCopy); } } } } catch (copyError) { console.error('Error copying mission at index', copyIndex, ':', copyError); continue; } } } catch (e) { console.error('Error creating safe missions copy:', e); return; } // Additional validation for safeMissions array if (!safeMissions || !Array.isArray(safeMissions)) { console.error('safeMissions is not a valid array'); return; } // Use safe copy for rendering if (safeMissions.length === 0) { var noMissionsText = new Text2('No hay misiones válidas 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 length check before loop var safeLoopLength = 0; try { if (safeMissions && Array.isArray(safeMissions)) { safeLoopLength = safeMissions.length; } } catch (e) { console.error('Error getting safe missions length:', e); return; } // Final validation before starting the loop if (!safeMissions || !Array.isArray(safeMissions) || safeLoopLength === 0) { console.error('safeMissions is not valid for rendering'); return; } for (var i = 0; i < safeLoopLength; i++) { var mission = null; try { // Enhanced safe access with comprehensive bounds checking if (!safeMissions || !Array.isArray(safeMissions)) { console.error('safeMissions became invalid during loop at index', i); return; } if (i < 0 || i >= safeMissions.length || i >= safeLoopLength) { console.error('Index out of bounds:', i, 'length:', safeMissions.length); continue; } // Additional safety check for array element existence if (!(i in safeMissions) || !safeMissions.hasOwnProperty(i)) { console.error('Array index does not exist:', i); continue; } // Check if the element is defined and not null if (safeMissions[i] === undefined || safeMissions[i] === null) { console.error('Mission element is undefined or null at index', i); continue; } // Enhanced safe access with additional bounds and type checking if (safeMissions && Array.isArray(safeMissions) && i >= 0 && i < safeMissions.length && i < safeLoopLength && safeMissions.hasOwnProperty && safeMissions.hasOwnProperty(i) && i in safeMissions && safeMissions[i] !== undefined && safeMissions[i] !== null && _typeof7(safeMissions[i]) === 'object') { try { mission = safeMissions[i]; // Additional validation after assignment if (!mission || _typeof7(mission) !== 'object') { console.error('Mission object is not valid after assignment at index', i); continue; } } catch (accessError) { console.error('Error accessing mission at index', i, ':', accessError); continue; } } else { console.error('Invalid index access:', i, 'of', safeMissions ? safeMissions.length : 'undefined array'); continue; } } catch (e) { console.error('Error accessing safe mission at index', i, ':', e); continue; } // Final mission validation with comprehensive property checks if (!mission || _typeof5(mission) !== 'object' || !mission.hasOwnProperty || typeof mission.hasOwnProperty !== 'function' || !mission.hasOwnProperty('text') || !mission.hasOwnProperty('metaTotal') || !mission.hasOwnProperty('avanceActual') || !mission.text || mission.metaTotal === undefined || mission.metaTotal === null || mission.avanceActual === undefined || mission.avanceActual === null) { console.error('Mission object is invalid or missing required properties:', mission); continue; } // Additional null safety check before using mission properties if (mission.hasOwnProperty('text') && mission.hasOwnProperty('metaTotal') && mission.hasOwnProperty('avanceActual') && mission.text !== undefined && mission.metaTotal !== undefined && mission.avanceActual !== undefined) { // Mission is safe to use } else { console.error('Mission failed final safety check at index', i); continue; } // Additional safety check to prevent undefined array access if (!safeMissions || !Array.isArray(safeMissions) || i >= safeMissions.length || !safeMissions[i]) { console.error('Mission array became invalid during iteration at index', i); return; } // Final safety check before accessing mission properties if (!mission || !mission.hasOwnProperty || typeof mission.text !== 'string' || typeof mission.metaTotal !== 'number' || typeof mission.avanceActual !== 'number') { console.error('Mission properties are invalid for rendering at index', i); 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 with safe calculation var safeCurrentProgress = mission.avanceActual !== undefined && mission.avanceActual !== null ? mission.avanceActual : 0; var safeTotalProgress = mission.metaTotal !== undefined && mission.metaTotal !== null && mission.metaTotal > 0 ? mission.metaTotal : 1; var progressWidth = Math.min(450, Math.max(0, safeCurrentProgress / safeTotalProgress * 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); // Safe progress bars array check if (missionsScreen.progressBars && Array.isArray(missionsScreen.progressBars)) { missionsScreen.progressBars.push(progressFill); } // Progress text with safe value access var currentProgress = mission.avanceActual !== undefined && mission.avanceActual !== null ? mission.avanceActual : 0; var totalProgress = mission.metaTotal !== undefined && mission.metaTotal !== null ? mission.metaTotal : 1; var progressText = new Text2(currentProgress + ' / ' + totalProgress, { 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(); ;
===================================================================
--- original.js
+++ change.js
@@ -910,8 +910,16 @@
/****
* Game Code
****/
// Game state management
+function _typeof8(o) {
+ "@babel/helpers - typeof";
+ return _typeof8 = "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;
+ }, _typeof8(o);
+}
function _typeof7(o) {
"@babel/helpers - typeof";
return _typeof7 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
@@ -2472,9 +2480,9 @@
activeMissions = [];
}
}
}
- // Final safety check after all attempts
+ // Final safety check after all attempts - enhanced validation
if (!activeMissions || !Array.isArray(activeMissions) || activeMissions.length === 0) {
// Create default empty state display
var noMissionsText = new Text2('No hay misiones disponibles', {
size: 60,
@@ -2486,8 +2494,32 @@
noMissionsText.y = 200;
missionsScreen.missionsContainer.addChild(noMissionsText);
return;
}
+ // Additional comprehensive safety check before any array access
+ try {
+ // Validate the array structure completely
+ if (!activeMissions || _typeof8(activeMissions) !== 'object' || !Array.isArray(activeMissions)) {
+ console.error('activeMissions is not a valid array');
+ return;
+ }
+ // Check array length and first element access safety
+ if (activeMissions.length === 0) {
+ console.error('activeMissions array is empty');
+ return;
+ }
+ // Test safe access to first element if it exists
+ if (activeMissions.length > 0) {
+ var testElement = activeMissions[0];
+ if (testElement === undefined || testElement === null) {
+ console.error('First mission element is undefined or null');
+ return;
+ }
+ }
+ } catch (error) {
+ console.error('Error in activeMissions validation:', error);
+ 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++) {
@@ -2593,8 +2625,27 @@
}
for (var i = 0; i < safeLoopLength; i++) {
var mission = null;
try {
+ // Enhanced safe access with comprehensive bounds checking
+ if (!safeMissions || !Array.isArray(safeMissions)) {
+ console.error('safeMissions became invalid during loop at index', i);
+ return;
+ }
+ if (i < 0 || i >= safeMissions.length || i >= safeLoopLength) {
+ console.error('Index out of bounds:', i, 'length:', safeMissions.length);
+ continue;
+ }
+ // Additional safety check for array element existence
+ if (!(i in safeMissions) || !safeMissions.hasOwnProperty(i)) {
+ console.error('Array index does not exist:', i);
+ continue;
+ }
+ // Check if the element is defined and not null
+ if (safeMissions[i] === undefined || safeMissions[i] === null) {
+ console.error('Mission element is undefined or null at index', i);
+ continue;
+ }
// Enhanced safe access with additional bounds and type checking
if (safeMissions && Array.isArray(safeMissions) && i >= 0 && i < safeMissions.length && i < safeLoopLength && safeMissions.hasOwnProperty && safeMissions.hasOwnProperty(i) && i in safeMissions && safeMissions[i] !== undefined && safeMissions[i] !== null && _typeof7(safeMissions[i]) === 'object') {
try {
mission = safeMissions[i];