User prompt
Please fix the bug: 'tween is not defined' in or related to this line: 'tween.to(self, {' Line Number: 31 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Add stars to top of screen
User prompt
Make stars flicker
User prompt
Make stars sparkle
User prompt
I can't see the stars
User prompt
Move stars to top of scene
User prompt
Make sure stars are in front of backdrop
User prompt
Increase star size
User prompt
Reduce story size so it is visible in scene
User prompt
Make the stars sparkle in the sky
User prompt
Make images high definition
User prompt
Make image hd
User prompt
Change text font to new time Roman
User prompt
Make text bold
User prompt
Make text black
User prompt
Move narrative text down 50
User prompt
Add narrative text to first scene using story asset as a backdrop
User prompt
Make graphics high definition
User prompt
Move story to bottom of scene
User prompt
Add story to first scene
User prompt
Add first scene to game
User prompt
Delete all code
Code edit (1 edits merged)
Please save this source code
User prompt
A Journey through Time
Initial prompt
Create a detailed concept and storyline for a musical adventure game titled "A Journey through Time." The game should combine engaging narrative elements with musical gameplay mechanics that enhance the player's experience as they explore different historical eras. Include the setting, main characters, key plot points, and how music integrates into gameplay, such as puzzles, battles, or exploration. Consider a progression system tied to musical achievements and how time travel influences both story and gameplay elements. # Steps 1. Define the historical time periods featured in the game and the reason the player travels through them. 2. Develop the protagonist and any key supporting characters, outlining their motivations and backgrounds. 3. Outline the main plot or quest that drives the adventure. 4. Describe how music is used in gameplay: for example, solving puzzles by playing melodies, rhythm-based challenges, or unlocking new areas by mastering musical themes. 5. Explain the progression and reward system tied to musical performance or discovery. 6. Illustrate how time travel alters game environments and impacts the story. # Output Format Present the concept in a structured format with sections for: - Title - Setting and Historical Periods - Characters - Plot Summary - Gameplay Mechanics (musical integration) - Progression and Rewards - Unique Features Related to Time Travel and Music Use clear, concise, and engaging language suitable for a game design pitch. # Examples Title: "A Journey through Time" Setting and Historical Periods: Ancient Egypt, Medieval Europe, and Futuristic Space Colonies. Characters: Protagonist is a young musician named Lyra who discovers a magical instrument enabling time travel. Supporting characters include historical figures and a mysterious antagonist seeking to alter history. Plot Summary: Lyra must collect lost musical relics across eras to restore the timeline and prevent chaos. Gameplay Mechanics: Players solve rhythm puzzles to unlock doors, participate in musical battles to defeat enemies, and compose tunes to influence characters and environments. Progression and Rewards: Unlock new instruments, abilities, and musical styles tied to each era as players advance. Unique Features: The soundtrack dynamically changes based on the era and player choices, affecting story outcomes.
/**** * 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