/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // Dot class for interactive dots in the puzzle var Dot = Container.expand(function () { var self = Container.call(this); // Create a visual representation for the dot var dotGraphics = self.attachAsset('Street', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.8, scaleY: 1.8, alpha: 0 }); // Dot properties self.isActive = false; self.gridX = 0; self.gridY = 0; self.instrumentIndex = 0; self.currentInstrument = null; // Array of instrument image IDs for first row (dots 1-5) self.instruments = ['Blank', 'Saxophone', 'Drum', 'Gutair', 'Harp', 'Flute']; // Array of image IDs for dots 21-25 (bottom row) self.specialInstruments = ['Blank', 'PJ', 'KJ', 'Harmony', 'Khalida', 'Sapphire']; // Method to toggle dot state self.toggle = function () { self.isActive = !self.isActive; }; // Method to cycle through instruments for first row (dots 1-5) self.cycleInstrument = function () { // Remove current instrument if it exists and free it from usedInstruments if (self.currentInstrument) { var currentInstrumentId = self.instruments[self.instrumentIndex]; if (currentInstrumentId !== 'Blank' && usedInstruments[currentInstrumentId] === self) { delete usedInstruments[currentInstrumentId]; } self.removeChild(self.currentInstrument); self.currentInstrument = null; } // Find next available instrument var startIndex = self.instrumentIndex; var found = false; do { self.instrumentIndex = (self.instrumentIndex + 1) % self.instruments.length; var instrumentId = self.instruments[self.instrumentIndex]; // Check if instrument is available (Blank is always available) if (instrumentId === 'Blank' || !usedInstruments[instrumentId]) { found = true; // Mark non-blank instruments as used if (instrumentId !== 'Blank') { usedInstruments[instrumentId] = self; } // Create new instrument image self.currentInstrument = self.attachAsset(instrumentId, { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0 }); break; } } while (self.instrumentIndex !== startIndex); // If no available instrument found, stay on current (shouldn't happen with 6 instruments for 5 dots) if (!found) { self.instrumentIndex = startIndex; } }; // Method to cycle through special images for dots 21-25 (bottom row) self.cycleSpecialInstrument = function () { // Remove current instrument if it exists if (self.currentInstrument) { // Remove from usedSpecialInstruments if not Blank if (typeof usedSpecialInstruments !== "undefined" && self.specialInstruments && typeof self.specialInstrumentIndex === "number") { var prevId = self.specialInstruments[self.specialInstrumentIndex]; if (prevId !== 'Blank' && usedSpecialInstruments[prevId] === self) { delete usedSpecialInstruments[prevId]; } } self.removeChild(self.currentInstrument); self.currentInstrument = null; } // Find next available special instrument (no duplicates except Blank) if (typeof usedSpecialInstruments === "undefined") { usedSpecialInstruments = {}; } if (typeof self.specialInstrumentIndex !== "number") self.specialInstrumentIndex = 0; self.specialInstrumentIndex = typeof self.specialInstrumentIndex === "number" ? self.specialInstrumentIndex : 0; var startIndex = self.specialInstrumentIndex; var found = false; do { self.specialInstrumentIndex = (self.specialInstrumentIndex + 1) % self.specialInstruments.length; var instrumentId = self.specialInstruments[self.specialInstrumentIndex]; // Only allow Blank or unused if (instrumentId === 'Blank' || !usedSpecialInstruments[instrumentId]) { found = true; // Mark as used if not Blank if (instrumentId !== 'Blank') { usedSpecialInstruments[instrumentId] = self; } // Slightly decrease the size of all special images for dots 21-25 var scaleX = 0.85; var scaleY = 0.85; if (instrumentId === 'Harmony') { scaleX = 1.45; scaleY = 1.45; } // Move Khalida or Harmony image up by 10 pixels, move KJ down by 5 pixels var extraY = 0; if (instrumentId === 'Khalida' || instrumentId === 'Harmony') { extraY = -10; } if (instrumentId === 'KJ') { extraY = 5; } self.currentInstrument = self.attachAsset(instrumentId, { anchorX: 0.5, anchorY: 0.5, scaleX: scaleX, scaleY: scaleY, y: extraY }); break; } } while (self.specialInstrumentIndex !== startIndex); // If no available instrument found, stay on current (shouldn't happen) if (!found) { self.specialInstrumentIndex = startIndex; } }; // Touch/click handler self.down = function (x, y, obj) { // Only cycle instruments for dots 1-5 (first row) if (self.gridY === 0) { self.cycleInstrument(); } // Dots 21-25 (bottom row, gridY === 4, gridX 0-4) else if (self.gridY === 4) { self.cycleSpecialInstrument(); } // Dots 16-20 (row 4, gridY === 3, gridX 0-4) else if (self.gridY === 3) { // Animal images to cycle through if (!self.animalImages) { self.animalImages = ['Blank', 'Cat', 'Dog', 'Fish', 'Frog', 'Turtle']; self.animalIndex = 0; } // Setup usedAnimalImages global tracker if not present if (typeof usedAnimalImages === "undefined") { usedAnimalImages = {}; } // Remove current animal image if exists and update usedAnimalImages if (self.currentInstrument) { if (typeof self.animalIndex === "number") { var prevAnimalId = self.animalImages[self.animalIndex]; if (prevAnimalId !== 'Blank' && usedAnimalImages[prevAnimalId] === self) { delete usedAnimalImages[prevAnimalId]; } } self.removeChild(self.currentInstrument); self.currentInstrument = null; } // Cycle to next available animal image (no duplicates except Blank) var startIndex = typeof self.animalIndex === "number" ? self.animalIndex : 0; var found = false; var tries = 0; do { self.animalIndex = (typeof self.animalIndex === "number" ? self.animalIndex : 0) + 1; if (self.animalIndex >= self.animalImages.length) self.animalIndex = 0; var animalId = self.animalImages[self.animalIndex]; // Only allow Blank or unused if (animalId === 'Blank' || !usedAnimalImages[animalId]) { found = true; // Mark as used if not Blank if (animalId !== 'Blank') { usedAnimalImages[animalId] = self; } self.currentInstrument = self.attachAsset(animalId, { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0 }); break; } tries++; } while (self.animalIndex !== startIndex && tries < self.animalImages.length + 1); // If no available animal found, stay on current (shouldn't happen) if (!found) { self.animalIndex = startIndex; } } // Dots 6-10 (row 2, gridY === 1, gridX 0-4) else if (self.gridY === 1) { // Food images to cycle through if (!self.foodImages) { self.foodImages = ['Blank', 'Pizza', 'Chips', 'Icecream', 'Donut', 'Spaghetti']; self.foodIndex = 0; } // Setup usedFoodImages global tracker if not present if (typeof usedFoodImages === "undefined") { usedFoodImages = {}; } // Remove current food image if exists and update usedFoodImages if (self.currentInstrument) { if (typeof self.foodIndex === "number") { var prevFoodId = self.foodImages[self.foodIndex]; if (prevFoodId !== 'Blank' && usedFoodImages[prevFoodId] === self) { delete usedFoodImages[prevFoodId]; } } self.removeChild(self.currentInstrument); self.currentInstrument = null; } // Cycle to next available food image (no duplicates except Blank) var startFoodIndex = typeof self.foodIndex === "number" ? self.foodIndex : 0; var foundFood = false; var foodTries = 0; do { self.foodIndex = (typeof self.foodIndex === "number" ? self.foodIndex : 0) + 1; if (self.foodIndex >= self.foodImages.length) self.foodIndex = 0; var foodId = self.foodImages[self.foodIndex]; // Only allow Blank or unused if (foodId === 'Blank' || !usedFoodImages[foodId]) { foundFood = true; // Mark as used if not Blank if (foodId !== 'Blank') { usedFoodImages[foodId] = self; } self.currentInstrument = self.attachAsset(foodId, { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0 }); break; } foodTries++; } while (self.foodIndex !== startFoodIndex && foodTries < self.foodImages.length + 1); // If no available food found, stay on current (shouldn't happen) if (!foundFood) { self.foodIndex = startFoodIndex; } } else if (self.gridY === 2) { // Toy images to cycle through if (!self.toyImages) { self.toyImages = ['Blank', 'Lego', 'Dolls', 'Basketball', 'Videogame', 'Plushtoy']; self.toyIndex = 0; } // Setup usedToyImages global tracker if not present if (typeof usedToyImages === "undefined") { usedToyImages = {}; } // Remove current toy image if exists and update usedToyImages if (self.currentInstrument) { if (typeof self.toyIndex === "number") { var prevToyId = self.toyImages[self.toyIndex]; if (prevToyId !== 'Blank' && usedToyImages[prevToyId] === self) { delete usedToyImages[prevToyId]; } } self.removeChild(self.currentInstrument); self.currentInstrument = null; } // Cycle to next available toy image (no duplicates except Blank) var startToyIndex = typeof self.toyIndex === "number" ? self.toyIndex : 0; var foundToy = false; var toyTries = 0; do { self.toyIndex = (typeof self.toyIndex === "number" ? self.toyIndex : 0) + 1; if (self.toyIndex >= self.toyImages.length) self.toyIndex = 0; var toyId = self.toyImages[self.toyIndex]; // Only allow Blank or unused if (toyId === 'Blank' || !usedToyImages[toyId]) { foundToy = true; // Mark as used if not Blank if (toyId !== 'Blank') { usedToyImages[toyId] = self; } self.currentInstrument = self.attachAsset(toyId, { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0 }); break; } toyTries++; } while (self.toyIndex !== startToyIndex && toyTries < self.toyImages.length + 1); // If no available toy found, stay on current (shouldn't happen) if (!foundToy) { self.toyIndex = startToyIndex; } } self.toggle(); // Update clues with strikethrough after changing dot if (typeof updateCluesWithStrikethrough === 'function') { updateCluesWithStrikethrough(); } }; // Initialize dot as inactive // Initialize with blank instrument self.currentInstrument = self.attachAsset('Blank', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0 }); return self; }); // Puzzle class for managing a puzzle element in the game var Puzzle = Container.expand(function () { var self = Container.call(this); // Add a 4x5 asset to the puzzle and scale it to be exactly 2048 wide var targetWidth = 2048; var assetWidth = 1000; var scale = targetWidth / assetWidth; // Center horizontally, align to top var puzzleImage = self.attachAsset('4x5', { anchorX: 0.5, anchorY: 0, x: 2048 / 2, y: 0, scaleX: scale, scaleY: scale }); // (Story asset removed) // (Clue images and clue text removed) // Create 25 dots in a 5x5 grid self.dots = []; var gridSize = 5; var dotSpacing = targetWidth / (gridSize + 1); // Distribute dots evenly across the width var gridHeight = puzzleImage.height * scale; var verticalSpacing = gridHeight / (gridSize + 1); for (var row = 0; row < gridSize; row++) { for (var col = 0; col < gridSize; col++) { var dot = new Dot(); dot.gridX = col; dot.gridY = row; // Initialize all indices to 0 for consistent reset state dot.instrumentIndex = 0; dot.specialInstrumentIndex = 0; dot.animalIndex = 0; dot.foodIndex = 0; dot.toyIndex = 0; // Position dots over the 4x5 asset dot.x = (col + 1) * dotSpacing; dot.y = (row + 1) * verticalSpacing; self.dots.push(dot); self.addChild(dot); } } // Generate randomized solution and clues var generator = new PuzzleGenerator(); self.targetSolution = generator.generateSolution(); self.generatedClues = generator.generateClues(self.targetSolution); // Example: puzzle state self.isSolved = false; // Method to check if puzzle is solved according to target solution self.checkSolved = function () { // Use the generated target solution var targetSolution = self.targetSolution || {}; // Check if all dots match the target solution var allCorrect = true; for (var i = 0; i < self.dots.length; i++) { var dot = self.dots[i]; var expectedImage = targetSolution[i]; // Get current image of the dot based on its row and current index var currentImage = 'Blank'; var row = dot.gridY; if (row === 0 && dot.instruments) { // Row 1: Music instruments currentImage = dot.instruments[dot.instrumentIndex]; } else if (row === 1 && dot.foodImages) { // Row 2: Food currentImage = dot.foodImages[dot.foodIndex]; } else if (row === 2 && dot.toyImages) { // Row 3: Toys currentImage = dot.toyImages[dot.toyIndex]; } else if (row === 3 && dot.animalImages) { // Row 4: Animals currentImage = dot.animalImages[dot.animalIndex]; } else if (row === 4 && dot.specialInstruments) { // Row 5: Family currentImage = dot.specialInstruments[dot.specialInstrumentIndex]; } // Check if current image matches expected if (currentImage !== expectedImage) { allCorrect = false; break; } } // Update solved state only - win display handled by green tick if (allCorrect && !self.isSolved) { self.isSolved = true; } else if (!allCorrect && self.isSolved) { self.isSolved = false; } }; // Example: update method for per-frame logic self.update = function () { // Add per-frame puzzle logic here // For example, check for completion self.checkSolved(); }; return self; }); // PuzzleGenerator class for creating randomized puzzle solutions and clues var PuzzleGenerator = Container.expand(function () { var self = Container.call(this); // Available items for each category (row) - expanded to include all factors self.categories = { 0: ['Drum', 'Harp', 'Saxophone', 'Flute', 'Gutair'], // Instruments - matches self.instruments array in Dot class 1: ['Pizza', 'Chips', 'Icecream', 'Donut', 'Spaghetti'], // Food - matches self.foodImages array in Dot class 2: ['Basketball', 'Dolls', 'Lego', 'Videogame', 'Plushtoy'], // Toys - matches self.toyImages array in Dot class 3: ['Fish', 'Turtle', 'Frog', 'Cat', 'Dog'], // Animals - matches self.animalImages array in Dot class 4: ['KJ', 'Khalida', 'Sapphire', 'Harmony', 'PJ'] // People - matches self.specialInstruments array in Dot class }; // Generate a random valid solution self.generateSolution = function () { var solution = {}; // For each row, randomly assign the 5 items to the 5 positions for (var row = 0; row < 5; row++) { var items = self.categories[row].slice(); // Copy array // Shuffle items using Fisher-Yates algorithm for (var i = items.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = items[i]; items[i] = items[j]; items[j] = temp; } // Assign shuffled items to positions for (var col = 0; col < 5; col++) { var dotIndex = row * 5 + col; solution[dotIndex] = items[col]; } } return solution; }; // Generate clues based on the solution self.generateClues = function (solution) { var clues = []; var usedClues = {}; // Track used clues to prevent duplicates // Validate solution exists and has required data if (!solution || _typeof2(solution) !== 'object') { return clues; } // Helper function to validate clue items function isValidItem(item) { return item && typeof item === 'string' && item !== 'Blank'; } // Helper function to create unique clue key function createClueKey(clue) { if (clue.type === 'equals') { var items = [clue.item1, clue.item2].sort(); return clue.type + ':' + items[0] + '=' + items[1]; } else if (clue.type === 'order') { return clue.type + ':' + clue.item1 + clue.operator + clue.item2; } else if (clue.type === 'position') { return clue.type + ':' + clue.item1 + '=' + clue.position; } return ''; } // Strategy: Generate more targeted clues that create logical chains // 1. Start with position clues for anchor points (all columns for better coverage) var anchorPositions = [0, 1, 2, 3, 4]; // all columns 1-5 for comprehensive coverage for (var i = 0; i < anchorPositions.length && clues.length < 8; i++) { var col = anchorPositions[i]; var row = Math.floor(Math.random() * 5); var item = solution[row * 5 + col]; if (isValidItem(item)) { var clueCandidate = { type: 'position', item1: item, position: col + 1 }; var clueKey = createClueKey(clueCandidate); if (!usedClues[clueKey]) { clues.push(clueCandidate); usedClues[clueKey] = true; } } } // 2. Generate strategic equality clues - ensure coverage across all columns var equalityAttempts = 0; while (clues.length < 15 && equalityAttempts < 50) { // Distribute equality clues across all columns for better coverage var col = Math.floor(Math.random() * 5); var row1 = Math.floor(Math.random() * 5); var row2; do { row2 = Math.floor(Math.random() * 5); } while (row2 === row1); var item1 = solution[row1 * 5 + col]; var item2 = solution[row2 * 5 + col]; if (isValidItem(item1) && isValidItem(item2) && item1 !== item2) { var clueCandidate = { type: 'equals', item1: item1, item2: item2 }; var clueKey = createClueKey(clueCandidate); if (!usedClues[clueKey]) { clues.push(clueCandidate); usedClues[clueKey] = true; } } equalityAttempts++; } // 3. Generate ordering clues that create logical connections across all rows var orderAttempts = 0; while (clues.length < 22 && orderAttempts < 80) { var row = Math.floor(Math.random() * 5); var col1 = Math.floor(Math.random() * 4); var col2 = col1 + 1; var item1 = solution[row * 5 + col1]; var item2 = solution[row * 5 + col2]; var operator = '<'; // Check for existing clue connections to prioritize logical chains var hasExistingClue = false; for (var c = 0; c < clues.length; c++) { if (clues[c].item1 === item1 || clues[c].item1 === item2 || clues[c].item2 === item1 || clues[c].item2 === item2) { hasExistingClue = true; break; } } if (isValidItem(item1) && isValidItem(item2) && item1 !== item2) { var clueCandidate = { type: 'order', item1: item1, item2: item2, operator: operator }; var clueKey = createClueKey(clueCandidate); if (!usedClues[clueKey]) { // Accept all valid ordering clues to ensure comprehensive coverage clues.push(clueCandidate); usedClues[clueKey] = true; } } orderAttempts++; } // 4. Fill remaining slots with additional strategic clues var fillAttempts = 0; while (clues.length < 25 && fillAttempts < 30) { var clueType = Math.random(); if (clueType < 0.4) { // Additional position clues for remaining columns var col = Math.floor(Math.random() * 5); var row = Math.floor(Math.random() * 5); var item = solution[row * 5 + col]; if (isValidItem(item)) { var clueCandidate = { type: 'position', item1: item, position: col + 1 }; var clueKey = createClueKey(clueCandidate); if (!usedClues[clueKey]) { clues.push(clueCandidate); usedClues[clueKey] = true; } } } else { // Additional equality clues var col = Math.floor(Math.random() * 5); var row1 = Math.floor(Math.random() * 5); var row2; do { row2 = Math.floor(Math.random() * 5); } while (row2 === row1); var item1 = solution[row1 * 5 + col]; var item2 = solution[row2 * 5 + col]; if (isValidItem(item1) && isValidItem(item2) && item1 !== item2) { var clueCandidate = { type: 'equals', item1: item1, item2: item2 }; var clueKey = createClueKey(clueCandidate); if (!usedClues[clueKey]) { clues.push(clueCandidate); usedClues[clueKey] = true; } } } fillAttempts++; } return clues; }; return self; }); // StoryScene class for displaying story content var StoryScene = Container.expand(function () { var self = Container.call(this); // Add background var bg = self.attachAsset('Street', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 20.48, scaleY: 27.32, alpha: 0.95 }); // Add story content container var storyContent = new Container(); self.addChild(storyContent); // --- SCENE DATA --- var scenes = [{ // First scene imageId: 'First', text: "Once upon a time, in a magical puzzle world,\nthere lived characters who needed your help\nto solve their mysteries..." }, { // Second scene imageId: 'Second', text: "Each puzzle you solve brings harmony to their world.\nAre you ready to begin your adventure?" }]; var currentScene = 0; // Add story title var storyTitle = new Text2("STORY", { size: 120, fill: 0xFFFFFF, align: 'center', font: "'Times New Roman','Times New Roman Bold','GillSans-Bold',Impact,'Arial Black',Tahoma" }); storyTitle.anchor.set(0.5, 0.5); storyTitle.x = 2048 / 2; storyTitle.y = 300; storyContent.addChild(storyTitle); // Add story image (centered, fills screen) var storyImage = storyContent.attachAsset(scenes[0].imageId, { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 1.0, scaleY: 1.0 }); // Add story text var storyText = new Text2(scenes[0].text, { size: 80, fill: 0xFFFFFF, align: 'center', font: "'Times New Roman','Times New Roman Bold','GillSans-Bold',Impact,'Arial Black',Tahoma" }); storyText.anchor.set(0.5, 0.5); storyText.x = 2048 / 2; storyText.y = 2732 - 600; storyContent.addChild(storyText); // Add continue button var continueText = new Text2("TAP TO CONTINUE", { size: 100, fill: 0xFFFF00, align: 'center', font: "'Times New Roman','Times New Roman Bold','GillSans-Bold',Impact,'Arial Black',Tahoma" }); continueText.anchor.set(0.5, 0.5); continueText.x = 2048 / 2; continueText.y = 2732 - 400; storyContent.addChild(continueText); // Pulse the continue text var _pulseContinueText = function pulseContinueText() { tween(continueText, { alpha: 0.3 }, { duration: 800, easing: tween.sineInOut, onFinish: function onFinish() { tween(continueText, { alpha: 1 }, { duration: 800, easing: tween.sineInOut, onFinish: _pulseContinueText }); } }); }; _pulseContinueText(); // Helper to update scene visuals with smooth fade transition function showScene(idx) { if (idx < 0 || idx >= scenes.length) return; // Fade out current image and text, then swap and fade in var fadeOutDuration = 350; var fadeInDuration = 350; // Helper to fade in new image and text function fadeInNewScene() { // Swap image if (storyImage && storyImage.parent) { storyImage.parent.removeChild(storyImage); } var newImg = storyContent.attachAsset(scenes[idx].imageId, { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 1.0, scaleY: 1.0 }); newImg.alpha = 0; storyImage = newImg; // Update text storyText.setText(scenes[idx].text); storyText.alpha = 0; // Fade in new image and text tween(newImg, { alpha: 1 }, { duration: fadeInDuration, easing: tween.cubicOut }); tween(storyText, { alpha: 1 }, { duration: fadeInDuration, easing: tween.cubicOut }); } // Fade out current image and text, then call fadeInNewScene if (storyImage && storyText) { tween(storyImage, { alpha: 0 }, { duration: fadeOutDuration, easing: tween.cubicIn, onFinish: fadeInNewScene }); tween(storyText, { alpha: 0 }, { duration: fadeOutDuration, easing: tween.cubicIn }); } else { // If no image/text, just show new scene fadeInNewScene(); } } // Handle tap/click to continue self.down = function (x, y, obj) { if (currentScene < scenes.length - 1) { // Go to next scene currentScene++; showScene(currentScene); } else { // Fade out story scene tween(self, { alpha: 0 }, { duration: 500, easing: tween.cubicOut, onFinish: function onFinish() { if (self.parent) { self.parent.removeChild(self); // Start the main game startMainGame(); } } }); } }; return self; }); // TitleScreen class for the game's title screen var TitleScreen = Container.expand(function () { var self = Container.call(this); // Add background var bg = self.attachAsset('Street', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 20.48, scaleY: 27.32, alpha: 0.95 }); // Add title image to fill the whole screen var titleImg = self.attachAsset('Title', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 1.0, scaleY: 1.0 }); // Add animated swirl image, centered, IN FRONT of title var swirlImg = self.attachAsset('Swirl', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 1.2, scaleY: 1.2, alpha: 0.45 }); self.swirlImg = swirlImg; // Add heading image above the title image and swirl, so it is in front of both // Start tiny in the center, then tween to large in the center var headingImg = self.attachAsset('Heading', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, // Start in the center scaleX: 0.1, scaleY: 0.1 }); // Add loading text that shows while assets are loading var loadingText = new Text2("LOADING...", { size: 80, fill: 0xFFFFFF, align: 'center', font: "'Times New Roman','Times New Roman Bold','GillSans-Bold',Impact,'Arial Black',Tahoma" }); loadingText.anchor.set(0.5, 0.5); loadingText.x = 2048 / 2; loadingText.y = 2732 / 2 + 600; loadingText.alpha = 1; self.addChild(loadingText); // Pulse the loading text while assets load var _pulseLoadingText = function pulseLoadingText() { if (!loadingText || !loadingText.parent) return; tween(loadingText, { alpha: 0.3 }, { duration: 600, easing: tween.sineInOut, onFinish: function onFinish() { if (!loadingText || !loadingText.parent) return; tween(loadingText, { alpha: 1 }, { duration: 600, easing: tween.sineInOut, onFinish: _pulseLoadingText }); } }); }; _pulseLoadingText(); // Animate heading to grow and stay in the center position, but only after fully loaded function startTitleScreenAnimations() { // Fade out loading text first if (loadingText && loadingText.parent) { tween(loadingText, { alpha: 0 }, { duration: 500, easing: tween.cubicOut, onFinish: function onFinish() { if (loadingText && loadingText.parent) { self.removeChild(loadingText); } } }); } tween(headingImg, { x: 2048 / 2, y: 2732 / 2, scaleX: 1.0, scaleY: 1.0 }, { duration: 5000, easing: tween.cubicOut }); // Animate swirl rotation using tween for infinite smooth rotation function startSwirlTween() { if (!self.swirlImg) return; // Always rotate to the next full circle (-2*PI) from current rotation for opposite direction var startRotation = self.swirlImg.rotation || 0; var endRotation = startRotation - Math.PI * 2; tween(self.swirlImg, { rotation: endRotation }, { duration: 8000, easing: tween.linear, onFinish: function onFinish() { // Reset rotation to avoid overflow and keep animation smooth if (self.swirlImg) self.swirlImg.rotation = self.swirlImg.rotation % (Math.PI * 2); startSwirlTween(); } }); } startSwirlTween(); } // Wait 2 seconds to simulate asset loading delay, then start animations LK.setTimeout(function () { if (self && self.parent) { startTitleScreenAnimations(); } }, 2000); // Add "Tap to Start" text with pulsing effect var startText = new Text2("TAP TO START", { size: 120, fill: 0xFFFF00, align: 'center', font: "'Times New Roman','Times New Roman Bold','GillSans-Bold',Impact,'Arial Black',Tahoma" }); startText.anchor.set(0.5, 0.5); startText.x = 2048 / 2; startText.y = 2732 - 300; self.addChild(startText); // Pulse the start text var _pulseStartText = function pulseStartText() { tween(startText, { alpha: 0.3 }, { duration: 800, easing: tween.sineInOut, onFinish: function onFinish() { tween(startText, { alpha: 1 }, { duration: 800, easing: tween.sineInOut, onFinish: _pulseStartText }); } }); }; _pulseStartText(); // Handle tap/click to start game self.down = function (x, y, obj) { // Fade out title screen tween(self, { alpha: 0 }, { duration: 500, easing: tween.cubicOut, onFinish: function onFinish() { if (self.parent) { self.parent.removeChild(self); // Start the main game directly startMainGame(); } } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Global variables that need to be accessible 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 usedInstruments = {}; var puzzle; var greenTick; var numberImages = []; var allClueAssets = []; var infoButton; var instructionsScreen = null; var clueStrikeStates = [false, false]; var usedSpecialInstruments = {}; var usedAnimalImages = {}; var usedFoodImages = {}; var usedToyImages = {}; // Function to start the main game after title screen function startMainGame() { // Initialize win/loss counters from storage with defaults if (typeof storage.wins === 'undefined') storage.wins = 0; if (typeof storage.losses === 'undefined') storage.losses = 0; // Reset global variables usedInstruments = {}; usedSpecialInstruments = {}; usedAnimalImages = {}; usedFoodImages = {}; usedToyImages = {}; numberImages = []; allClueAssets = []; // Reset clueStrikeStates BEFORE creating clues to prevent old state from being applied clueStrikeStates = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]; // Add Puzzle to the game when it starts puzzle = new Puzzle(); game.addChild(puzzle); // Reset all dots to ensure clean state for (var i = 0; i < puzzle.dots.length; i++) { var dot = puzzle.dots[i]; // Reset all indices to 0 dot.instrumentIndex = 0; dot.specialInstrumentIndex = 0; dot.animalIndex = 0; dot.foodIndex = 0; dot.toyIndex = 0; // Clear current instrument and reset to blank if (dot.currentInstrument) { dot.removeChild(dot.currentInstrument); dot.currentInstrument = null; } // Set to blank instrument dot.currentInstrument = dot.attachAsset('Blank', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0 }); } // Add 1 2 3 4 5 number image assets to the top of the screen var numberLabelY = 60; // 60px from top var numberSpacing = 2048 / 6; // 5 numbers, 6 spaces // Track number image assets for later removal var numberImages = []; for (var i = 1; i <= 5; i++) { var numImg = LK.getAsset(i + "", { anchorX: 0.5, anchorY: 0, x: i * numberSpacing, y: numberLabelY, scaleX: 0.7, scaleY: 0.7 }); game.addChild(numImg); numberImages.push(numImg); } // --- CLUE STRIKETHROUGH LOGIC --- // Track strikethrough state for clues (first two clues only for now) var clueStrikeStates = [false, false]; // Helper to apply or remove strikethrough effect (alpha fade) for a group of clue assets function setClueStrikethrough(clueGroup, isStruck) { var alpha = isStruck ? 0.35 : 1.0; for (var i = 0; i < clueGroup.length; i++) { if (clueGroup[i]) clueGroup[i].alpha = alpha; } } // Helper to toggle strikethrough and remember state // Optionally accepts a clueIndex to persist state for first two clues function makeClueStrikeToggle(clueGroup, clueIndex) { var struck = false; // If restoring, use persisted state if (typeof clueIndex === "number" && clueStrikeStates[clueIndex] !== undefined) { struck = clueStrikeStates[clueIndex]; setClueStrikethrough(clueGroup, struck); } for (var i = 0; i < clueGroup.length; i++) { // Attach to all, but only one will handle the toggle clueGroup[i].down = function () { struck = !struck; setClueStrikethrough(clueGroup, struck); if (typeof clueIndex === "number") { clueStrikeStates[clueIndex] = struck; } }; } } // Generate dynamic clues based on the puzzle solution var clueAssets = []; var clueY = 2732 - 40 - 500 + 30; var clueX = 30; var clueSpacing = 120; var clueIndex = 0; // Create visual clues from generated clue data for (var i = 0; i < puzzle.generatedClues.length && i < 25; i++) { var clue = puzzle.generatedClues[i]; // Skip clue if it has invalid properties if (!clue || !clue.item1) { continue; } var clueAssetGroup = []; // Calculate position (5 columns of 5 clues each) // Adjust column spacing to fit within screen width (2048px) var columnSpacing = (2048 - clueX * 2) / 5; // Distribute 5 columns evenly across available width var columnX = clueX + Math.floor(clueIndex / 5) * columnSpacing; var currentY = clueY + clueIndex % 5 * clueSpacing; // Create first item with proper scaling for special items var item1Scale = 0.45; var item1ExtraY = 0; if (clue.item1 === 'Harmony') { item1Scale = 0.55; item1ExtraY = -10; } else if (clue.item1 === 'Khalida') { item1ExtraY = -10; } else if (clue.item1 === 'KJ') { item1ExtraY = 5; } var item1Asset = LK.getAsset(clue.item1, { anchorX: 0.0, anchorY: 1.0, x: columnX, y: currentY + item1ExtraY, scaleX: item1Scale, scaleY: item1Scale }); game.addChild(item1Asset); clueAssetGroup.push(item1Asset); // Create operator text var operatorText; if (clue.type === 'equals') { operatorText = "="; } else if (clue.type === 'order') { operatorText = clue.operator; } else if (clue.type === 'position') { operatorText = "="; } var opText = new Text2(operatorText, { size: 120, fill: 0xFFFFFF }); opText.anchor.set(0.5, 1.0); opText.x = columnX + 200 * 0.45 + 30; opText.y = currentY; game.addChild(opText); clueAssetGroup.push(opText); // Create second item var secondItem; var item2Scale = 0.45; var item2ExtraY = 0; if (clue.type === 'position') { secondItem = clue.position.toString(); } else { secondItem = clue.item2; // Apply special scaling for second item too if (secondItem && secondItem === 'Harmony') { item2Scale = 0.55; item2ExtraY = -10; } else if (secondItem && secondItem === 'Khalida') { item2ExtraY = -10; } else if (secondItem && secondItem === 'KJ') { item2ExtraY = 5; } } // Only create second item if it exists if (secondItem) { var item2Asset = LK.getAsset(secondItem, { anchorX: 0.0, anchorY: 1.0, x: columnX + 200 * 0.45 + 60, y: currentY + item2ExtraY, scaleX: item2Scale, scaleY: item2Scale }); game.addChild(item2Asset); clueAssetGroup.push(item2Asset); } // Add strikethrough functionality makeClueStrikeToggle(clueAssetGroup, i < 2 ? i : undefined); // Store for later cleanup clueAssets = clueAssets.concat(clueAssetGroup); clueIndex++; } // Store clue assets globally for cleanup allClueAssets = clueAssets; // Add green tick to bottom right corner var greenTick = LK.getAsset('Greentick', { anchorX: 1.0, anchorY: 1.0, x: 2048 - 0, //{7i} // moved right by 50px y: 2732 - 50 - 600 - 35, // moved up by 15px (previously 10, now 15) scaleX: 0.8, scaleY: 0.8 }); game.addChild(greenTick); // Add info button to bottom left corner var infoButton = LK.getAsset('Info', { anchorX: 0.0, anchorY: 1.0, x: 0, y: 2732 - 50 - 600 - 30, scaleX: 1.5, scaleY: 1.5 }); game.addChild(infoButton); // Variable to track instructions screen var instructionsScreen = null; // Make info button clickable to show illustrated how-to-play guide infoButton.down = function (x, y, obj) { // If instructions screen is already showing, hide it if (instructionsScreen && instructionsScreen.parent) { instructionsScreen.parent.removeChild(instructionsScreen); instructionsScreen = null; return; } // Create instructions screen container instructionsScreen = new Container(); // Add semi-transparent background var instructionsBg = LK.getAsset('Street', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 20.48, scaleY: 27.32, alpha: 0.92 }); instructionsScreen.addChild(instructionsBg); // Add "How to Play" asset to the top of the instructions page var howToPlayAsset = LK.getAsset('Howtoplaybutton', { anchorX: 0.5, anchorY: 0, x: 2048 / 2, y: 80, scaleX: 1.0, scaleY: 1.0 }); instructionsScreen.addChild(howToPlayAsset); // Add visual clue examples to help players understand the clue system // Example 1: Equality clue (Sapphire = Chips) var exampleSapphire = LK.getAsset('Sapphire', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 - 200, y: 800, scaleX: 0.6, scaleY: 0.6 }); instructionsScreen.addChild(exampleSapphire); var exampleEquals = new Text2("=", { size: 80, fill: 0xFFFFFF }); exampleEquals.anchor.set(0.5, 0.5); exampleEquals.x = 2048 / 2; exampleEquals.y = 800; instructionsScreen.addChild(exampleEquals); var exampleChips = LK.getAsset('Chips', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 + 200, y: 800, scaleX: 0.6, scaleY: 0.6 }); instructionsScreen.addChild(exampleChips); // Example 2: Less than clue (Donut < Chips) var exampleDonut = LK.getAsset('Donut', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 - 200, y: 950, scaleX: 0.6, scaleY: 0.6 }); instructionsScreen.addChild(exampleDonut); var exampleLessThan = new Text2("<", { size: 80, fill: 0xFFFFFF }); exampleLessThan.anchor.set(0.5, 0.5); exampleLessThan.x = 2048 / 2; exampleLessThan.y = 950; instructionsScreen.addChild(exampleLessThan); var exampleChips2 = LK.getAsset('Chips', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 + 200, y: 950, scaleX: 0.6, scaleY: 0.6 }); instructionsScreen.addChild(exampleChips2); // Example 3: Greater than clue (Guitar > Cat) var exampleGuitar = LK.getAsset('Gutair', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 - 200, y: 1100, scaleX: 0.6, scaleY: 0.6 }); instructionsScreen.addChild(exampleGuitar); var exampleGreaterThan = new Text2(">", { size: 80, fill: 0xFFFFFF }); exampleGreaterThan.anchor.set(0.5, 0.5); exampleGreaterThan.x = 2048 / 2; exampleGreaterThan.y = 1100; instructionsScreen.addChild(exampleGreaterThan); var exampleCat = LK.getAsset('Cat', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2 + 200, y: 1100, scaleX: 0.6, scaleY: 0.6 }); instructionsScreen.addChild(exampleCat); // Add step-by-step text instructions positioned below the visual examples var instructionsText = new Text2("HOW TO PLAY THIS PUZZLE GAME\n\n" + "1. TAP ANY QUESTION MARK to cycle through available pictures\n" + "2. USE THE CLUES (examples shown above):\n" + " β’ = means 'equals' or 'matches'\n" + " β’ < means 'comes before' (left to right)\n" + " β’ > means 'comes after' (left to right)\n\n" + "3. STRIKE THROUGH CLUES by tapping them\n" + "4. CHECK YOUR ANSWER by tapping the green tick\n\n" + "Tap anywhere to close this guide.", { size: 60, fill: 0xffffff, align: 'center', font: "'Times New Roman Bold','Times New Roman','GillSans-Bold',Impact,'Arial Black',Tahoma" }); instructionsText.anchor.set(0.5, 0.5); instructionsText.x = 2048 / 2; instructionsText.y = 2732 / 2 + 100 + 300; instructionsScreen.addChild(instructionsText); // Make the entire instructions screen clickable to close instructionsScreen.down = function (x, y, obj) { if (instructionsScreen && instructionsScreen.parent) { instructionsScreen.parent.removeChild(instructionsScreen); instructionsScreen = null; } }; // Add instructions screen to game game.addChild(instructionsScreen); }; // Helper to show/hide info button function setInfoButtonVisible(visible) { if (infoButton && infoButton.parent) { infoButton.visible = !!visible; } } // Function to update clues with strikethrough for solved items (picture clues only) function updateCluesWithStrikethrough() { // This function now only handles picture clue strikethrough effects // The picture clues are already implemented with makeClueStrikeToggle // No additional text-based clue processing needed } // Make green tick clickable to enter puzzle attempt greenTick.down = function (x, y, obj) { // Remove all clue assets from game when green tick is clicked if (typeof allClueAssets === "undefined") allClueAssets = []; for (var i = 0; i < allClueAssets.length; i++) { if (allClueAssets[i] && allClueAssets[i].parent) { allClueAssets[i].parent.removeChild(allClueAssets[i]); } } // Remove number image assets from game when green tick is clicked if (typeof numberImages !== "undefined" && numberImages.length) { for (var i = 0; i < numberImages.length; i++) { if (numberImages[i] && numberImages[i].parent) numberImages[i].parent.removeChild(numberImages[i]); } } if (puzzle && typeof puzzle.checkSolved === "function") { // Run the check puzzle.checkSolved(); // If solved, show endpuzzletwo scene if (puzzle.isSolved) { // Remove the puzzle and green tick from the game if (puzzle.parent) puzzle.parent.removeChild(puzzle); if (greenTick.parent) greenTick.parent.removeChild(greenTick); // Hide info button when showing endpuzzletwo setInfoButtonVisible(false); // Show endpuzzletwo asset centered on screen var endpuzzletwo = LK.getAsset('Endpuzzletwo', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 2.2, scaleY: 2.2, alpha: 0 }); game.addChild(endpuzzletwo); // Fade in endpuzzletwo tween(endpuzzletwo, { alpha: 1 }, { duration: 350, easing: tween.cubicOut }); // After 2 seconds, fade out and swap to correct scene with correct word under the correct image LK.setTimeout(function () { tween(endpuzzletwo, { alpha: 0 }, { duration: 350, easing: tween.cubicIn, onFinish: function onFinish() { if (endpuzzletwo.parent) endpuzzletwo.parent.removeChild(endpuzzletwo); // Show Correct scene (centered) var correctScene = LK.getAsset('Correct', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 2.2, scaleY: 2.2, alpha: 0 }); game.addChild(correctScene); // Fade in correctScene tween(correctScene, { alpha: 1 }, { duration: 350, easing: tween.cubicOut }); // No winning image displayed - just show the correct word // Increment wins counter storage.wins = (storage.wins || 0) + 1; // Show the correct word asset at the bottom of the screen var correctWord = LK.getAsset('Correctword', { anchorX: 0.5, anchorY: 1.0, x: 2048 / 2, y: 2732 - 50, scaleX: 2.2, scaleY: 2.2, alpha: 0 }); game.addChild(correctWord); tween(correctWord, { alpha: 1 }, { duration: 350, easing: tween.cubicOut }); // Add win/loss tally text on correct screen var tallyText = new Text2("WINS: " + storage.wins + " | LOSSES: " + storage.losses, { size: 80, fill: 0xFFFFFF, align: 'center' }); tallyText.anchor.set(0.5, 0.5); tallyText.x = 2048 / 2; tallyText.y = 2732 / 2 - 200 - 750; tallyText.alpha = 0; game.addChild(tallyText); tween(tallyText, { alpha: 1 }, { duration: 350, easing: tween.cubicOut }); // Add play again button above the correct word var playAgainBtnY = 2732 - 50 - correctWord.height * 2.2 - 40; // 40px above correct word var playAgainBtn = LK.getAsset('Playagain', { anchorX: 0.5, anchorY: 1.0, x: 2048 / 2, y: playAgainBtnY, scaleX: 1.8, scaleY: 1.8, alpha: 0 }); game.addChild(playAgainBtn); tween(playAgainBtn, { alpha: 1 }, { duration: 350, easing: tween.cubicOut }); // Play again button handler: remove correct scene and restart puzzle playAgainBtn.down = function (x, y, obj) { // Fade out all correct scene assets, then remove and reset var fadeOuts = [correctScene, correctWord, playAgainBtn, tallyText]; var fadeCount = 0; var fadeDone = function fadeDone() { fadeCount++; if (fadeCount === fadeOuts.length) { // Remove all correct scene assets if (correctScene && correctScene.parent) correctScene.parent.removeChild(correctScene); if (correctWord && correctWord.parent) correctWord.parent.removeChild(correctWord); if (playAgainBtn && playAgainBtn.parent) playAgainBtn.parent.removeChild(playAgainBtn); if (tallyText && tallyText.parent) tallyText.parent.removeChild(tallyText); // Reset all used image trackers so dots can be reused usedInstruments = {}; usedSpecialInstruments = {}; usedAnimalImages = {}; usedFoodImages = {}; usedToyImages = {}; // Reset strikethrough state for all clues BEFORE creating new puzzle clueStrikeStates = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]; // Re-add puzzle and green tick puzzle = new Puzzle(); game.addChild(puzzle); game.addChild(greenTick); // Reset all dots to ensure clean state for (var i = 0; i < puzzle.dots.length; i++) { var dot = puzzle.dots[i]; // Reset all indices to 0 dot.instrumentIndex = 0; dot.specialInstrumentIndex = 0; dot.animalIndex = 0; dot.foodIndex = 0; dot.toyIndex = 0; // Clear current instrument and reset to blank if (dot.currentInstrument) { dot.removeChild(dot.currentInstrument); dot.currentInstrument = null; } // Set to blank instrument dot.currentInstrument = dot.attachAsset('Blank', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0 }); } // Re-add number image assets to the top of the screen numberImages = []; for (var i = 1; i <= 5; i++) { var numImg = LK.getAsset(i + "", { anchorX: 0.5, anchorY: 0, x: i * (2048 / 6), y: 60, scaleX: 0.7, scaleY: 0.7 }); game.addChild(numImg); numberImages.push(numImg); } // Generate new dynamic clues for the new puzzle var clueAssets = []; var clueY = 2732 - 40 - 500 + 30; var clueX = 30; var clueSpacing = 120; var clueIndex = 0; // Create visual clues from generated clue data for (var i = 0; i < puzzle.generatedClues.length && i < 25; i++) { var clue = puzzle.generatedClues[i]; // Skip clue if it has invalid properties if (!clue || !clue.item1) { continue; } var clueAssetGroup = []; // Calculate position (5 columns of 5 clues each) // Adjust column spacing to fit within screen width (2048px) var columnSpacing = (2048 - clueX * 2) / 5; // Distribute 5 columns evenly across available width var columnX = clueX + Math.floor(clueIndex / 5) * columnSpacing; var currentY = clueY + clueIndex % 5 * clueSpacing; // Create first item with proper scaling for special items var item1Scale = 0.45; var item1ExtraY = 0; if (clue.item1 === 'Harmony') { item1Scale = 0.55; item1ExtraY = -10; } else if (clue.item1 === 'Khalida') { item1ExtraY = -10; } else if (clue.item1 === 'KJ') { item1ExtraY = 5; } var item1Asset = LK.getAsset(clue.item1, { anchorX: 0.0, anchorY: 1.0, x: columnX, y: currentY + item1ExtraY, scaleX: item1Scale, scaleY: item1Scale }); game.addChild(item1Asset); clueAssetGroup.push(item1Asset); // Create operator text var operatorText; if (clue.type === 'equals') { operatorText = "="; } else if (clue.type === 'order') { operatorText = clue.operator; } else if (clue.type === 'position') { operatorText = "="; } var opText = new Text2(operatorText, { size: 120, fill: 0xFFFFFF }); opText.anchor.set(0.5, 1.0); opText.x = columnX + 200 * 0.45 + 30; opText.y = currentY; game.addChild(opText); clueAssetGroup.push(opText); // Create second item var secondItem; var item2Scale = 0.45; var item2ExtraY = 0; if (clue.type === 'position') { secondItem = clue.position.toString(); } else { secondItem = clue.item2; // Apply special scaling for second item too if (secondItem && secondItem === 'Harmony') { item2Scale = 0.55; item2ExtraY = -10; } else if (secondItem && secondItem === 'Khalida') { item2ExtraY = -10; } else if (secondItem && secondItem === 'KJ') { item2ExtraY = 5; } } // Only create second item if it exists if (secondItem) { var item2Asset = LK.getAsset(secondItem, { anchorX: 0.0, anchorY: 1.0, x: columnX + 200 * 0.45 + 60, y: currentY + item2ExtraY, scaleX: item2Scale, scaleY: item2Scale }); game.addChild(item2Asset); clueAssetGroup.push(item2Asset); } // Add strikethrough functionality makeClueStrikeToggle(clueAssetGroup, i < 2 ? i : undefined); // Store for later cleanup clueAssets = clueAssets.concat(clueAssetGroup); clueIndex++; } // Update global reference allClueAssets = clueAssets; // Show info button again after play again setInfoButtonVisible(true); } }; for (var i = 0; i < fadeOuts.length; i++) { if (fadeOuts[i]) { tween(fadeOuts[i], { alpha: 0 }, { duration: 250, easing: tween.cubicIn, onFinish: fadeDone }); } else { fadeDone(); } } }; } }); }, 2000); } else { // If not solved, show endgame1 scene if (puzzle.parent) puzzle.parent.removeChild(puzzle); if (greenTick.parent) greenTick.parent.removeChild(greenTick); // Hide info button when showing endgame1 setInfoButtonVisible(false); // Show endgame1 asset centered on screen var endgame1 = LK.getAsset('Endpuzzleone', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 2.2, scaleY: 2.2, alpha: 0 }); game.addChild(endgame1); tween(endgame1, { alpha: 1 }, { duration: 350, easing: tween.cubicOut }); // After 2 seconds, fade out and swap to incorrect scene with incorrect word under the incorrect image LK.setTimeout(function () { tween(endgame1, { alpha: 0 }, { duration: 350, easing: tween.cubicIn, onFinish: function onFinish() { if (endgame1.parent) endgame1.parent.removeChild(endgame1); // Show Incorrect scene (centered) var incorrectScene = LK.getAsset('Incorrect', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 2.2, scaleY: 2.2, alpha: 0 }); game.addChild(incorrectScene); tween(incorrectScene, { alpha: 1 }, { duration: 350, easing: tween.cubicOut }); // Find the first incorrect dot and its expected word var targetSolution = puzzle.targetSolution || {}; var firstWrongIdx = -1; var wrongActual = ''; var wrongExpected = ''; for (var i = 0; i < puzzle.dots.length; i++) { var dot = puzzle.dots[i]; var expected = targetSolution[i]; var actual = 'Blank'; var row = dot.gridY; // Get current image based on row and index if (row === 0 && dot.instruments) { actual = dot.instruments[dot.instrumentIndex]; } else if (row === 1 && dot.foodImages) { actual = dot.foodImages[dot.foodIndex]; } else if (row === 2 && dot.toyImages) { actual = dot.toyImages[dot.toyIndex]; } else if (row === 3 && dot.animalImages) { actual = dot.animalImages[dot.animalIndex]; } else if (row === 4 && dot.specialInstruments) { actual = dot.specialInstruments[dot.specialInstrumentIndex]; } if (actual !== expected) { firstWrongIdx = i; wrongActual = actual; wrongExpected = expected; break; } } // If found, show the incorrect image and word under it if (firstWrongIdx !== -1) { var wrongImg = null; var imgY = 2732 / 2 + 100; var wordY = imgY; // Only show the image if it's not 'Blank' if (wrongActual !== 'Blank') { wrongImg = LK.getAsset(wrongActual, { anchorX: 0.5, anchorY: 1.0, x: 2048 / 2, y: imgY, alpha: 0 }); game.addChild(wrongImg); tween(wrongImg, { alpha: 1 }, { duration: 350, easing: tween.cubicOut }); wordY = 2732 / 2 + 120 + (wrongImg.height || 100); // 20px below image } else { // If blank, just show the word lower down wordY = 2732 / 2 + 120; } // Increment losses counter storage.losses = (storage.losses || 0) + 1; // Show the incorrect word asset at the bottom of the screen var incorrectWord = LK.getAsset('Incorrectword', { anchorX: 0.5, anchorY: 1.0, x: 2048 / 2, y: 2732 - 50, // 50px padding from bottom scaleX: 2.2, scaleY: 2.2, alpha: 0 }); game.addChild(incorrectWord); tween(incorrectWord, { alpha: 1 }, { duration: 350, easing: tween.cubicOut }); // Add win/loss tally text on incorrect screen var incorrectTallyText = new Text2("WINS: " + storage.wins + " | LOSSES: " + storage.losses, { size: 80, fill: 0xFFFFFF, align: 'center' }); incorrectTallyText.anchor.set(0.5, 0.5); incorrectTallyText.x = 2048 / 2; incorrectTallyText.y = 2732 / 2 - 200 - 750; incorrectTallyText.alpha = 0; game.addChild(incorrectTallyText); tween(incorrectTallyText, { alpha: 1 }, { duration: 350, easing: tween.cubicOut }); // Add retry button below the incorrect image/word var retryBtnY = 2732 - 50 - incorrectWord.height * 2.2 - 40; // 40px above incorrect word var retryBtn = LK.getAsset('Retry', { anchorX: 0.5, anchorY: 1.0, x: 2048 / 2, y: retryBtnY, scaleX: 1.8, scaleY: 1.8, alpha: 0 }); game.addChild(retryBtn); tween(retryBtn, { alpha: 1 }, { duration: 350, easing: tween.cubicOut }); // Retry button handler: remove incorrect scene and restart puzzle retryBtn.down = function (x, y, obj) { // Fade out all incorrect scene assets, then remove and reset var fadeOuts = [incorrectScene, wrongImg, incorrectWord, retryBtn, incorrectTallyText]; var fadeCount = 0; var fadeDone = function fadeDone() { fadeCount++; if (fadeCount === fadeOuts.length) { // Remove all incorrect scene assets if (incorrectScene && incorrectScene.parent) incorrectScene.parent.removeChild(incorrectScene); if (wrongImg && wrongImg.parent) wrongImg.parent.removeChild(wrongImg); if (incorrectWord && incorrectWord.parent) incorrectWord.parent.removeChild(incorrectWord); if (retryBtn && retryBtn.parent) retryBtn.parent.removeChild(retryBtn); if (incorrectTallyText && incorrectTallyText.parent) incorrectTallyText.parent.removeChild(incorrectTallyText); // Reset all used image trackers so dots can be reused usedInstruments = {}; usedSpecialInstruments = {}; usedAnimalImages = {}; usedFoodImages = {}; usedToyImages = {}; // Reset strikethrough state for all clues BEFORE creating new puzzle clueStrikeStates = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false]; // Re-add puzzle and green tick puzzle = new Puzzle(); game.addChild(puzzle); game.addChild(greenTick); // Reset all dots to ensure clean state for (var i = 0; i < puzzle.dots.length; i++) { var dot = puzzle.dots[i]; // Reset all indices to 0 dot.instrumentIndex = 0; dot.specialInstrumentIndex = 0; dot.animalIndex = 0; dot.foodIndex = 0; dot.toyIndex = 0; // Clear current instrument and reset to blank if (dot.currentInstrument) { dot.removeChild(dot.currentInstrument); dot.currentInstrument = null; } // Set to blank instrument dot.currentInstrument = dot.attachAsset('Blank', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0 }); } // Re-add number image assets to the top of the screen numberImages = []; for (var i = 1; i <= 5; i++) { var numImg = LK.getAsset(i + "", { anchorX: 0.5, anchorY: 0, x: i * (2048 / 6), y: 60, scaleX: 0.7, scaleY: 0.7 }); game.addChild(numImg); numberImages.push(numImg); } // Generate new dynamic clues for the new puzzle var clueAssets = []; var clueY = 2732 - 40 - 500 + 30; var clueX = 30; var clueSpacing = 120; var clueIndex = 0; // Create visual clues from generated clue data for (var i = 0; i < puzzle.generatedClues.length && i < 25; i++) { var clue = puzzle.generatedClues[i]; // Skip clue if it has invalid properties if (!clue || !clue.item1) { continue; } var clueAssetGroup = []; // Calculate position (5 columns of 5 clues each) // Adjust column spacing to fit within screen width (2048px) var columnSpacing = (2048 - clueX * 2) / 5; // Distribute 5 columns evenly across available width var columnX = clueX + Math.floor(clueIndex / 5) * columnSpacing; var currentY = clueY + clueIndex % 5 * clueSpacing; // Create first item with proper scaling for special items var item1Scale = 0.45; var item1ExtraY = 0; if (clue.item1 === 'Harmony') { item1Scale = 0.55; item1ExtraY = -10; } else if (clue.item1 === 'Khalida') { item1ExtraY = -10; } else if (clue.item1 === 'KJ') { item1ExtraY = 5; } var item1Asset = LK.getAsset(clue.item1, { anchorX: 0.0, anchorY: 1.0, x: columnX, y: currentY + item1ExtraY, scaleX: item1Scale, scaleY: item1Scale }); game.addChild(item1Asset); clueAssetGroup.push(item1Asset); // Create operator text var operatorText; if (clue.type === 'equals') { operatorText = "="; } else if (clue.type === 'order') { operatorText = clue.operator; } else if (clue.type === 'position') { operatorText = "="; } var opText = new Text2(operatorText, { size: 120, fill: 0xFFFFFF }); opText.anchor.set(0.5, 1.0); opText.x = columnX + 200 * 0.45 + 30; opText.y = currentY; game.addChild(opText); clueAssetGroup.push(opText); // Create second item var secondItem; var item2Scale = 0.45; var item2ExtraY = 0; if (clue.type === 'position') { secondItem = clue.position.toString(); } else { secondItem = clue.item2; // Apply special scaling for second item too if (secondItem && secondItem === 'Harmony') { item2Scale = 0.55; item2ExtraY = -10; } else if (secondItem && secondItem === 'Khalida') { item2ExtraY = -10; } else if (secondItem && secondItem === 'KJ') { item2ExtraY = 5; } } // Only create second item if it exists if (secondItem) { var item2Asset = LK.getAsset(secondItem, { anchorX: 0.0, anchorY: 1.0, x: columnX + 200 * 0.45 + 60, y: currentY + item2ExtraY, scaleX: item2Scale, scaleY: item2Scale }); game.addChild(item2Asset); clueAssetGroup.push(item2Asset); } // Add strikethrough functionality makeClueStrikeToggle(clueAssetGroup, i < 2 ? i : undefined); // Store for later cleanup clueAssets = clueAssets.concat(clueAssetGroup); clueIndex++; } // Update global reference allClueAssets = clueAssets; // Re-add info button after story asset if (infoButton && infoButton.parent) { infoButton.parent.removeChild(infoButton); } // Find the story asset in the puzzle and add infoButton after it var storyAssetIdx = -1; for (var i = 0; i < puzzle.children.length; i++) { var child = puzzle.children[i]; if (child && child.assetId === 'Story') { storyAssetIdx = i; break; } } if (storyAssetIdx !== -1) { // Insert infoButton after story asset if (puzzle.children.length > storyAssetIdx + 1) { puzzle.addChildAt(infoButton, storyAssetIdx + 1); } else { puzzle.addChild(infoButton); } } else { // Fallback: add to puzzle if not found puzzle.addChild(infoButton); } // Show info button again after retry setInfoButtonVisible(true); } }; for (var i = 0; i < fadeOuts.length; i++) { if (fadeOuts[i]) { tween(fadeOuts[i], { alpha: 0 }, { duration: 250, easing: tween.cubicIn, onFinish: fadeDone }); } else { fadeDone(); } } }; } } }); }, 2000); } } }; // Update global references that might be needed window.puzzle = puzzle; window.greenTick = greenTick; window.numberImages = numberImages; window.allClueAssets = allClueAssets; window.infoButton = infoButton; } // Initialize the game with title screen var titleScreen = new TitleScreen(); game.addChild(titleScreen);
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Dot class for interactive dots in the puzzle
var Dot = Container.expand(function () {
var self = Container.call(this);
// Create a visual representation for the dot
var dotGraphics = self.attachAsset('Street', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.8,
scaleY: 1.8,
alpha: 0
});
// Dot properties
self.isActive = false;
self.gridX = 0;
self.gridY = 0;
self.instrumentIndex = 0;
self.currentInstrument = null;
// Array of instrument image IDs for first row (dots 1-5)
self.instruments = ['Blank', 'Saxophone', 'Drum', 'Gutair', 'Harp', 'Flute'];
// Array of image IDs for dots 21-25 (bottom row)
self.specialInstruments = ['Blank', 'PJ', 'KJ', 'Harmony', 'Khalida', 'Sapphire'];
// Method to toggle dot state
self.toggle = function () {
self.isActive = !self.isActive;
};
// Method to cycle through instruments for first row (dots 1-5)
self.cycleInstrument = function () {
// Remove current instrument if it exists and free it from usedInstruments
if (self.currentInstrument) {
var currentInstrumentId = self.instruments[self.instrumentIndex];
if (currentInstrumentId !== 'Blank' && usedInstruments[currentInstrumentId] === self) {
delete usedInstruments[currentInstrumentId];
}
self.removeChild(self.currentInstrument);
self.currentInstrument = null;
}
// Find next available instrument
var startIndex = self.instrumentIndex;
var found = false;
do {
self.instrumentIndex = (self.instrumentIndex + 1) % self.instruments.length;
var instrumentId = self.instruments[self.instrumentIndex];
// Check if instrument is available (Blank is always available)
if (instrumentId === 'Blank' || !usedInstruments[instrumentId]) {
found = true;
// Mark non-blank instruments as used
if (instrumentId !== 'Blank') {
usedInstruments[instrumentId] = self;
}
// Create new instrument image
self.currentInstrument = self.attachAsset(instrumentId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
break;
}
} while (self.instrumentIndex !== startIndex);
// If no available instrument found, stay on current (shouldn't happen with 6 instruments for 5 dots)
if (!found) {
self.instrumentIndex = startIndex;
}
};
// Method to cycle through special images for dots 21-25 (bottom row)
self.cycleSpecialInstrument = function () {
// Remove current instrument if it exists
if (self.currentInstrument) {
// Remove from usedSpecialInstruments if not Blank
if (typeof usedSpecialInstruments !== "undefined" && self.specialInstruments && typeof self.specialInstrumentIndex === "number") {
var prevId = self.specialInstruments[self.specialInstrumentIndex];
if (prevId !== 'Blank' && usedSpecialInstruments[prevId] === self) {
delete usedSpecialInstruments[prevId];
}
}
self.removeChild(self.currentInstrument);
self.currentInstrument = null;
}
// Find next available special instrument (no duplicates except Blank)
if (typeof usedSpecialInstruments === "undefined") {
usedSpecialInstruments = {};
}
if (typeof self.specialInstrumentIndex !== "number") self.specialInstrumentIndex = 0;
self.specialInstrumentIndex = typeof self.specialInstrumentIndex === "number" ? self.specialInstrumentIndex : 0;
var startIndex = self.specialInstrumentIndex;
var found = false;
do {
self.specialInstrumentIndex = (self.specialInstrumentIndex + 1) % self.specialInstruments.length;
var instrumentId = self.specialInstruments[self.specialInstrumentIndex];
// Only allow Blank or unused
if (instrumentId === 'Blank' || !usedSpecialInstruments[instrumentId]) {
found = true;
// Mark as used if not Blank
if (instrumentId !== 'Blank') {
usedSpecialInstruments[instrumentId] = self;
}
// Slightly decrease the size of all special images for dots 21-25
var scaleX = 0.85;
var scaleY = 0.85;
if (instrumentId === 'Harmony') {
scaleX = 1.45;
scaleY = 1.45;
}
// Move Khalida or Harmony image up by 10 pixels, move KJ down by 5 pixels
var extraY = 0;
if (instrumentId === 'Khalida' || instrumentId === 'Harmony') {
extraY = -10;
}
if (instrumentId === 'KJ') {
extraY = 5;
}
self.currentInstrument = self.attachAsset(instrumentId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: scaleX,
scaleY: scaleY,
y: extraY
});
break;
}
} while (self.specialInstrumentIndex !== startIndex);
// If no available instrument found, stay on current (shouldn't happen)
if (!found) {
self.specialInstrumentIndex = startIndex;
}
};
// Touch/click handler
self.down = function (x, y, obj) {
// Only cycle instruments for dots 1-5 (first row)
if (self.gridY === 0) {
self.cycleInstrument();
}
// Dots 21-25 (bottom row, gridY === 4, gridX 0-4)
else if (self.gridY === 4) {
self.cycleSpecialInstrument();
}
// Dots 16-20 (row 4, gridY === 3, gridX 0-4)
else if (self.gridY === 3) {
// Animal images to cycle through
if (!self.animalImages) {
self.animalImages = ['Blank', 'Cat', 'Dog', 'Fish', 'Frog', 'Turtle'];
self.animalIndex = 0;
}
// Setup usedAnimalImages global tracker if not present
if (typeof usedAnimalImages === "undefined") {
usedAnimalImages = {};
}
// Remove current animal image if exists and update usedAnimalImages
if (self.currentInstrument) {
if (typeof self.animalIndex === "number") {
var prevAnimalId = self.animalImages[self.animalIndex];
if (prevAnimalId !== 'Blank' && usedAnimalImages[prevAnimalId] === self) {
delete usedAnimalImages[prevAnimalId];
}
}
self.removeChild(self.currentInstrument);
self.currentInstrument = null;
}
// Cycle to next available animal image (no duplicates except Blank)
var startIndex = typeof self.animalIndex === "number" ? self.animalIndex : 0;
var found = false;
var tries = 0;
do {
self.animalIndex = (typeof self.animalIndex === "number" ? self.animalIndex : 0) + 1;
if (self.animalIndex >= self.animalImages.length) self.animalIndex = 0;
var animalId = self.animalImages[self.animalIndex];
// Only allow Blank or unused
if (animalId === 'Blank' || !usedAnimalImages[animalId]) {
found = true;
// Mark as used if not Blank
if (animalId !== 'Blank') {
usedAnimalImages[animalId] = self;
}
self.currentInstrument = self.attachAsset(animalId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
break;
}
tries++;
} while (self.animalIndex !== startIndex && tries < self.animalImages.length + 1);
// If no available animal found, stay on current (shouldn't happen)
if (!found) {
self.animalIndex = startIndex;
}
}
// Dots 6-10 (row 2, gridY === 1, gridX 0-4)
else if (self.gridY === 1) {
// Food images to cycle through
if (!self.foodImages) {
self.foodImages = ['Blank', 'Pizza', 'Chips', 'Icecream', 'Donut', 'Spaghetti'];
self.foodIndex = 0;
}
// Setup usedFoodImages global tracker if not present
if (typeof usedFoodImages === "undefined") {
usedFoodImages = {};
}
// Remove current food image if exists and update usedFoodImages
if (self.currentInstrument) {
if (typeof self.foodIndex === "number") {
var prevFoodId = self.foodImages[self.foodIndex];
if (prevFoodId !== 'Blank' && usedFoodImages[prevFoodId] === self) {
delete usedFoodImages[prevFoodId];
}
}
self.removeChild(self.currentInstrument);
self.currentInstrument = null;
}
// Cycle to next available food image (no duplicates except Blank)
var startFoodIndex = typeof self.foodIndex === "number" ? self.foodIndex : 0;
var foundFood = false;
var foodTries = 0;
do {
self.foodIndex = (typeof self.foodIndex === "number" ? self.foodIndex : 0) + 1;
if (self.foodIndex >= self.foodImages.length) self.foodIndex = 0;
var foodId = self.foodImages[self.foodIndex];
// Only allow Blank or unused
if (foodId === 'Blank' || !usedFoodImages[foodId]) {
foundFood = true;
// Mark as used if not Blank
if (foodId !== 'Blank') {
usedFoodImages[foodId] = self;
}
self.currentInstrument = self.attachAsset(foodId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
break;
}
foodTries++;
} while (self.foodIndex !== startFoodIndex && foodTries < self.foodImages.length + 1);
// If no available food found, stay on current (shouldn't happen)
if (!foundFood) {
self.foodIndex = startFoodIndex;
}
} else if (self.gridY === 2) {
// Toy images to cycle through
if (!self.toyImages) {
self.toyImages = ['Blank', 'Lego', 'Dolls', 'Basketball', 'Videogame', 'Plushtoy'];
self.toyIndex = 0;
}
// Setup usedToyImages global tracker if not present
if (typeof usedToyImages === "undefined") {
usedToyImages = {};
}
// Remove current toy image if exists and update usedToyImages
if (self.currentInstrument) {
if (typeof self.toyIndex === "number") {
var prevToyId = self.toyImages[self.toyIndex];
if (prevToyId !== 'Blank' && usedToyImages[prevToyId] === self) {
delete usedToyImages[prevToyId];
}
}
self.removeChild(self.currentInstrument);
self.currentInstrument = null;
}
// Cycle to next available toy image (no duplicates except Blank)
var startToyIndex = typeof self.toyIndex === "number" ? self.toyIndex : 0;
var foundToy = false;
var toyTries = 0;
do {
self.toyIndex = (typeof self.toyIndex === "number" ? self.toyIndex : 0) + 1;
if (self.toyIndex >= self.toyImages.length) self.toyIndex = 0;
var toyId = self.toyImages[self.toyIndex];
// Only allow Blank or unused
if (toyId === 'Blank' || !usedToyImages[toyId]) {
foundToy = true;
// Mark as used if not Blank
if (toyId !== 'Blank') {
usedToyImages[toyId] = self;
}
self.currentInstrument = self.attachAsset(toyId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
break;
}
toyTries++;
} while (self.toyIndex !== startToyIndex && toyTries < self.toyImages.length + 1);
// If no available toy found, stay on current (shouldn't happen)
if (!foundToy) {
self.toyIndex = startToyIndex;
}
}
self.toggle();
// Update clues with strikethrough after changing dot
if (typeof updateCluesWithStrikethrough === 'function') {
updateCluesWithStrikethrough();
}
};
// Initialize dot as inactive
// Initialize with blank instrument
self.currentInstrument = self.attachAsset('Blank', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
return self;
});
// Puzzle class for managing a puzzle element in the game
var Puzzle = Container.expand(function () {
var self = Container.call(this);
// Add a 4x5 asset to the puzzle and scale it to be exactly 2048 wide
var targetWidth = 2048;
var assetWidth = 1000;
var scale = targetWidth / assetWidth;
// Center horizontally, align to top
var puzzleImage = self.attachAsset('4x5', {
anchorX: 0.5,
anchorY: 0,
x: 2048 / 2,
y: 0,
scaleX: scale,
scaleY: scale
});
// (Story asset removed)
// (Clue images and clue text removed)
// Create 25 dots in a 5x5 grid
self.dots = [];
var gridSize = 5;
var dotSpacing = targetWidth / (gridSize + 1); // Distribute dots evenly across the width
var gridHeight = puzzleImage.height * scale;
var verticalSpacing = gridHeight / (gridSize + 1);
for (var row = 0; row < gridSize; row++) {
for (var col = 0; col < gridSize; col++) {
var dot = new Dot();
dot.gridX = col;
dot.gridY = row;
// Initialize all indices to 0 for consistent reset state
dot.instrumentIndex = 0;
dot.specialInstrumentIndex = 0;
dot.animalIndex = 0;
dot.foodIndex = 0;
dot.toyIndex = 0;
// Position dots over the 4x5 asset
dot.x = (col + 1) * dotSpacing;
dot.y = (row + 1) * verticalSpacing;
self.dots.push(dot);
self.addChild(dot);
}
}
// Generate randomized solution and clues
var generator = new PuzzleGenerator();
self.targetSolution = generator.generateSolution();
self.generatedClues = generator.generateClues(self.targetSolution);
// Example: puzzle state
self.isSolved = false;
// Method to check if puzzle is solved according to target solution
self.checkSolved = function () {
// Use the generated target solution
var targetSolution = self.targetSolution || {};
// Check if all dots match the target solution
var allCorrect = true;
for (var i = 0; i < self.dots.length; i++) {
var dot = self.dots[i];
var expectedImage = targetSolution[i];
// Get current image of the dot based on its row and current index
var currentImage = 'Blank';
var row = dot.gridY;
if (row === 0 && dot.instruments) {
// Row 1: Music instruments
currentImage = dot.instruments[dot.instrumentIndex];
} else if (row === 1 && dot.foodImages) {
// Row 2: Food
currentImage = dot.foodImages[dot.foodIndex];
} else if (row === 2 && dot.toyImages) {
// Row 3: Toys
currentImage = dot.toyImages[dot.toyIndex];
} else if (row === 3 && dot.animalImages) {
// Row 4: Animals
currentImage = dot.animalImages[dot.animalIndex];
} else if (row === 4 && dot.specialInstruments) {
// Row 5: Family
currentImage = dot.specialInstruments[dot.specialInstrumentIndex];
}
// Check if current image matches expected
if (currentImage !== expectedImage) {
allCorrect = false;
break;
}
}
// Update solved state only - win display handled by green tick
if (allCorrect && !self.isSolved) {
self.isSolved = true;
} else if (!allCorrect && self.isSolved) {
self.isSolved = false;
}
};
// Example: update method for per-frame logic
self.update = function () {
// Add per-frame puzzle logic here
// For example, check for completion
self.checkSolved();
};
return self;
});
// PuzzleGenerator class for creating randomized puzzle solutions and clues
var PuzzleGenerator = Container.expand(function () {
var self = Container.call(this);
// Available items for each category (row) - expanded to include all factors
self.categories = {
0: ['Drum', 'Harp', 'Saxophone', 'Flute', 'Gutair'],
// Instruments - matches self.instruments array in Dot class
1: ['Pizza', 'Chips', 'Icecream', 'Donut', 'Spaghetti'],
// Food - matches self.foodImages array in Dot class
2: ['Basketball', 'Dolls', 'Lego', 'Videogame', 'Plushtoy'],
// Toys - matches self.toyImages array in Dot class
3: ['Fish', 'Turtle', 'Frog', 'Cat', 'Dog'],
// Animals - matches self.animalImages array in Dot class
4: ['KJ', 'Khalida', 'Sapphire', 'Harmony', 'PJ'] // People - matches self.specialInstruments array in Dot class
};
// Generate a random valid solution
self.generateSolution = function () {
var solution = {};
// For each row, randomly assign the 5 items to the 5 positions
for (var row = 0; row < 5; row++) {
var items = self.categories[row].slice(); // Copy array
// Shuffle items using Fisher-Yates algorithm
for (var i = items.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = items[i];
items[i] = items[j];
items[j] = temp;
}
// Assign shuffled items to positions
for (var col = 0; col < 5; col++) {
var dotIndex = row * 5 + col;
solution[dotIndex] = items[col];
}
}
return solution;
};
// Generate clues based on the solution
self.generateClues = function (solution) {
var clues = [];
var usedClues = {}; // Track used clues to prevent duplicates
// Validate solution exists and has required data
if (!solution || _typeof2(solution) !== 'object') {
return clues;
}
// Helper function to validate clue items
function isValidItem(item) {
return item && typeof item === 'string' && item !== 'Blank';
}
// Helper function to create unique clue key
function createClueKey(clue) {
if (clue.type === 'equals') {
var items = [clue.item1, clue.item2].sort();
return clue.type + ':' + items[0] + '=' + items[1];
} else if (clue.type === 'order') {
return clue.type + ':' + clue.item1 + clue.operator + clue.item2;
} else if (clue.type === 'position') {
return clue.type + ':' + clue.item1 + '=' + clue.position;
}
return '';
}
// Strategy: Generate more targeted clues that create logical chains
// 1. Start with position clues for anchor points (all columns for better coverage)
var anchorPositions = [0, 1, 2, 3, 4]; // all columns 1-5 for comprehensive coverage
for (var i = 0; i < anchorPositions.length && clues.length < 8; i++) {
var col = anchorPositions[i];
var row = Math.floor(Math.random() * 5);
var item = solution[row * 5 + col];
if (isValidItem(item)) {
var clueCandidate = {
type: 'position',
item1: item,
position: col + 1
};
var clueKey = createClueKey(clueCandidate);
if (!usedClues[clueKey]) {
clues.push(clueCandidate);
usedClues[clueKey] = true;
}
}
}
// 2. Generate strategic equality clues - ensure coverage across all columns
var equalityAttempts = 0;
while (clues.length < 15 && equalityAttempts < 50) {
// Distribute equality clues across all columns for better coverage
var col = Math.floor(Math.random() * 5);
var row1 = Math.floor(Math.random() * 5);
var row2;
do {
row2 = Math.floor(Math.random() * 5);
} while (row2 === row1);
var item1 = solution[row1 * 5 + col];
var item2 = solution[row2 * 5 + col];
if (isValidItem(item1) && isValidItem(item2) && item1 !== item2) {
var clueCandidate = {
type: 'equals',
item1: item1,
item2: item2
};
var clueKey = createClueKey(clueCandidate);
if (!usedClues[clueKey]) {
clues.push(clueCandidate);
usedClues[clueKey] = true;
}
}
equalityAttempts++;
}
// 3. Generate ordering clues that create logical connections across all rows
var orderAttempts = 0;
while (clues.length < 22 && orderAttempts < 80) {
var row = Math.floor(Math.random() * 5);
var col1 = Math.floor(Math.random() * 4);
var col2 = col1 + 1;
var item1 = solution[row * 5 + col1];
var item2 = solution[row * 5 + col2];
var operator = '<';
// Check for existing clue connections to prioritize logical chains
var hasExistingClue = false;
for (var c = 0; c < clues.length; c++) {
if (clues[c].item1 === item1 || clues[c].item1 === item2 || clues[c].item2 === item1 || clues[c].item2 === item2) {
hasExistingClue = true;
break;
}
}
if (isValidItem(item1) && isValidItem(item2) && item1 !== item2) {
var clueCandidate = {
type: 'order',
item1: item1,
item2: item2,
operator: operator
};
var clueKey = createClueKey(clueCandidate);
if (!usedClues[clueKey]) {
// Accept all valid ordering clues to ensure comprehensive coverage
clues.push(clueCandidate);
usedClues[clueKey] = true;
}
}
orderAttempts++;
}
// 4. Fill remaining slots with additional strategic clues
var fillAttempts = 0;
while (clues.length < 25 && fillAttempts < 30) {
var clueType = Math.random();
if (clueType < 0.4) {
// Additional position clues for remaining columns
var col = Math.floor(Math.random() * 5);
var row = Math.floor(Math.random() * 5);
var item = solution[row * 5 + col];
if (isValidItem(item)) {
var clueCandidate = {
type: 'position',
item1: item,
position: col + 1
};
var clueKey = createClueKey(clueCandidate);
if (!usedClues[clueKey]) {
clues.push(clueCandidate);
usedClues[clueKey] = true;
}
}
} else {
// Additional equality clues
var col = Math.floor(Math.random() * 5);
var row1 = Math.floor(Math.random() * 5);
var row2;
do {
row2 = Math.floor(Math.random() * 5);
} while (row2 === row1);
var item1 = solution[row1 * 5 + col];
var item2 = solution[row2 * 5 + col];
if (isValidItem(item1) && isValidItem(item2) && item1 !== item2) {
var clueCandidate = {
type: 'equals',
item1: item1,
item2: item2
};
var clueKey = createClueKey(clueCandidate);
if (!usedClues[clueKey]) {
clues.push(clueCandidate);
usedClues[clueKey] = true;
}
}
}
fillAttempts++;
}
return clues;
};
return self;
});
// StoryScene class for displaying story content
var StoryScene = Container.expand(function () {
var self = Container.call(this);
// Add background
var bg = self.attachAsset('Street', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 20.48,
scaleY: 27.32,
alpha: 0.95
});
// Add story content container
var storyContent = new Container();
self.addChild(storyContent);
// --- SCENE DATA ---
var scenes = [{
// First scene
imageId: 'First',
text: "Once upon a time, in a magical puzzle world,\nthere lived characters who needed your help\nto solve their mysteries..."
}, {
// Second scene
imageId: 'Second',
text: "Each puzzle you solve brings harmony to their world.\nAre you ready to begin your adventure?"
}];
var currentScene = 0;
// Add story title
var storyTitle = new Text2("STORY", {
size: 120,
fill: 0xFFFFFF,
align: 'center',
font: "'Times New Roman','Times New Roman Bold','GillSans-Bold',Impact,'Arial Black',Tahoma"
});
storyTitle.anchor.set(0.5, 0.5);
storyTitle.x = 2048 / 2;
storyTitle.y = 300;
storyContent.addChild(storyTitle);
// Add story image (centered, fills screen)
var storyImage = storyContent.attachAsset(scenes[0].imageId, {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 1.0,
scaleY: 1.0
});
// Add story text
var storyText = new Text2(scenes[0].text, {
size: 80,
fill: 0xFFFFFF,
align: 'center',
font: "'Times New Roman','Times New Roman Bold','GillSans-Bold',Impact,'Arial Black',Tahoma"
});
storyText.anchor.set(0.5, 0.5);
storyText.x = 2048 / 2;
storyText.y = 2732 - 600;
storyContent.addChild(storyText);
// Add continue button
var continueText = new Text2("TAP TO CONTINUE", {
size: 100,
fill: 0xFFFF00,
align: 'center',
font: "'Times New Roman','Times New Roman Bold','GillSans-Bold',Impact,'Arial Black',Tahoma"
});
continueText.anchor.set(0.5, 0.5);
continueText.x = 2048 / 2;
continueText.y = 2732 - 400;
storyContent.addChild(continueText);
// Pulse the continue text
var _pulseContinueText = function pulseContinueText() {
tween(continueText, {
alpha: 0.3
}, {
duration: 800,
easing: tween.sineInOut,
onFinish: function onFinish() {
tween(continueText, {
alpha: 1
}, {
duration: 800,
easing: tween.sineInOut,
onFinish: _pulseContinueText
});
}
});
};
_pulseContinueText();
// Helper to update scene visuals with smooth fade transition
function showScene(idx) {
if (idx < 0 || idx >= scenes.length) return;
// Fade out current image and text, then swap and fade in
var fadeOutDuration = 350;
var fadeInDuration = 350;
// Helper to fade in new image and text
function fadeInNewScene() {
// Swap image
if (storyImage && storyImage.parent) {
storyImage.parent.removeChild(storyImage);
}
var newImg = storyContent.attachAsset(scenes[idx].imageId, {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 1.0,
scaleY: 1.0
});
newImg.alpha = 0;
storyImage = newImg;
// Update text
storyText.setText(scenes[idx].text);
storyText.alpha = 0;
// Fade in new image and text
tween(newImg, {
alpha: 1
}, {
duration: fadeInDuration,
easing: tween.cubicOut
});
tween(storyText, {
alpha: 1
}, {
duration: fadeInDuration,
easing: tween.cubicOut
});
}
// Fade out current image and text, then call fadeInNewScene
if (storyImage && storyText) {
tween(storyImage, {
alpha: 0
}, {
duration: fadeOutDuration,
easing: tween.cubicIn,
onFinish: fadeInNewScene
});
tween(storyText, {
alpha: 0
}, {
duration: fadeOutDuration,
easing: tween.cubicIn
});
} else {
// If no image/text, just show new scene
fadeInNewScene();
}
}
// Handle tap/click to continue
self.down = function (x, y, obj) {
if (currentScene < scenes.length - 1) {
// Go to next scene
currentScene++;
showScene(currentScene);
} else {
// Fade out story scene
tween(self, {
alpha: 0
}, {
duration: 500,
easing: tween.cubicOut,
onFinish: function onFinish() {
if (self.parent) {
self.parent.removeChild(self);
// Start the main game
startMainGame();
}
}
});
}
};
return self;
});
// TitleScreen class for the game's title screen
var TitleScreen = Container.expand(function () {
var self = Container.call(this);
// Add background
var bg = self.attachAsset('Street', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 20.48,
scaleY: 27.32,
alpha: 0.95
});
// Add title image to fill the whole screen
var titleImg = self.attachAsset('Title', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 1.0,
scaleY: 1.0
});
// Add animated swirl image, centered, IN FRONT of title
var swirlImg = self.attachAsset('Swirl', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.45
});
self.swirlImg = swirlImg;
// Add heading image above the title image and swirl, so it is in front of both
// Start tiny in the center, then tween to large in the center
var headingImg = self.attachAsset('Heading', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
// Start in the center
scaleX: 0.1,
scaleY: 0.1
});
// Add loading text that shows while assets are loading
var loadingText = new Text2("LOADING...", {
size: 80,
fill: 0xFFFFFF,
align: 'center',
font: "'Times New Roman','Times New Roman Bold','GillSans-Bold',Impact,'Arial Black',Tahoma"
});
loadingText.anchor.set(0.5, 0.5);
loadingText.x = 2048 / 2;
loadingText.y = 2732 / 2 + 600;
loadingText.alpha = 1;
self.addChild(loadingText);
// Pulse the loading text while assets load
var _pulseLoadingText = function pulseLoadingText() {
if (!loadingText || !loadingText.parent) return;
tween(loadingText, {
alpha: 0.3
}, {
duration: 600,
easing: tween.sineInOut,
onFinish: function onFinish() {
if (!loadingText || !loadingText.parent) return;
tween(loadingText, {
alpha: 1
}, {
duration: 600,
easing: tween.sineInOut,
onFinish: _pulseLoadingText
});
}
});
};
_pulseLoadingText();
// Animate heading to grow and stay in the center position, but only after fully loaded
function startTitleScreenAnimations() {
// Fade out loading text first
if (loadingText && loadingText.parent) {
tween(loadingText, {
alpha: 0
}, {
duration: 500,
easing: tween.cubicOut,
onFinish: function onFinish() {
if (loadingText && loadingText.parent) {
self.removeChild(loadingText);
}
}
});
}
tween(headingImg, {
x: 2048 / 2,
y: 2732 / 2,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 5000,
easing: tween.cubicOut
});
// Animate swirl rotation using tween for infinite smooth rotation
function startSwirlTween() {
if (!self.swirlImg) return;
// Always rotate to the next full circle (-2*PI) from current rotation for opposite direction
var startRotation = self.swirlImg.rotation || 0;
var endRotation = startRotation - Math.PI * 2;
tween(self.swirlImg, {
rotation: endRotation
}, {
duration: 8000,
easing: tween.linear,
onFinish: function onFinish() {
// Reset rotation to avoid overflow and keep animation smooth
if (self.swirlImg) self.swirlImg.rotation = self.swirlImg.rotation % (Math.PI * 2);
startSwirlTween();
}
});
}
startSwirlTween();
}
// Wait 2 seconds to simulate asset loading delay, then start animations
LK.setTimeout(function () {
if (self && self.parent) {
startTitleScreenAnimations();
}
}, 2000);
// Add "Tap to Start" text with pulsing effect
var startText = new Text2("TAP TO START", {
size: 120,
fill: 0xFFFF00,
align: 'center',
font: "'Times New Roman','Times New Roman Bold','GillSans-Bold',Impact,'Arial Black',Tahoma"
});
startText.anchor.set(0.5, 0.5);
startText.x = 2048 / 2;
startText.y = 2732 - 300;
self.addChild(startText);
// Pulse the start text
var _pulseStartText = function pulseStartText() {
tween(startText, {
alpha: 0.3
}, {
duration: 800,
easing: tween.sineInOut,
onFinish: function onFinish() {
tween(startText, {
alpha: 1
}, {
duration: 800,
easing: tween.sineInOut,
onFinish: _pulseStartText
});
}
});
};
_pulseStartText();
// Handle tap/click to start game
self.down = function (x, y, obj) {
// Fade out title screen
tween(self, {
alpha: 0
}, {
duration: 500,
easing: tween.cubicOut,
onFinish: function onFinish() {
if (self.parent) {
self.parent.removeChild(self);
// Start the main game directly
startMainGame();
}
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Global variables that need to be accessible
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 usedInstruments = {};
var puzzle;
var greenTick;
var numberImages = [];
var allClueAssets = [];
var infoButton;
var instructionsScreen = null;
var clueStrikeStates = [false, false];
var usedSpecialInstruments = {};
var usedAnimalImages = {};
var usedFoodImages = {};
var usedToyImages = {};
// Function to start the main game after title screen
function startMainGame() {
// Initialize win/loss counters from storage with defaults
if (typeof storage.wins === 'undefined') storage.wins = 0;
if (typeof storage.losses === 'undefined') storage.losses = 0;
// Reset global variables
usedInstruments = {};
usedSpecialInstruments = {};
usedAnimalImages = {};
usedFoodImages = {};
usedToyImages = {};
numberImages = [];
allClueAssets = [];
// Reset clueStrikeStates BEFORE creating clues to prevent old state from being applied
clueStrikeStates = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false];
// Add Puzzle to the game when it starts
puzzle = new Puzzle();
game.addChild(puzzle);
// Reset all dots to ensure clean state
for (var i = 0; i < puzzle.dots.length; i++) {
var dot = puzzle.dots[i];
// Reset all indices to 0
dot.instrumentIndex = 0;
dot.specialInstrumentIndex = 0;
dot.animalIndex = 0;
dot.foodIndex = 0;
dot.toyIndex = 0;
// Clear current instrument and reset to blank
if (dot.currentInstrument) {
dot.removeChild(dot.currentInstrument);
dot.currentInstrument = null;
}
// Set to blank instrument
dot.currentInstrument = dot.attachAsset('Blank', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
}
// Add 1 2 3 4 5 number image assets to the top of the screen
var numberLabelY = 60; // 60px from top
var numberSpacing = 2048 / 6; // 5 numbers, 6 spaces
// Track number image assets for later removal
var numberImages = [];
for (var i = 1; i <= 5; i++) {
var numImg = LK.getAsset(i + "", {
anchorX: 0.5,
anchorY: 0,
x: i * numberSpacing,
y: numberLabelY,
scaleX: 0.7,
scaleY: 0.7
});
game.addChild(numImg);
numberImages.push(numImg);
}
// --- CLUE STRIKETHROUGH LOGIC ---
// Track strikethrough state for clues (first two clues only for now)
var clueStrikeStates = [false, false];
// Helper to apply or remove strikethrough effect (alpha fade) for a group of clue assets
function setClueStrikethrough(clueGroup, isStruck) {
var alpha = isStruck ? 0.35 : 1.0;
for (var i = 0; i < clueGroup.length; i++) {
if (clueGroup[i]) clueGroup[i].alpha = alpha;
}
}
// Helper to toggle strikethrough and remember state
// Optionally accepts a clueIndex to persist state for first two clues
function makeClueStrikeToggle(clueGroup, clueIndex) {
var struck = false;
// If restoring, use persisted state
if (typeof clueIndex === "number" && clueStrikeStates[clueIndex] !== undefined) {
struck = clueStrikeStates[clueIndex];
setClueStrikethrough(clueGroup, struck);
}
for (var i = 0; i < clueGroup.length; i++) {
// Attach to all, but only one will handle the toggle
clueGroup[i].down = function () {
struck = !struck;
setClueStrikethrough(clueGroup, struck);
if (typeof clueIndex === "number") {
clueStrikeStates[clueIndex] = struck;
}
};
}
}
// Generate dynamic clues based on the puzzle solution
var clueAssets = [];
var clueY = 2732 - 40 - 500 + 30;
var clueX = 30;
var clueSpacing = 120;
var clueIndex = 0;
// Create visual clues from generated clue data
for (var i = 0; i < puzzle.generatedClues.length && i < 25; i++) {
var clue = puzzle.generatedClues[i];
// Skip clue if it has invalid properties
if (!clue || !clue.item1) {
continue;
}
var clueAssetGroup = [];
// Calculate position (5 columns of 5 clues each)
// Adjust column spacing to fit within screen width (2048px)
var columnSpacing = (2048 - clueX * 2) / 5; // Distribute 5 columns evenly across available width
var columnX = clueX + Math.floor(clueIndex / 5) * columnSpacing;
var currentY = clueY + clueIndex % 5 * clueSpacing;
// Create first item with proper scaling for special items
var item1Scale = 0.45;
var item1ExtraY = 0;
if (clue.item1 === 'Harmony') {
item1Scale = 0.55;
item1ExtraY = -10;
} else if (clue.item1 === 'Khalida') {
item1ExtraY = -10;
} else if (clue.item1 === 'KJ') {
item1ExtraY = 5;
}
var item1Asset = LK.getAsset(clue.item1, {
anchorX: 0.0,
anchorY: 1.0,
x: columnX,
y: currentY + item1ExtraY,
scaleX: item1Scale,
scaleY: item1Scale
});
game.addChild(item1Asset);
clueAssetGroup.push(item1Asset);
// Create operator text
var operatorText;
if (clue.type === 'equals') {
operatorText = "=";
} else if (clue.type === 'order') {
operatorText = clue.operator;
} else if (clue.type === 'position') {
operatorText = "=";
}
var opText = new Text2(operatorText, {
size: 120,
fill: 0xFFFFFF
});
opText.anchor.set(0.5, 1.0);
opText.x = columnX + 200 * 0.45 + 30;
opText.y = currentY;
game.addChild(opText);
clueAssetGroup.push(opText);
// Create second item
var secondItem;
var item2Scale = 0.45;
var item2ExtraY = 0;
if (clue.type === 'position') {
secondItem = clue.position.toString();
} else {
secondItem = clue.item2;
// Apply special scaling for second item too
if (secondItem && secondItem === 'Harmony') {
item2Scale = 0.55;
item2ExtraY = -10;
} else if (secondItem && secondItem === 'Khalida') {
item2ExtraY = -10;
} else if (secondItem && secondItem === 'KJ') {
item2ExtraY = 5;
}
}
// Only create second item if it exists
if (secondItem) {
var item2Asset = LK.getAsset(secondItem, {
anchorX: 0.0,
anchorY: 1.0,
x: columnX + 200 * 0.45 + 60,
y: currentY + item2ExtraY,
scaleX: item2Scale,
scaleY: item2Scale
});
game.addChild(item2Asset);
clueAssetGroup.push(item2Asset);
}
// Add strikethrough functionality
makeClueStrikeToggle(clueAssetGroup, i < 2 ? i : undefined);
// Store for later cleanup
clueAssets = clueAssets.concat(clueAssetGroup);
clueIndex++;
}
// Store clue assets globally for cleanup
allClueAssets = clueAssets;
// Add green tick to bottom right corner
var greenTick = LK.getAsset('Greentick', {
anchorX: 1.0,
anchorY: 1.0,
x: 2048 - 0,
//{7i} // moved right by 50px
y: 2732 - 50 - 600 - 35,
// moved up by 15px (previously 10, now 15)
scaleX: 0.8,
scaleY: 0.8
});
game.addChild(greenTick);
// Add info button to bottom left corner
var infoButton = LK.getAsset('Info', {
anchorX: 0.0,
anchorY: 1.0,
x: 0,
y: 2732 - 50 - 600 - 30,
scaleX: 1.5,
scaleY: 1.5
});
game.addChild(infoButton);
// Variable to track instructions screen
var instructionsScreen = null;
// Make info button clickable to show illustrated how-to-play guide
infoButton.down = function (x, y, obj) {
// If instructions screen is already showing, hide it
if (instructionsScreen && instructionsScreen.parent) {
instructionsScreen.parent.removeChild(instructionsScreen);
instructionsScreen = null;
return;
}
// Create instructions screen container
instructionsScreen = new Container();
// Add semi-transparent background
var instructionsBg = LK.getAsset('Street', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 20.48,
scaleY: 27.32,
alpha: 0.92
});
instructionsScreen.addChild(instructionsBg);
// Add "How to Play" asset to the top of the instructions page
var howToPlayAsset = LK.getAsset('Howtoplaybutton', {
anchorX: 0.5,
anchorY: 0,
x: 2048 / 2,
y: 80,
scaleX: 1.0,
scaleY: 1.0
});
instructionsScreen.addChild(howToPlayAsset);
// Add visual clue examples to help players understand the clue system
// Example 1: Equality clue (Sapphire = Chips)
var exampleSapphire = LK.getAsset('Sapphire', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 - 200,
y: 800,
scaleX: 0.6,
scaleY: 0.6
});
instructionsScreen.addChild(exampleSapphire);
var exampleEquals = new Text2("=", {
size: 80,
fill: 0xFFFFFF
});
exampleEquals.anchor.set(0.5, 0.5);
exampleEquals.x = 2048 / 2;
exampleEquals.y = 800;
instructionsScreen.addChild(exampleEquals);
var exampleChips = LK.getAsset('Chips', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 + 200,
y: 800,
scaleX: 0.6,
scaleY: 0.6
});
instructionsScreen.addChild(exampleChips);
// Example 2: Less than clue (Donut < Chips)
var exampleDonut = LK.getAsset('Donut', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 - 200,
y: 950,
scaleX: 0.6,
scaleY: 0.6
});
instructionsScreen.addChild(exampleDonut);
var exampleLessThan = new Text2("<", {
size: 80,
fill: 0xFFFFFF
});
exampleLessThan.anchor.set(0.5, 0.5);
exampleLessThan.x = 2048 / 2;
exampleLessThan.y = 950;
instructionsScreen.addChild(exampleLessThan);
var exampleChips2 = LK.getAsset('Chips', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 + 200,
y: 950,
scaleX: 0.6,
scaleY: 0.6
});
instructionsScreen.addChild(exampleChips2);
// Example 3: Greater than clue (Guitar > Cat)
var exampleGuitar = LK.getAsset('Gutair', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 - 200,
y: 1100,
scaleX: 0.6,
scaleY: 0.6
});
instructionsScreen.addChild(exampleGuitar);
var exampleGreaterThan = new Text2(">", {
size: 80,
fill: 0xFFFFFF
});
exampleGreaterThan.anchor.set(0.5, 0.5);
exampleGreaterThan.x = 2048 / 2;
exampleGreaterThan.y = 1100;
instructionsScreen.addChild(exampleGreaterThan);
var exampleCat = LK.getAsset('Cat', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 + 200,
y: 1100,
scaleX: 0.6,
scaleY: 0.6
});
instructionsScreen.addChild(exampleCat);
// Add step-by-step text instructions positioned below the visual examples
var instructionsText = new Text2("HOW TO PLAY THIS PUZZLE GAME\n\n" + "1. TAP ANY QUESTION MARK to cycle through available pictures\n" + "2. USE THE CLUES (examples shown above):\n" + " β’ = means 'equals' or 'matches'\n" + " β’ < means 'comes before' (left to right)\n" + " β’ > means 'comes after' (left to right)\n\n" + "3. STRIKE THROUGH CLUES by tapping them\n" + "4. CHECK YOUR ANSWER by tapping the green tick\n\n" + "Tap anywhere to close this guide.", {
size: 60,
fill: 0xffffff,
align: 'center',
font: "'Times New Roman Bold','Times New Roman','GillSans-Bold',Impact,'Arial Black',Tahoma"
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = 2048 / 2;
instructionsText.y = 2732 / 2 + 100 + 300;
instructionsScreen.addChild(instructionsText);
// Make the entire instructions screen clickable to close
instructionsScreen.down = function (x, y, obj) {
if (instructionsScreen && instructionsScreen.parent) {
instructionsScreen.parent.removeChild(instructionsScreen);
instructionsScreen = null;
}
};
// Add instructions screen to game
game.addChild(instructionsScreen);
};
// Helper to show/hide info button
function setInfoButtonVisible(visible) {
if (infoButton && infoButton.parent) {
infoButton.visible = !!visible;
}
}
// Function to update clues with strikethrough for solved items (picture clues only)
function updateCluesWithStrikethrough() {
// This function now only handles picture clue strikethrough effects
// The picture clues are already implemented with makeClueStrikeToggle
// No additional text-based clue processing needed
}
// Make green tick clickable to enter puzzle attempt
greenTick.down = function (x, y, obj) {
// Remove all clue assets from game when green tick is clicked
if (typeof allClueAssets === "undefined") allClueAssets = [];
for (var i = 0; i < allClueAssets.length; i++) {
if (allClueAssets[i] && allClueAssets[i].parent) {
allClueAssets[i].parent.removeChild(allClueAssets[i]);
}
}
// Remove number image assets from game when green tick is clicked
if (typeof numberImages !== "undefined" && numberImages.length) {
for (var i = 0; i < numberImages.length; i++) {
if (numberImages[i] && numberImages[i].parent) numberImages[i].parent.removeChild(numberImages[i]);
}
}
if (puzzle && typeof puzzle.checkSolved === "function") {
// Run the check
puzzle.checkSolved();
// If solved, show endpuzzletwo scene
if (puzzle.isSolved) {
// Remove the puzzle and green tick from the game
if (puzzle.parent) puzzle.parent.removeChild(puzzle);
if (greenTick.parent) greenTick.parent.removeChild(greenTick);
// Hide info button when showing endpuzzletwo
setInfoButtonVisible(false);
// Show endpuzzletwo asset centered on screen
var endpuzzletwo = LK.getAsset('Endpuzzletwo', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 2.2,
scaleY: 2.2,
alpha: 0
});
game.addChild(endpuzzletwo);
// Fade in endpuzzletwo
tween(endpuzzletwo, {
alpha: 1
}, {
duration: 350,
easing: tween.cubicOut
});
// After 2 seconds, fade out and swap to correct scene with correct word under the correct image
LK.setTimeout(function () {
tween(endpuzzletwo, {
alpha: 0
}, {
duration: 350,
easing: tween.cubicIn,
onFinish: function onFinish() {
if (endpuzzletwo.parent) endpuzzletwo.parent.removeChild(endpuzzletwo);
// Show Correct scene (centered)
var correctScene = LK.getAsset('Correct', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 2.2,
scaleY: 2.2,
alpha: 0
});
game.addChild(correctScene);
// Fade in correctScene
tween(correctScene, {
alpha: 1
}, {
duration: 350,
easing: tween.cubicOut
});
// No winning image displayed - just show the correct word
// Increment wins counter
storage.wins = (storage.wins || 0) + 1;
// Show the correct word asset at the bottom of the screen
var correctWord = LK.getAsset('Correctword', {
anchorX: 0.5,
anchorY: 1.0,
x: 2048 / 2,
y: 2732 - 50,
scaleX: 2.2,
scaleY: 2.2,
alpha: 0
});
game.addChild(correctWord);
tween(correctWord, {
alpha: 1
}, {
duration: 350,
easing: tween.cubicOut
});
// Add win/loss tally text on correct screen
var tallyText = new Text2("WINS: " + storage.wins + " | LOSSES: " + storage.losses, {
size: 80,
fill: 0xFFFFFF,
align: 'center'
});
tallyText.anchor.set(0.5, 0.5);
tallyText.x = 2048 / 2;
tallyText.y = 2732 / 2 - 200 - 750;
tallyText.alpha = 0;
game.addChild(tallyText);
tween(tallyText, {
alpha: 1
}, {
duration: 350,
easing: tween.cubicOut
});
// Add play again button above the correct word
var playAgainBtnY = 2732 - 50 - correctWord.height * 2.2 - 40; // 40px above correct word
var playAgainBtn = LK.getAsset('Playagain', {
anchorX: 0.5,
anchorY: 1.0,
x: 2048 / 2,
y: playAgainBtnY,
scaleX: 1.8,
scaleY: 1.8,
alpha: 0
});
game.addChild(playAgainBtn);
tween(playAgainBtn, {
alpha: 1
}, {
duration: 350,
easing: tween.cubicOut
});
// Play again button handler: remove correct scene and restart puzzle
playAgainBtn.down = function (x, y, obj) {
// Fade out all correct scene assets, then remove and reset
var fadeOuts = [correctScene, correctWord, playAgainBtn, tallyText];
var fadeCount = 0;
var fadeDone = function fadeDone() {
fadeCount++;
if (fadeCount === fadeOuts.length) {
// Remove all correct scene assets
if (correctScene && correctScene.parent) correctScene.parent.removeChild(correctScene);
if (correctWord && correctWord.parent) correctWord.parent.removeChild(correctWord);
if (playAgainBtn && playAgainBtn.parent) playAgainBtn.parent.removeChild(playAgainBtn);
if (tallyText && tallyText.parent) tallyText.parent.removeChild(tallyText);
// Reset all used image trackers so dots can be reused
usedInstruments = {};
usedSpecialInstruments = {};
usedAnimalImages = {};
usedFoodImages = {};
usedToyImages = {};
// Reset strikethrough state for all clues BEFORE creating new puzzle
clueStrikeStates = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false];
// Re-add puzzle and green tick
puzzle = new Puzzle();
game.addChild(puzzle);
game.addChild(greenTick);
// Reset all dots to ensure clean state
for (var i = 0; i < puzzle.dots.length; i++) {
var dot = puzzle.dots[i];
// Reset all indices to 0
dot.instrumentIndex = 0;
dot.specialInstrumentIndex = 0;
dot.animalIndex = 0;
dot.foodIndex = 0;
dot.toyIndex = 0;
// Clear current instrument and reset to blank
if (dot.currentInstrument) {
dot.removeChild(dot.currentInstrument);
dot.currentInstrument = null;
}
// Set to blank instrument
dot.currentInstrument = dot.attachAsset('Blank', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
}
// Re-add number image assets to the top of the screen
numberImages = [];
for (var i = 1; i <= 5; i++) {
var numImg = LK.getAsset(i + "", {
anchorX: 0.5,
anchorY: 0,
x: i * (2048 / 6),
y: 60,
scaleX: 0.7,
scaleY: 0.7
});
game.addChild(numImg);
numberImages.push(numImg);
}
// Generate new dynamic clues for the new puzzle
var clueAssets = [];
var clueY = 2732 - 40 - 500 + 30;
var clueX = 30;
var clueSpacing = 120;
var clueIndex = 0;
// Create visual clues from generated clue data
for (var i = 0; i < puzzle.generatedClues.length && i < 25; i++) {
var clue = puzzle.generatedClues[i];
// Skip clue if it has invalid properties
if (!clue || !clue.item1) {
continue;
}
var clueAssetGroup = [];
// Calculate position (5 columns of 5 clues each)
// Adjust column spacing to fit within screen width (2048px)
var columnSpacing = (2048 - clueX * 2) / 5; // Distribute 5 columns evenly across available width
var columnX = clueX + Math.floor(clueIndex / 5) * columnSpacing;
var currentY = clueY + clueIndex % 5 * clueSpacing;
// Create first item with proper scaling for special items
var item1Scale = 0.45;
var item1ExtraY = 0;
if (clue.item1 === 'Harmony') {
item1Scale = 0.55;
item1ExtraY = -10;
} else if (clue.item1 === 'Khalida') {
item1ExtraY = -10;
} else if (clue.item1 === 'KJ') {
item1ExtraY = 5;
}
var item1Asset = LK.getAsset(clue.item1, {
anchorX: 0.0,
anchorY: 1.0,
x: columnX,
y: currentY + item1ExtraY,
scaleX: item1Scale,
scaleY: item1Scale
});
game.addChild(item1Asset);
clueAssetGroup.push(item1Asset);
// Create operator text
var operatorText;
if (clue.type === 'equals') {
operatorText = "=";
} else if (clue.type === 'order') {
operatorText = clue.operator;
} else if (clue.type === 'position') {
operatorText = "=";
}
var opText = new Text2(operatorText, {
size: 120,
fill: 0xFFFFFF
});
opText.anchor.set(0.5, 1.0);
opText.x = columnX + 200 * 0.45 + 30;
opText.y = currentY;
game.addChild(opText);
clueAssetGroup.push(opText);
// Create second item
var secondItem;
var item2Scale = 0.45;
var item2ExtraY = 0;
if (clue.type === 'position') {
secondItem = clue.position.toString();
} else {
secondItem = clue.item2;
// Apply special scaling for second item too
if (secondItem && secondItem === 'Harmony') {
item2Scale = 0.55;
item2ExtraY = -10;
} else if (secondItem && secondItem === 'Khalida') {
item2ExtraY = -10;
} else if (secondItem && secondItem === 'KJ') {
item2ExtraY = 5;
}
}
// Only create second item if it exists
if (secondItem) {
var item2Asset = LK.getAsset(secondItem, {
anchorX: 0.0,
anchorY: 1.0,
x: columnX + 200 * 0.45 + 60,
y: currentY + item2ExtraY,
scaleX: item2Scale,
scaleY: item2Scale
});
game.addChild(item2Asset);
clueAssetGroup.push(item2Asset);
}
// Add strikethrough functionality
makeClueStrikeToggle(clueAssetGroup, i < 2 ? i : undefined);
// Store for later cleanup
clueAssets = clueAssets.concat(clueAssetGroup);
clueIndex++;
}
// Update global reference
allClueAssets = clueAssets;
// Show info button again after play again
setInfoButtonVisible(true);
}
};
for (var i = 0; i < fadeOuts.length; i++) {
if (fadeOuts[i]) {
tween(fadeOuts[i], {
alpha: 0
}, {
duration: 250,
easing: tween.cubicIn,
onFinish: fadeDone
});
} else {
fadeDone();
}
}
};
}
});
}, 2000);
} else {
// If not solved, show endgame1 scene
if (puzzle.parent) puzzle.parent.removeChild(puzzle);
if (greenTick.parent) greenTick.parent.removeChild(greenTick);
// Hide info button when showing endgame1
setInfoButtonVisible(false);
// Show endgame1 asset centered on screen
var endgame1 = LK.getAsset('Endpuzzleone', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 2.2,
scaleY: 2.2,
alpha: 0
});
game.addChild(endgame1);
tween(endgame1, {
alpha: 1
}, {
duration: 350,
easing: tween.cubicOut
});
// After 2 seconds, fade out and swap to incorrect scene with incorrect word under the incorrect image
LK.setTimeout(function () {
tween(endgame1, {
alpha: 0
}, {
duration: 350,
easing: tween.cubicIn,
onFinish: function onFinish() {
if (endgame1.parent) endgame1.parent.removeChild(endgame1);
// Show Incorrect scene (centered)
var incorrectScene = LK.getAsset('Incorrect', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 2.2,
scaleY: 2.2,
alpha: 0
});
game.addChild(incorrectScene);
tween(incorrectScene, {
alpha: 1
}, {
duration: 350,
easing: tween.cubicOut
});
// Find the first incorrect dot and its expected word
var targetSolution = puzzle.targetSolution || {};
var firstWrongIdx = -1;
var wrongActual = '';
var wrongExpected = '';
for (var i = 0; i < puzzle.dots.length; i++) {
var dot = puzzle.dots[i];
var expected = targetSolution[i];
var actual = 'Blank';
var row = dot.gridY;
// Get current image based on row and index
if (row === 0 && dot.instruments) {
actual = dot.instruments[dot.instrumentIndex];
} else if (row === 1 && dot.foodImages) {
actual = dot.foodImages[dot.foodIndex];
} else if (row === 2 && dot.toyImages) {
actual = dot.toyImages[dot.toyIndex];
} else if (row === 3 && dot.animalImages) {
actual = dot.animalImages[dot.animalIndex];
} else if (row === 4 && dot.specialInstruments) {
actual = dot.specialInstruments[dot.specialInstrumentIndex];
}
if (actual !== expected) {
firstWrongIdx = i;
wrongActual = actual;
wrongExpected = expected;
break;
}
}
// If found, show the incorrect image and word under it
if (firstWrongIdx !== -1) {
var wrongImg = null;
var imgY = 2732 / 2 + 100;
var wordY = imgY;
// Only show the image if it's not 'Blank'
if (wrongActual !== 'Blank') {
wrongImg = LK.getAsset(wrongActual, {
anchorX: 0.5,
anchorY: 1.0,
x: 2048 / 2,
y: imgY,
alpha: 0
});
game.addChild(wrongImg);
tween(wrongImg, {
alpha: 1
}, {
duration: 350,
easing: tween.cubicOut
});
wordY = 2732 / 2 + 120 + (wrongImg.height || 100); // 20px below image
} else {
// If blank, just show the word lower down
wordY = 2732 / 2 + 120;
}
// Increment losses counter
storage.losses = (storage.losses || 0) + 1;
// Show the incorrect word asset at the bottom of the screen
var incorrectWord = LK.getAsset('Incorrectword', {
anchorX: 0.5,
anchorY: 1.0,
x: 2048 / 2,
y: 2732 - 50,
// 50px padding from bottom
scaleX: 2.2,
scaleY: 2.2,
alpha: 0
});
game.addChild(incorrectWord);
tween(incorrectWord, {
alpha: 1
}, {
duration: 350,
easing: tween.cubicOut
});
// Add win/loss tally text on incorrect screen
var incorrectTallyText = new Text2("WINS: " + storage.wins + " | LOSSES: " + storage.losses, {
size: 80,
fill: 0xFFFFFF,
align: 'center'
});
incorrectTallyText.anchor.set(0.5, 0.5);
incorrectTallyText.x = 2048 / 2;
incorrectTallyText.y = 2732 / 2 - 200 - 750;
incorrectTallyText.alpha = 0;
game.addChild(incorrectTallyText);
tween(incorrectTallyText, {
alpha: 1
}, {
duration: 350,
easing: tween.cubicOut
});
// Add retry button below the incorrect image/word
var retryBtnY = 2732 - 50 - incorrectWord.height * 2.2 - 40; // 40px above incorrect word
var retryBtn = LK.getAsset('Retry', {
anchorX: 0.5,
anchorY: 1.0,
x: 2048 / 2,
y: retryBtnY,
scaleX: 1.8,
scaleY: 1.8,
alpha: 0
});
game.addChild(retryBtn);
tween(retryBtn, {
alpha: 1
}, {
duration: 350,
easing: tween.cubicOut
});
// Retry button handler: remove incorrect scene and restart puzzle
retryBtn.down = function (x, y, obj) {
// Fade out all incorrect scene assets, then remove and reset
var fadeOuts = [incorrectScene, wrongImg, incorrectWord, retryBtn, incorrectTallyText];
var fadeCount = 0;
var fadeDone = function fadeDone() {
fadeCount++;
if (fadeCount === fadeOuts.length) {
// Remove all incorrect scene assets
if (incorrectScene && incorrectScene.parent) incorrectScene.parent.removeChild(incorrectScene);
if (wrongImg && wrongImg.parent) wrongImg.parent.removeChild(wrongImg);
if (incorrectWord && incorrectWord.parent) incorrectWord.parent.removeChild(incorrectWord);
if (retryBtn && retryBtn.parent) retryBtn.parent.removeChild(retryBtn);
if (incorrectTallyText && incorrectTallyText.parent) incorrectTallyText.parent.removeChild(incorrectTallyText);
// Reset all used image trackers so dots can be reused
usedInstruments = {};
usedSpecialInstruments = {};
usedAnimalImages = {};
usedFoodImages = {};
usedToyImages = {};
// Reset strikethrough state for all clues BEFORE creating new puzzle
clueStrikeStates = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false];
// Re-add puzzle and green tick
puzzle = new Puzzle();
game.addChild(puzzle);
game.addChild(greenTick);
// Reset all dots to ensure clean state
for (var i = 0; i < puzzle.dots.length; i++) {
var dot = puzzle.dots[i];
// Reset all indices to 0
dot.instrumentIndex = 0;
dot.specialInstrumentIndex = 0;
dot.animalIndex = 0;
dot.foodIndex = 0;
dot.toyIndex = 0;
// Clear current instrument and reset to blank
if (dot.currentInstrument) {
dot.removeChild(dot.currentInstrument);
dot.currentInstrument = null;
}
// Set to blank instrument
dot.currentInstrument = dot.attachAsset('Blank', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
}
// Re-add number image assets to the top of the screen
numberImages = [];
for (var i = 1; i <= 5; i++) {
var numImg = LK.getAsset(i + "", {
anchorX: 0.5,
anchorY: 0,
x: i * (2048 / 6),
y: 60,
scaleX: 0.7,
scaleY: 0.7
});
game.addChild(numImg);
numberImages.push(numImg);
}
// Generate new dynamic clues for the new puzzle
var clueAssets = [];
var clueY = 2732 - 40 - 500 + 30;
var clueX = 30;
var clueSpacing = 120;
var clueIndex = 0;
// Create visual clues from generated clue data
for (var i = 0; i < puzzle.generatedClues.length && i < 25; i++) {
var clue = puzzle.generatedClues[i];
// Skip clue if it has invalid properties
if (!clue || !clue.item1) {
continue;
}
var clueAssetGroup = [];
// Calculate position (5 columns of 5 clues each)
// Adjust column spacing to fit within screen width (2048px)
var columnSpacing = (2048 - clueX * 2) / 5; // Distribute 5 columns evenly across available width
var columnX = clueX + Math.floor(clueIndex / 5) * columnSpacing;
var currentY = clueY + clueIndex % 5 * clueSpacing;
// Create first item with proper scaling for special items
var item1Scale = 0.45;
var item1ExtraY = 0;
if (clue.item1 === 'Harmony') {
item1Scale = 0.55;
item1ExtraY = -10;
} else if (clue.item1 === 'Khalida') {
item1ExtraY = -10;
} else if (clue.item1 === 'KJ') {
item1ExtraY = 5;
}
var item1Asset = LK.getAsset(clue.item1, {
anchorX: 0.0,
anchorY: 1.0,
x: columnX,
y: currentY + item1ExtraY,
scaleX: item1Scale,
scaleY: item1Scale
});
game.addChild(item1Asset);
clueAssetGroup.push(item1Asset);
// Create operator text
var operatorText;
if (clue.type === 'equals') {
operatorText = "=";
} else if (clue.type === 'order') {
operatorText = clue.operator;
} else if (clue.type === 'position') {
operatorText = "=";
}
var opText = new Text2(operatorText, {
size: 120,
fill: 0xFFFFFF
});
opText.anchor.set(0.5, 1.0);
opText.x = columnX + 200 * 0.45 + 30;
opText.y = currentY;
game.addChild(opText);
clueAssetGroup.push(opText);
// Create second item
var secondItem;
var item2Scale = 0.45;
var item2ExtraY = 0;
if (clue.type === 'position') {
secondItem = clue.position.toString();
} else {
secondItem = clue.item2;
// Apply special scaling for second item too
if (secondItem && secondItem === 'Harmony') {
item2Scale = 0.55;
item2ExtraY = -10;
} else if (secondItem && secondItem === 'Khalida') {
item2ExtraY = -10;
} else if (secondItem && secondItem === 'KJ') {
item2ExtraY = 5;
}
}
// Only create second item if it exists
if (secondItem) {
var item2Asset = LK.getAsset(secondItem, {
anchorX: 0.0,
anchorY: 1.0,
x: columnX + 200 * 0.45 + 60,
y: currentY + item2ExtraY,
scaleX: item2Scale,
scaleY: item2Scale
});
game.addChild(item2Asset);
clueAssetGroup.push(item2Asset);
}
// Add strikethrough functionality
makeClueStrikeToggle(clueAssetGroup, i < 2 ? i : undefined);
// Store for later cleanup
clueAssets = clueAssets.concat(clueAssetGroup);
clueIndex++;
}
// Update global reference
allClueAssets = clueAssets;
// Re-add info button after story asset
if (infoButton && infoButton.parent) {
infoButton.parent.removeChild(infoButton);
}
// Find the story asset in the puzzle and add infoButton after it
var storyAssetIdx = -1;
for (var i = 0; i < puzzle.children.length; i++) {
var child = puzzle.children[i];
if (child && child.assetId === 'Story') {
storyAssetIdx = i;
break;
}
}
if (storyAssetIdx !== -1) {
// Insert infoButton after story asset
if (puzzle.children.length > storyAssetIdx + 1) {
puzzle.addChildAt(infoButton, storyAssetIdx + 1);
} else {
puzzle.addChild(infoButton);
}
} else {
// Fallback: add to puzzle if not found
puzzle.addChild(infoButton);
}
// Show info button again after retry
setInfoButtonVisible(true);
}
};
for (var i = 0; i < fadeOuts.length; i++) {
if (fadeOuts[i]) {
tween(fadeOuts[i], {
alpha: 0
}, {
duration: 250,
easing: tween.cubicIn,
onFinish: fadeDone
});
} else {
fadeDone();
}
}
};
}
}
});
}, 2000);
}
}
};
// Update global references that might be needed
window.puzzle = puzzle;
window.greenTick = greenTick;
window.numberImages = numberImages;
window.allClueAssets = allClueAssets;
window.infoButton = infoButton;
}
// Initialize the game with title screen
var titleScreen = new TitleScreen();
game.addChild(titleScreen);
Add more vibrant colours to picture
Make this scene more modern like in the present
A 4x5 grid in professor Layton game style. In-Game asset. 2d. High contrast. No shadows
Remove man
Saxophone in professor Layton game style. In-Game asset. 2d. High contrast. No shadows
Harp in professor Layton game style. In-Game asset. 2d. High contrast. No shadows
Drum in professor Layton game style. In-Game asset. 2d. High contrast. No shadows
Flute in professor Layton game style. In-Game asset. 2d. High contrast. No shadows
Question mark professor Layton game style. In-Game asset. 2d. High contrast. No shadows
12yo blonde girl in professor Layton game style. In-Game asset. 2d. High contrast. No shadows
Cute little10yo girl brown hair in professor Layton game style. In-Game asset. 2d. High contrast. No shadows
Cute little 7yo girl with blonde curly hair. Professor Layton game style In-Game asset. 2d. High contrast. No shadows
15 yo boy with short scruffy blonde hair professor Layton game style. In-Game asset. 2d. High contrast. No shadows
18yo girl with short brown hair professor Layton game style. In-Game asset. 2d. High contrast. No shadows
Cat in professor Layton game style. In-Game asset. 2d. High contrast. No shadows
White dog with brown patch on eyes professor Layton game style. In-Game asset. 2d. High contrast. No shadows
Turtle in professor Layton game style. In-Game asset. 2d. High contrast. No shadows
Frog in professor Layton game style. In-Game asset. 2d. High contrast. No shadows
Goldfish in professor Layton game style. In-Game asset. 2d. High contrast. No shadows
Basketball ball professor Layton game style. In-Game asset. 2d. High contrast. No shadows
Lego bricks professor Layton game style. In-Game asset. 2d. High contrast. No shadows
Video game console professor Layton game style. In-Game asset. 2d. High contrast. No shadows
Teddy bear professor Layton game style. In-Game asset. 2d. High contrast. No shadows
These dolls in professor Layton game art style
Hot chips or fries in professor Layton game style artwork. In-Game asset. 2d. High contrast. No shadows
Bowl of spaghetti in professor Layton game style artwork. In-Game asset. 2d. High contrast. No shadows
Pizza in professor Layton game style artwork. In-Game asset. 2d. High contrast. No shadows
Chocolate donut in professor Layton game style artwork. In-Game asset. 2d. High contrast. No shadows
Ice cream cone in professor Layton game style artwork. In-Game asset. 2d. High contrast. No shadows
Make her crack a small smile
The word "correct" in professor Layton game style. In-Game asset. 2d. High contrast. No shadows
The word " incorrect" in professor Layton game style. In-Game asset. 2d. High contrast. No shadows
Green tick in professor Layton gamestyle. In-Game asset. 2d. High contrast. No shadows
Button with RETRY PUZZLE on it in professor Layton game style artwork In-Game asset. 2d. High contrast. No shadows
Information symbol in professor Layton game style artwork. In-Game asset. 2d. High contrast. No shadows
Number 1 button professor Layton game style artwork. In-Game asset. 2d. High contrast. No shadows
Number 2
Number 3
Number 4
Number 5
Remove clock
Make sure J and Y is not cut off
How to play button in professor Layton game style font. In-Game asset. 2d. High contrast. No shadows
Make robe hang lower so you can't see it's feet
Make it say play new puzzle
A 16:9 title banner