/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { coins: 0, currentLevel: 1, bombCount: 0, hintCount: 0, clockCount: 0, timerCount: 0, skipCount: 0, mansionCount: 0, hutCount: 0, patchCount: 0, towerCount: 0, castleCount: 0, ghostCount: 0, wizardCount: 0, catCount: 0, buildingPositions: {} }); /**** * Classes ****/ var Card = Container.expand(function (symbolType) { var self = Container.call(this); self.symbolType = symbolType; self.isFlipped = false; self.isMatched = false; self.canFlip = true; // Card back (always visible when not flipped) var cardBack = LK.getAsset('cardBack', { anchorX: 0.5, anchorY: 0.5 }); self.addChild(cardBack); // Card front (white background) var cardFront = LK.getAsset('cardFront', { anchorX: 0.5, anchorY: 0.5, alpha: 0 }); self.addChild(cardFront); // Symbol on the card var symbol = LK.getAsset('symbol' + symbolType, { anchorX: 0.5, anchorY: 0.5, alpha: 0 }); self.addChild(symbol); self.flip = function () { if (!self.canFlip || self.isMatched) { return; } LK.getSound('cardFlip').play(); self.isFlipped = !self.isFlipped; if (self.isFlipped) { // Show front and symbol tween(cardFront, { alpha: 1 }, { duration: 200 }); tween(symbol, { alpha: 1 }, { duration: 200 }); } else { // Hide front and symbol tween(cardFront, { alpha: 0 }, { duration: 200 }); tween(symbol, { alpha: 0 }, { duration: 200 }); } }; self.setMatched = function () { self.isMatched = true; self.canFlip = false; // Add a subtle scale effect for matched cards tween(self, { scaleX: 1.1, scaleY: 1.1 }, { duration: 300, easing: tween.easeOut }); }; self.down = function (x, y, obj) { if (self.canFlip && !self.isFlipped && !self.isMatched) { handleCardTap(self); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game variables // Game state variables 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 cards = []; var flippedCards = []; var moves = 0; var gameCompleted = false; var canFlipCards = true; var gameOver = false; var showMenu = true; // Level and timing variables var currentLevel = storage.currentLevel || 1; var startTime = Date.now(); var gameStartTime = Date.now(); var LEVEL_TIME_LIMIT = 120; // 2 minutes in seconds var MOVE_LIMIT = 15; // Grid configuration var GRID_COLS = 4; var GRID_ROWS = 4; var CARD_SIZE = 200; var CARD_SPACING = 20; // UI elements var movesTxt = new Text2('Moves: 0', { size: 60, fill: 0x000000, fontWeight: 'bold' }); movesTxt.anchor.set(0.5, 0); LK.gui.top.addChild(movesTxt); movesTxt.y = 100; var timerTxt = new Text2('Time: 0:00', { size: 60, fill: 0x000000, fontWeight: 'bold' }); timerTxt.anchor.set(0.5, 0); LK.gui.top.addChild(timerTxt); timerTxt.y = 180; // Initialize storage with defaults to prevent undefined access errors // Initialize coins from storage var coins = storage.coins || 0; var coinsTxt = new Text2('Coins: ' + coins, { size: 60, fill: 0xFFD700, fontWeight: 'bold' }); coinsTxt.anchor.set(0.5, 0); LK.gui.top.addChild(coinsTxt); coinsTxt.y = 260; // Initialize saved games from individual storage slots with validation var savedGames = []; for (var i = 0; i < 5; i++) { var slotData = storage['savedGame' + i] || null; // Validate slotData structure if (slotData && _typeof(slotData) === 'object' && typeof slotData.level === 'number' && typeof slotData.coins === 'number') { savedGames.push(slotData); } else { savedGames.push(null); } } if (!Array.isArray(savedGames)) { savedGames = []; } while (savedGames.length < 5) { savedGames.push(null); } var levelTxt = new Text2('Level: ' + currentLevel, { size: 60, fill: 0x000000, fontWeight: 'bold' }); levelTxt.anchor.set(0.5, 0); LK.gui.top.addChild(levelTxt); levelTxt.y = 340; // Level completion notification text var levelCompleteTxt = new Text2('LEVEL COMPLETE!', { size: 100, fill: 0x00FF00, fontWeight: 'bold' }); levelCompleteTxt.anchor.set(0.5, 0.5); levelCompleteTxt.x = 2048 / 2; levelCompleteTxt.y = 2732 / 2; levelCompleteTxt.visible = false; game.addChild(levelCompleteTxt); // Power-up UI elements var bombTxt = new Text2('Bomb: ' + (storage.bombCount || 0), { size: 40, fill: 0xFF6B6B, fontWeight: 'bold' }); bombTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(bombTxt); bombTxt.x = 120; bombTxt.y = 100; var lightbulbTxt = new Text2('Hint: ' + (storage.hintCount || 0), { size: 40, fill: 0xFFD700, fontWeight: 'bold' }); lightbulbTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(lightbulbTxt); lightbulbTxt.x = 120; lightbulbTxt.y = 160; var clockTxt = new Text2('Clock: ' + (storage.clockCount || 0), { size: 40, fill: 0x4ECDC4, fontWeight: 'bold' }); clockTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(clockTxt); clockTxt.x = 120; clockTxt.y = 220; var timerPowerTxt = new Text2('Timer: ' + (storage.timerCount || 0), { size: 40, fill: 0x96CEB4, fontWeight: 'bold' }); timerPowerTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(timerPowerTxt); timerPowerTxt.x = 120; timerPowerTxt.y = 280; var skipTxt = new Text2('Skip: ' + (storage.skipCount || 0), { size: 40, fill: 0xFF9FF3, fontWeight: 'bold' }); skipTxt.anchor.set(0, 0); LK.gui.topLeft.addChild(skipTxt); skipTxt.x = 120; skipTxt.y = 340; // Menu screen elements var menuContainer = new Container(); game.addChild(menuContainer); var titleTxt = new Text2('SPOOKY MEMORY MATCH', { size: 120, fill: 0xFF6600, fontWeight: 'bold' }); titleTxt.anchor.set(0.5, 0.5); titleTxt.x = 2048 / 2; titleTxt.y = 500; menuContainer.addChild(titleTxt); var levelInfoTxt = new Text2('Current Level: ' + currentLevel, { size: 80, fill: 0xFFD700, fontWeight: 'bold' }); levelInfoTxt.anchor.set(0.5, 0.5); levelInfoTxt.x = 2048 / 2; levelInfoTxt.y = 700; menuContainer.addChild(levelInfoTxt); var coinsInfoTxt = new Text2('Coins: ' + coins, { size: 80, fill: 0xFFD700, fontWeight: 'bold' }); coinsInfoTxt.anchor.set(0.5, 0.5); coinsInfoTxt.x = 2048 / 2; coinsInfoTxt.y = 850; menuContainer.addChild(coinsInfoTxt); var playBtn = new Text2('PLAY', { size: 100, fill: 0x4ECDC4, fontWeight: 'bold' }); playBtn.anchor.set(0.5, 0.5); playBtn.x = 2048 / 2; playBtn.y = 1050; menuContainer.addChild(playBtn); var instructionsTxt = new Text2('Match spooky pairs to advance levels!\nEarn coins to buy magical power-ups!', { size: 60, fill: 0xFF6600, fontWeight: 'bold' }); instructionsTxt.anchor.set(0.5, 0.5); instructionsTxt.x = 2048 / 2; instructionsTxt.y = 2200; menuContainer.addChild(instructionsTxt); var progressTxt = new Text2('Progress: ' + currentLevel + '/500', { size: 70, fill: 0x96CEB4, fontWeight: 'bold' }); progressTxt.anchor.set(0.5, 0.5); progressTxt.x = 2048 / 2; progressTxt.y = 2400; menuContainer.addChild(progressTxt); // Shop button for buying power-ups var shopBtn = new Text2('SHOP', { size: 100, fill: 0xFFD700, fontWeight: 'bold' }); shopBtn.anchor.set(0.5, 0.5); shopBtn.x = 2048 / 2; shopBtn.y = 1250; menuContainer.addChild(shopBtn); // Shop screen elements var shopContainer = new Container(); shopContainer.visible = false; game.addChild(shopContainer); var shopTitleTxt = new Text2('SHOP', { size: 120, fill: 0xFFD700, fontWeight: 'bold' }); shopTitleTxt.anchor.set(0.5, 0.5); shopTitleTxt.x = 2048 / 2; shopTitleTxt.y = 400; shopContainer.addChild(shopTitleTxt); var shopCoinsTxt = new Text2('Coins: ' + coins, { size: 80, fill: 0xFFD700, fontWeight: 'bold' }); shopCoinsTxt.anchor.set(0.5, 0.5); shopCoinsTxt.x = 2048 / 2; shopCoinsTxt.y = 500; shopContainer.addChild(shopCoinsTxt); // Tab buttons var powerUpTabBtn = new Text2('POWER-UPS', { size: 80, fill: 0x4ECDC4, fontWeight: 'bold' }); powerUpTabBtn.anchor.set(0.5, 0.5); powerUpTabBtn.x = 2048 / 2 - 200; powerUpTabBtn.y = 600; shopContainer.addChild(powerUpTabBtn); var buildingTabBtn = new Text2('BUILDINGS', { size: 80, fill: 0x666666, fontWeight: 'bold' }); buildingTabBtn.anchor.set(0.5, 0.5); buildingTabBtn.x = 2048 / 2 + 200; buildingTabBtn.y = 600; shopContainer.addChild(buildingTabBtn); // Power-ups tab content var powerUpTabContainer = new Container(); powerUpTabContainer.visible = true; // Start with power-ups tab visible shopContainer.addChild(powerUpTabContainer); var shopBombBtn = new Text2('BOMB - 10 Coins\n(Removes 6 random cards)', { size: 60, fill: 0xFF6B6B, fontWeight: 'bold' }); shopBombBtn.anchor.set(0.5, 0.5); shopBombBtn.x = 2048 / 2; shopBombBtn.y = 800; powerUpTabContainer.addChild(shopBombBtn); var shopHintBtn = new Text2('HINT - 15 Coins\n(Reveals a matching pair)', { size: 60, fill: 0xFFD700, fontWeight: 'bold' }); shopHintBtn.anchor.set(0.5, 0.5); shopHintBtn.x = 2048 / 2; shopHintBtn.y = 1000; powerUpTabContainer.addChild(shopHintBtn); var shopClockBtn = new Text2('CLOCK - 20 Coins\n(Adds 5 minutes)', { size: 60, fill: 0x4ECDC4, fontWeight: 'bold' }); shopClockBtn.anchor.set(0.5, 0.5); shopClockBtn.x = 2048 / 2; shopClockBtn.y = 1200; powerUpTabContainer.addChild(shopClockBtn); var shopTimerBtn = new Text2('TIMER - 5 Coins\n(Adds 1 minute)', { size: 60, fill: 0x96CEB4, fontWeight: 'bold' }); shopTimerBtn.anchor.set(0.5, 0.5); shopTimerBtn.x = 2048 / 2; shopTimerBtn.y = 1400; powerUpTabContainer.addChild(shopTimerBtn); var shopSkipBtn = new Text2('SKIP - 100 Coins\n(Skip current level)', { size: 60, fill: 0xFF9FF3, fontWeight: 'bold' }); shopSkipBtn.anchor.set(0.5, 0.5); shopSkipBtn.x = 2048 / 2; shopSkipBtn.y = 1600; powerUpTabContainer.addChild(shopSkipBtn); // Buildings tab content var buildingTabContainer = new Container(); buildingTabContainer.visible = false; shopContainer.addChild(buildingTabContainer); var hauntedMansionBtn = new Text2('HAUNTED MANSION - 50 Coins\n(Spooky decoration)', { size: 60, fill: 0x4B0082, fontWeight: 'bold' }); hauntedMansionBtn.anchor.set(0.5, 0.5); hauntedMansionBtn.x = 2048 / 2; hauntedMansionBtn.y = 800; buildingTabContainer.addChild(hauntedMansionBtn); var witchHutBtn = new Text2('WITCH HUT - 75 Coins\n(Magical dwelling)', { size: 60, fill: 0x228B22, fontWeight: 'bold' }); witchHutBtn.anchor.set(0.5, 0.5); witchHutBtn.x = 2048 / 2; witchHutBtn.y = 950; buildingTabContainer.addChild(witchHutBtn); var pumpkinPatchBtn = new Text2('PUMPKIN PATCH - 30 Coins\n(Halloween decoration)', { size: 60, fill: 0xFF8C00, fontWeight: 'bold' }); pumpkinPatchBtn.anchor.set(0.5, 0.5); pumpkinPatchBtn.x = 2048 / 2; pumpkinPatchBtn.y = 1100; buildingTabContainer.addChild(pumpkinPatchBtn); var ghostlyTowerBtn = new Text2('GHOSTLY TOWER - 100 Coins\n(Spectral building)', { size: 60, fill: 0xF5F5F5, fontWeight: 'bold' }); ghostlyTowerBtn.anchor.set(0.5, 0.5); ghostlyTowerBtn.x = 2048 / 2; ghostlyTowerBtn.y = 1250; buildingTabContainer.addChild(ghostlyTowerBtn); var vampireCastleBtn = new Text2('VAMPIRE CASTLE - 200 Coins\n(Dark fortress)', { size: 60, fill: 0x8B0000, fontWeight: 'bold' }); vampireCastleBtn.anchor.set(0.5, 0.5); vampireCastleBtn.x = 2048 / 2; vampireCastleBtn.y = 1400; buildingTabContainer.addChild(vampireCastleBtn); // NPC characters var friendlyGhostBtn = new Text2('FRIENDLY GHOST - 40 Coins\n(Helpful NPC)', { size: 60, fill: 0xD3D3D3, fontWeight: 'bold' }); friendlyGhostBtn.anchor.set(0.5, 0.5); friendlyGhostBtn.x = 2048 / 2; friendlyGhostBtn.y = 1550; buildingTabContainer.addChild(friendlyGhostBtn); var wizardBtn = new Text2('WIZARD - 60 Coins\n(Wise NPC)', { size: 60, fill: 0x191970, fontWeight: 'bold' }); wizardBtn.anchor.set(0.5, 0.5); wizardBtn.x = 2048 / 2; wizardBtn.y = 1700; buildingTabContainer.addChild(wizardBtn); var blackCatBtn = new Text2('BLACK CAT - 25 Coins\n(Mystical companion)', { size: 60, fill: 0x000000, fontWeight: 'bold' }); blackCatBtn.anchor.set(0.5, 0.5); blackCatBtn.x = 2048 / 2; blackCatBtn.y = 1850; buildingTabContainer.addChild(blackCatBtn); var shopBackBtn = new Text2('BACK TO MENU', { size: 80, fill: 0xCCCCCC, fontWeight: 'bold' }); shopBackBtn.anchor.set(0.5, 0.5); shopBackBtn.x = 2048 / 2; shopBackBtn.y = 2000; shopContainer.addChild(shopBackBtn); // Saved Games button var savedGamesBtn = new Text2('SAVED GAMES', { size: 100, fill: 0x96CEB4, fontWeight: 'bold' }); savedGamesBtn.anchor.set(0.5, 0.5); savedGamesBtn.x = 2048 / 2; savedGamesBtn.y = 1450; menuContainer.addChild(savedGamesBtn); // World button var worldBtn = new Container(); worldBtn.x = 2048 / 2; worldBtn.y = 1650; // Add background image var worldBackground = LK.getAsset('worldbackground', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2 }); worldBtn.addChild(worldBackground); // Add text on top of background var worldBtnText = new Text2('WORLD', { size: 100, fill: 0x4B0082, fontWeight: 'bold' }); worldBtnText.anchor.set(0.5, 0.5); worldBtn.addChild(worldBtnText); menuContainer.addChild(worldBtn); // Saved Games screen container var savedGamesContainer = new Container(); savedGamesContainer.visible = false; game.addChild(savedGamesContainer); var savedGamesTitleTxt = new Text2('SAVED GAMES', { size: 120, fill: 0x96CEB4, fontWeight: 'bold' }); savedGamesTitleTxt.anchor.set(0.5, 0.5); savedGamesTitleTxt.x = 2048 / 2; savedGamesTitleTxt.y = 400; savedGamesContainer.addChild(savedGamesTitleTxt); var savedGamesInstructionTxt = new Text2('Click a slot to load or save your game progress', { size: 60, fill: 0x000000, fontWeight: 'bold' }); savedGamesInstructionTxt.anchor.set(0.5, 0.5); savedGamesInstructionTxt.x = 2048 / 2; savedGamesInstructionTxt.y = 550; savedGamesContainer.addChild(savedGamesInstructionTxt); // Create 5 save game slot buttons in saved games container var saveSlots = []; for (var i = 0; i < 5; i++) { var slotData = savedGames[i]; var slotText = 'Slot ' + (i + 1); if (slotData) { slotText += ' - Level ' + slotData.level + ' (' + slotData.coins + ' coins)'; if (slotData.result) { slotText += ' - ' + slotData.result; } } else { slotText += ' - Empty'; } var slotBtn = new Text2(slotText, { size: 60, fill: slotData ? 0x4ECDC4 : 0x666666, fontWeight: 'bold' }); slotBtn.anchor.set(0.5, 0.5); slotBtn.x = 2048 / 2; slotBtn.y = 750 + i * 150; slotBtn.slotIndex = i; savedGamesContainer.addChild(slotBtn); saveSlots.push(slotBtn); } // Back to menu button for saved games var savedGamesBackBtn = new Text2('BACK TO MENU', { size: 80, fill: 0xCCCCCC, fontWeight: 'bold' }); savedGamesBackBtn.anchor.set(0.5, 0.5); savedGamesBackBtn.x = 2048 / 2; savedGamesBackBtn.y = 1500; savedGamesContainer.addChild(savedGamesBackBtn); // Create card types array based on level (4 tiles for first level + 6 tiles per additional level) var totalTiles; if (currentLevel === 1) { totalTiles = 4; // First level has exactly 4 tiles } else { totalTiles = 4 + (currentLevel - 1) * 6; // 4 base tiles + 6 per level } var pairCount = totalTiles / 2; var cardTypes = []; for (var i = 1; i <= pairCount; i++) { // Ensure symbol index stays within valid range (1-25) var symbolIndex = (i - 1) % 25 + 1; // Cycle through 25 available symbols cardTypes.push(symbolIndex); cardTypes.push(symbolIndex); // Add pair } // Shuffle function function shuffleArray(array) { for (var i = array.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = array[i]; array[i] = array[j]; array[j] = temp; } return array; } // Initialize cards function initializeCards() { var shuffledTypes = shuffleArray(cardTypes); // Calculate dynamic grid size based on total tiles var totalTiles = cardTypes.length; GRID_COLS = Math.ceil(Math.sqrt(totalTiles)); GRID_ROWS = Math.ceil(totalTiles / GRID_COLS); // Adjust card size based on grid size if (totalTiles > 16) { CARD_SIZE = Math.max(120, 200 - (totalTiles - 16) * 5); CARD_SPACING = Math.max(10, 20 - (totalTiles - 16) * 1); } // Calculate grid positioning var gridWidth = GRID_COLS * CARD_SIZE + (GRID_COLS - 1) * CARD_SPACING; var gridHeight = GRID_ROWS * CARD_SIZE + (GRID_ROWS - 1) * CARD_SPACING; var startX = (2048 - gridWidth) / 2 + CARD_SIZE / 2; var startY = (2732 - gridHeight) / 2 + CARD_SIZE / 2; for (var i = 0; i < totalTiles; i++) { var row = Math.floor(i / GRID_COLS); var col = i % GRID_COLS; var card = new Card(shuffledTypes[i]); card.x = startX + col * (CARD_SIZE + CARD_SPACING); card.y = startY + row * (CARD_SIZE + CARD_SPACING); cards.push(card); game.addChild(card); } } // Handle card tap function handleCardTap(card) { if (!canFlipCards || flippedCards.length >= 2 || gameOver) { return; } card.flip(); flippedCards.push(card); if (flippedCards.length === 2) { moves++; movesTxt.setText('Moves: ' + moves); // Check if move limit exceeded if (moves >= MOVE_LIMIT) { gameOver = true; // Save current level progress before game over storage.currentLevel = currentLevel; // Auto-save failed attempt autoSaveGame('Failed - Move Limit'); LK.setTimeout(function () { LK.showGameOver(); }, 1000); return; } canFlipCards = false; // Check for match after a short delay LK.setTimeout(function () { checkForMatch(); }, 1000); } } // Check if two flipped cards match function checkForMatch() { var card1 = flippedCards[0]; var card2 = flippedCards[1]; if (card1.symbolType === card2.symbolType) { // Match found LK.getSound('match').play(); card1.setMatched(); card2.setMatched(); // Award 5 coins for matching pair coins += 5; storage.coins = coins; coinsTxt.setText('Coins: ' + coins); // Check if game is complete var matchedCount = 0; for (var i = 0; i < cards.length; i++) { if (cards[i] && typeof cards[i].isMatched !== 'undefined' && cards[i].isMatched) { matchedCount++; } } if (matchedCount === cards.length) { gameCompleted = true; // Save current level completion storage.currentLevel = currentLevel; // Auto-save completed level autoSaveGame('Completed'); // Award bonus coins for completing level coins += 10; storage.coins = coins; coinsTxt.setText('Coins: ' + coins); // Check if we've completed all 500 levels if (currentLevel >= 500) { // Show you win when all levels are completed LK.setTimeout(function () { LK.showYouWin(); }, 1000); } else { // Advance to next level currentLevel++; storage.currentLevel = currentLevel; // Save current level to storage levelTxt.setText('Level: ' + currentLevel); // Update menu progress display levelInfoTxt.setText('Current Level: ' + currentLevel); progressTxt.setText('Progress: ' + currentLevel + '/500'); // Show level completion message LK.effects.flashScreen(0x00FF00, 1000); // Reset for next level LK.setTimeout(function () { resetLevel(); }, 1500); } } } else { // No match LK.getSound('noMatch').play(); card1.flip(); card2.flip(); } flippedCards = []; canFlipCards = true; } // Reset level for progression function resetLevel() { // Show level completion message briefly if advancing if (currentLevel > 1) { levelCompleteTxt.setText('LEVEL ' + (currentLevel - 1) + ' COMPLETE!'); levelCompleteTxt.visible = true; LK.setTimeout(function () { levelCompleteTxt.visible = false; }, 2000); } // Clear existing cards for (var i = 0; i < cards.length; i++) { if (cards[i] && typeof cards[i].destroy === 'function') { cards[i].destroy(); } } cards = []; flippedCards = []; moves = 0; gameCompleted = false; canFlipCards = true; gameOver = false; gameStartTime = Date.now(); startTime = Date.now(); // Update UI movesTxt.setText('Moves: 0'); timerTxt.setText('Time: 0:00'); // Recreate card types for new level var totalTiles; if (currentLevel === 1) { totalTiles = 4; // First level has exactly 4 tiles } else { totalTiles = 4 + (currentLevel - 1) * 6; // 4 base tiles + 6 per level } var pairCount = totalTiles / 2; cardTypes = []; for (var i = 1; i <= pairCount; i++) { // Ensure symbol index stays within valid range (1-25) var symbolIndex = (i - 1) % 25 + 1; // Cycle through 25 available symbols cardTypes.push(symbolIndex); cardTypes.push(symbolIndex); } // Initialize new cards initializeCards(); } // Format time display function formatTime(seconds) { var minutes = Math.floor(seconds / 60); var remainingSeconds = seconds % 60; return minutes + ':' + (remainingSeconds < 10 ? '0' : '') + remainingSeconds; } // Building purchase functions function buyHauntedMansion() { if (coins >= 50) { coins = Math.max(0, coins - 50); storage.coins = coins; shopCoinsTxt.setText('Coins: ' + coins); coinsInfoTxt.setText('Coins: ' + coins); var mansionCount = storage.mansionCount || 0; storage.mansionCount = mansionCount + 1; LK.effects.flashScreen(0x4B0082, 500); } } function buyWitchHut() { if (coins >= 75) { coins = Math.max(0, coins - 75); storage.coins = coins; shopCoinsTxt.setText('Coins: ' + coins); coinsInfoTxt.setText('Coins: ' + coins); var hutCount = storage.hutCount || 0; storage.hutCount = hutCount + 1; LK.effects.flashScreen(0x228B22, 500); } } function buyPumpkinPatch() { if (coins >= 30) { coins = Math.max(0, coins - 30); storage.coins = coins; shopCoinsTxt.setText('Coins: ' + coins); coinsInfoTxt.setText('Coins: ' + coins); var patchCount = storage.patchCount || 0; storage.patchCount = patchCount + 1; LK.effects.flashScreen(0xFF8C00, 500); } } function buyGhostlyTower() { if (coins >= 100) { coins = Math.max(0, coins - 100); storage.coins = coins; shopCoinsTxt.setText('Coins: ' + coins); coinsInfoTxt.setText('Coins: ' + coins); var towerCount = storage.towerCount || 0; storage.towerCount = towerCount + 1; LK.effects.flashScreen(0xF5F5F5, 500); } } function buyVampireCastle() { if (coins >= 200) { coins = Math.max(0, coins - 200); storage.coins = coins; shopCoinsTxt.setText('Coins: ' + coins); coinsInfoTxt.setText('Coins: ' + coins); var castleCount = storage.castleCount || 0; storage.castleCount = castleCount + 1; LK.effects.flashScreen(0x8B0000, 500); } } function buyFriendlyGhost() { if (coins >= 40) { coins = Math.max(0, coins - 40); storage.coins = coins; shopCoinsTxt.setText('Coins: ' + coins); coinsInfoTxt.setText('Coins: ' + coins); var ghostCount = storage.ghostCount || 0; storage.ghostCount = ghostCount + 1; LK.effects.flashScreen(0xD3D3D3, 500); } } function buyWizard() { if (coins >= 60) { coins = Math.max(0, coins - 60); storage.coins = coins; shopCoinsTxt.setText('Coins: ' + coins); coinsInfoTxt.setText('Coins: ' + coins); var wizardCount = storage.wizardCount || 0; storage.wizardCount = wizardCount + 1; LK.effects.flashScreen(0x191970, 500); } } function buyBlackCat() { if (coins >= 25) { coins = Math.max(0, coins - 25); storage.coins = coins; shopCoinsTxt.setText('Coins: ' + coins); coinsInfoTxt.setText('Coins: ' + coins); var catCount = storage.catCount || 0; storage.catCount = catCount + 1; LK.effects.flashScreen(0x000000, 500); } } // Shop power-up purchase functions function buyBomb() { if (coins >= 10) { coins = Math.max(0, coins - 10); storage.coins = coins; shopCoinsTxt.setText('Coins: ' + coins); coinsInfoTxt.setText('Coins: ' + coins); // Add bomb to inventory (stored in storage) var bombCount = storage.bombCount || 0; storage.bombCount = bombCount + 1; bombTxt.setText('Bomb: ' + (storage.bombCount || 0)); LK.effects.flashScreen(0x00FF00, 500); } } function buyHint() { if (coins >= 15) { coins = Math.max(0, coins - 15); storage.coins = coins; shopCoinsTxt.setText('Coins: ' + coins); coinsInfoTxt.setText('Coins: ' + coins); // Add hint to inventory var hintCount = storage.hintCount || 0; storage.hintCount = hintCount + 1; lightbulbTxt.setText('Hint: ' + (storage.hintCount || 0)); LK.effects.flashScreen(0x00FF00, 500); } } function buyClock() { if (coins >= 20) { coins = Math.max(0, coins - 20); storage.coins = coins; shopCoinsTxt.setText('Coins: ' + coins); coinsInfoTxt.setText('Coins: ' + coins); // Add clock to inventory var clockCount = storage.clockCount || 0; storage.clockCount = clockCount + 1; clockTxt.setText('Clock: ' + (storage.clockCount || 0)); LK.effects.flashScreen(0x00FF00, 500); } } function buyTimer() { if (coins >= 5) { coins = Math.max(0, coins - 5); storage.coins = coins; shopCoinsTxt.setText('Coins: ' + coins); coinsInfoTxt.setText('Coins: ' + coins); // Add timer to inventory var timerCount = storage.timerCount || 0; storage.timerCount = timerCount + 1; timerPowerTxt.setText('Timer: ' + (storage.timerCount || 0)); LK.effects.flashScreen(0x00FF00, 500); } } function buySkip() { if (coins >= 100) { coins = Math.max(0, coins - 100); storage.coins = coins; shopCoinsTxt.setText('Coins: ' + coins); coinsInfoTxt.setText('Coins: ' + coins); // Add skip to inventory var skipCount = storage.skipCount || 0; storage.skipCount = skipCount + 1; skipTxt.setText('Skip: ' + (storage.skipCount || 0)); LK.effects.flashScreen(0x00FF00, 500); } } // Power-up functions function useBomb() { var bombCount = storage.bombCount || 0; if (bombCount > 0) { storage.bombCount = bombCount - 1; // Update display bombTxt.setText('Bomb: ' + (storage.bombCount || 0)); // Delete 6 random non-matched cards var availableCards = []; for (var i = 0; i < cards.length; i++) { if (cards[i] && typeof cards[i].isMatched !== 'undefined' && !cards[i].isMatched) { availableCards.push(cards[i]); } } var cardsToRemove = Math.min(6, availableCards.length); for (var i = 0; i < cardsToRemove; i++) { if (availableCards.length > 0) { var randomIndex = Math.floor(Math.random() * availableCards.length); var cardToRemove = availableCards[randomIndex]; if (cardToRemove && cardToRemove.destroy) { cardToRemove.destroy(); var cardIndex = cards.indexOf(cardToRemove); if (cardIndex !== -1) { cards.splice(cardIndex, 1); } availableCards.splice(randomIndex, 1); } } } } } function useLightbulb() { var hintCount = storage.hintCount || 0; if (hintCount > 0) { storage.hintCount = hintCount - 1; // Update display lightbulbTxt.setText('Hint: ' + (storage.hintCount || 0)); // Find a matching pair that's not matched yet var unmatchedCards = []; for (var i = 0; i < cards.length; i++) { if (cards[i] && typeof cards[i].isMatched !== 'undefined' && !cards[i].isMatched) { unmatchedCards.push(cards[i]); } } // Group by symbol type var symbolGroups = {}; for (var i = 0; i < unmatchedCards.length; i++) { var card = unmatchedCards[i]; if (!symbolGroups[card.symbolType]) { symbolGroups[card.symbolType] = []; } symbolGroups[card.symbolType].push(card); } // Find first pair and show them for (var symbolType in symbolGroups) { if (symbolGroups[symbolType].length >= 2) { var pair = symbolGroups[symbolType].slice(0, 2); for (var i = 0; i < pair.length; i++) { if (!pair[i].isFlipped) { pair[i].flip(); } } break; } } } } function useClock() { var clockCount = storage.clockCount || 0; if (clockCount > 0) { storage.clockCount = clockCount - 1; // Update display clockTxt.setText('Clock: ' + (storage.clockCount || 0)); // Add 5 minutes (300 seconds) to game time gameStartTime -= 300000; // Subtract 5 minutes from start time to effectively add time } } function useTimer() { var timerCount = storage.timerCount || 0; if (timerCount > 0) { storage.timerCount = timerCount - 1; // Update display timerPowerTxt.setText('Timer: ' + (storage.timerCount || 0)); // Add 1 minute (60 seconds) to game time gameStartTime -= 60000; // Subtract 1 minute from start time to effectively add time } } function useSkip() { var skipCount = storage.skipCount || 0; if (skipCount > 0) { storage.skipCount = skipCount - 1; // Update display skipTxt.setText('Skip: ' + (storage.skipCount || 0)); // Save current level before skipping storage.currentLevel = currentLevel; // Check if we've completed all 500 levels if (currentLevel >= 500) { // Show you win when all levels are completed LK.setTimeout(function () { LK.showYouWin(); }, 1000); } else { // Advance to next level currentLevel++; storage.currentLevel = currentLevel; // Save current level to storage levelTxt.setText('Level: ' + currentLevel); // Reset for next level LK.setTimeout(function () { resetLevel(); }, 1000); } } } // Function to save current game state function saveGame(slotIndex) { // Create flattened gameData object with only literals var gameData = { level: currentLevel, coins: coins, timestamp: Date.now() }; // Ensure savedGames is initialized as an array if (!Array.isArray(savedGames)) { savedGames = []; } // Ensure we have enough slots while (savedGames.length <= slotIndex) { savedGames.push(null); } savedGames[slotIndex] = gameData; storage['savedGame' + slotIndex] = gameData; // Update the slot button text only if saveSlots exists and has the slot if (saveSlots && saveSlots[slotIndex]) { var slotBtn = saveSlots[slotIndex]; slotBtn.setText('Slot ' + (slotIndex + 1) + ' - Level ' + gameData.level + ' (' + gameData.coins + ' coins)'); slotBtn.tint = 0x4ECDC4; } } // Function to auto-save to circular buffer of latest 5 games function autoSaveGame(gameResult) { // Create flattened gameData object with only literals var gameData = { level: currentLevel, coins: coins, timestamp: Date.now(), result: gameResult }; // Ensure savedGames is initialized as an array if (!Array.isArray(savedGames)) { savedGames = []; } // Create a new array to avoid reference issues var newSavedGames = []; // Add new game to the beginning newSavedGames.push(gameData); // Add existing games (up to 4 more) for (var i = 0; i < Math.min(4, savedGames.length); i++) { if (savedGames[i]) { newSavedGames.push(savedGames[i]); } } savedGames = newSavedGames; // Keep only the latest 5 games if (savedGames.length > 5) { savedGames = savedGames.slice(0, 5); } // Save each slot individually to storage with only literals for (var i = 0; i < 5; i++) { if (i < savedGames.length && savedGames[i]) { storage['savedGame' + i] = { level: savedGames[i].level, coins: savedGames[i].coins, timestamp: savedGames[i].timestamp, result: savedGames[i].result || '' }; } else { storage['savedGame' + i] = null; } } // Update all slot buttons if they exist if (saveSlots) { for (var i = 0; i < 5; i++) { if (saveSlots[i]) { var slotData = savedGames[i]; var slotText = 'Slot ' + (i + 1); if (slotData) { slotText += ' - Level ' + slotData.level + ' (' + slotData.coins + ' coins)'; if (slotData.result) { slotText += ' - ' + slotData.result; } } else { slotText += ' - Empty'; } saveSlots[i].setText(slotText); saveSlots[i].tint = slotData ? 0x4ECDC4 : 0x666666; } } } } // Function to load saved game function loadGame(slotIndex) { if (slotIndex >= 0 && slotIndex < savedGames.length && savedGames[slotIndex]) { var gameData = savedGames[slotIndex]; if (gameData && typeof gameData.level === 'number' && typeof gameData.coins === 'number') { currentLevel = Math.max(1, Math.min(500, gameData.level)); coins = Math.max(0, gameData.coins); storage.currentLevel = currentLevel; storage.coins = coins; // Update UI levelInfoTxt.setText('Current Level: ' + currentLevel); coinsInfoTxt.setText('Coins: ' + coins); progressTxt.setText('Progress: ' + currentLevel + '/500'); } } } // Function to update power-up inventory display function updatePowerUpDisplay() { bombTxt.setText('Bomb: ' + (storage.bombCount || 0)); lightbulbTxt.setText('Hint: ' + (storage.hintCount || 0)); clockTxt.setText('Clock: ' + (storage.clockCount || 0)); timerPowerTxt.setText('Timer: ' + (storage.timerCount || 0)); skipTxt.setText('Skip: ' + (storage.skipCount || 0)); } // Function to start the game function startGame() { showMenu = false; menuContainer.visible = false; // Show game UI elements movesTxt.visible = true; timerTxt.visible = true; coinsTxt.visible = true; levelTxt.visible = true; bombTxt.visible = true; lightbulbTxt.visible = true; clockTxt.visible = true; timerPowerTxt.visible = true; skipTxt.visible = true; playBackBtn.visible = true; // Update power-up display updatePowerUpDisplay(); // Initialize game initializeCards(); gameStartTime = Date.now(); startTime = Date.now(); } // Add click handlers for power-ups bombTxt.down = function (x, y, obj) { useBomb(); }; lightbulbTxt.down = function (x, y, obj) { useLightbulb(); }; clockTxt.down = function (x, y, obj) { useClock(); }; timerPowerTxt.down = function (x, y, obj) { useTimer(); }; skipTxt.down = function (x, y, obj) { useSkip(); }; // Saved Games button click handler savedGamesBtn.down = function (x, y, obj) { menuContainer.visible = false; savedGamesContainer.visible = true; // Update saved games display for (var i = 0; i < saveSlots.length; i++) { var slotData = savedGames[i]; var slotText = 'Slot ' + (i + 1); if (slotData) { slotText += ' - Level ' + slotData.level + ' (' + slotData.coins + ' coins)'; if (slotData.result) { slotText += ' - ' + slotData.result; } } else { slotText += ' - Empty'; } saveSlots[i].setText(slotText); saveSlots[i].tint = slotData ? 0x4ECDC4 : 0x666666; } }; // World screen container var worldContainer = new Container(); worldContainer.visible = false; // Add worldbackground as background var worldContainerBackground = LK.getAsset('worldbackground', { anchorX: 0.5, anchorY: 0.5, scaleX: 20, scaleY: 27 }); worldContainerBackground.x = 2048 / 2; worldContainerBackground.y = 2732 / 2; worldContainer.addChild(worldContainerBackground); game.addChild(worldContainer); var worldTitleTxt = new Text2('YOUR SPOOKY WORLD', { size: 120, fill: 0x4B0082, fontWeight: 'bold' }); worldTitleTxt.anchor.set(0.5, 0.5); worldTitleTxt.x = 2048 / 2; worldTitleTxt.y = 400; worldContainer.addChild(worldTitleTxt); var worldInstructionTxt = new Text2('Drag buildings to place them in your world', { size: 60, fill: 0x000000, fontWeight: 'bold' }); worldInstructionTxt.anchor.set(0.5, 0.5); worldInstructionTxt.x = 2048 / 2; worldInstructionTxt.y = 500; worldContainer.addChild(worldInstructionTxt); // World back button var worldBackBtn = new Text2('BACK TO MENU', { size: 80, fill: 0xCCCCCC, fontWeight: 'bold' }); worldBackBtn.anchor.set(0.5, 0.5); worldBackBtn.x = 2048 / 2; worldBackBtn.y = 2400; worldContainer.addChild(worldBackBtn); // Array to store placed buildings var placedBuildings = []; // World button click handler worldBtn.down = function (x, y, obj) { menuContainer.visible = false; worldContainer.visible = true; createWorldBuildings(); }; // World back button handler worldBackBtn.down = function (x, y, obj) { worldContainer.visible = false; menuContainer.visible = true; saveWorldState(); }; // Function to create world buildings based on purchased items function createWorldBuildings() { // Clear existing buildings for (var i = 0; i < placedBuildings.length; i++) { placedBuildings[i].destroy(); } placedBuildings = []; // Load saved positions from flattened storage structure var savedPositions = {}; for (var i = 0; i < placedBuildings.length; i++) { var building = placedBuildings[i]; var x = storage['buildingPos_' + building.buildingId + '_x']; var y = storage['buildingPos_' + building.buildingId + '_y']; if (x !== undefined && y !== undefined) { savedPositions[building.buildingId] = { x: x, y: y }; } } var buildingY = 700; var buildingX = 150; var buildingSpacing = 300; // Create buildings based on purchased counts var mansionCount = storage.mansionCount || 0; for (var i = 0; i < mansionCount; i++) { var mansion = createBuilding('Haunted Mansion', 0x4B0082, buildingX, buildingY, 'mansion_' + i); placedBuildings.push(mansion); worldContainer.addChild(mansion); buildingX += buildingSpacing; if (buildingX > 1800) { buildingX = 150; buildingY += 250; } } var hutCount = storage.hutCount || 0; for (var i = 0; i < hutCount; i++) { var hut = createBuilding('Witch Hut', 0x228B22, buildingX, buildingY, 'hut_' + i); placedBuildings.push(hut); worldContainer.addChild(hut); buildingX += buildingSpacing; if (buildingX > 1800) { buildingX = 150; buildingY += 250; } } var patchCount = storage.patchCount || 0; for (var i = 0; i < patchCount; i++) { var patch = createBuilding('Pumpkin Patch', 0xFF8C00, buildingX, buildingY, 'patch_' + i); placedBuildings.push(patch); worldContainer.addChild(patch); buildingX += buildingSpacing; if (buildingX > 1800) { buildingX = 150; buildingY += 250; } } var towerCount = storage.towerCount || 0; for (var i = 0; i < towerCount; i++) { var tower = createBuilding('Ghostly Tower', 0xF5F5F5, buildingX, buildingY, 'tower_' + i); placedBuildings.push(tower); worldContainer.addChild(tower); buildingX += buildingSpacing; if (buildingX > 1800) { buildingX = 150; buildingY += 250; } } var castleCount = storage.castleCount || 0; for (var i = 0; i < castleCount; i++) { var castle = createBuilding('Vampire Castle', 0x8B0000, buildingX, buildingY, 'castle_' + i); placedBuildings.push(castle); worldContainer.addChild(castle); buildingX += buildingSpacing; if (buildingX > 1800) { buildingX = 150; buildingY += 250; } } var ghostCount = storage.ghostCount || 0; for (var i = 0; i < ghostCount; i++) { var ghost = createBuilding('Friendly Ghost', 0xD3D3D3, buildingX, buildingY, 'ghost_' + i); placedBuildings.push(ghost); worldContainer.addChild(ghost); buildingX += buildingSpacing; if (buildingX > 1800) { buildingX = 150; buildingY += 250; } } var wizardCount = storage.wizardCount || 0; for (var i = 0; i < wizardCount; i++) { var wizard = createBuilding('Wizard', 0x191970, buildingX, buildingY, 'wizard_' + i); placedBuildings.push(wizard); worldContainer.addChild(wizard); buildingX += buildingSpacing; if (buildingX > 1800) { buildingX = 150; buildingY += 250; } } var catCount = storage.catCount || 0; for (var i = 0; i < catCount; i++) { var cat = createBuilding('Black Cat', 0x000000, buildingX, buildingY, 'cat_' + i); placedBuildings.push(cat); worldContainer.addChild(cat); buildingX += buildingSpacing; if (buildingX > 1800) { buildingX = 150; buildingY += 250; } } // Apply saved positions for (var i = 0; i < placedBuildings.length; i++) { var building = placedBuildings[i]; if (savedPositions[building.buildingId]) { building.x = savedPositions[building.buildingId].x; building.y = savedPositions[building.buildingId].y; } } } // Function to create a draggable building function createBuilding(name, color, x, y, buildingId) { var building = new Container(); building.buildingId = buildingId; // Create building visual - use appropriate asset based on building type var assetName = 'hauntedMansion'; // default fallback if (name === 'Haunted Mansion') assetName = 'hauntedMansion';else if (name === 'Witch Hut') assetName = 'witchHut';else if (name === 'Pumpkin Patch') assetName = 'pumpkinPatch';else if (name === 'Ghostly Tower') assetName = 'ghostlyTower';else if (name === 'Vampire Castle') assetName = 'vampireCastle';else if (name === 'Friendly Ghost') assetName = 'friendlyGhost';else if (name === 'Wizard') assetName = 'wizard';else if (name === 'Black Cat') assetName = 'blackCat'; var buildingShape = LK.getAsset(assetName, { anchorX: 0.5, anchorY: 0.5 }); building.addChild(buildingShape); // Create building label var buildingLabel = new Text2(name, { size: 30, fill: 0x000000, fontWeight: 'bold' }); buildingLabel.anchor.set(0.5, 0.5); buildingLabel.y = 100; building.addChild(buildingLabel); building.x = x; building.y = y; // Make building draggable building.isDragging = false; building.down = function (x, y, obj) { if (building && typeof building.x !== 'undefined' && typeof building.y !== 'undefined') { building.isDragging = true; // Convert coordinates to local space for proper offset calculation var localPos = worldContainer.toLocal({ x: x, y: y }); building.dragOffsetX = localPos.x - building.x; building.dragOffsetY = localPos.y - building.y; } }; building.up = function (x, y, obj) { building.isDragging = false; }; return building; } // Function to save world state function saveWorldState() { var positions = {}; for (var i = 0; i < placedBuildings.length; i++) { var building = placedBuildings[i]; positions[building.buildingId] = { x: building.x, y: building.y }; } // Store positions as individual key-value pairs to avoid object nesting issues for (var buildingId in positions) { storage['buildingPos_' + buildingId + '_x'] = positions[buildingId].x; storage['buildingPos_' + buildingId + '_y'] = positions[buildingId].y; } } // Handle building dragging var draggedBuilding = null; // World container mouse handlers worldContainer.move = function (x, y, obj) { for (var i = 0; i < placedBuildings.length; i++) { var building = placedBuildings[i]; if (building && building.isDragging) { // Convert coordinates to world container local space var localPos = worldContainer.toLocal({ x: x, y: y }); // Keep buildings within world bounds var newX = Math.max(100, Math.min(1948, localPos.x - (building.dragOffsetX || 0))); var newY = Math.max(600, Math.min(2300, localPos.y - (building.dragOffsetY || 0))); building.x = newX; building.y = newY; break; } } }; worldContainer.up = function (x, y, obj) { for (var i = 0; i < placedBuildings.length; i++) { var building = placedBuildings[i]; if (building.isDragging) { building.isDragging = false; break; } } }; // Saved Games back button click handler savedGamesBackBtn.down = function (x, y, obj) { savedGamesContainer.visible = false; menuContainer.visible = true; }; // Save game slot click handlers for (var i = 0; i < saveSlots.length; i++) { saveSlots[i].down = function (x, y, obj) { var slotIndex = obj.slotIndex; var gameData = savedGames[slotIndex]; if (gameData) { // Load existing save and go back to menu loadGame(slotIndex); savedGamesContainer.visible = false; menuContainer.visible = true; } else { // Save current game to empty slot saveGame(slotIndex); } }; } // Shop button click handler shopBtn.down = function (x, y, obj) { menuContainer.visible = false; shopContainer.visible = true; shopCoinsTxt.setText('Coins: ' + coins); }; // Tab switching handlers powerUpTabBtn.down = function (x, y, obj) { powerUpTabContainer.visible = true; buildingTabContainer.visible = false; powerUpTabBtn.fill = 0x4ECDC4; buildingTabBtn.fill = 0x666666; }; buildingTabBtn.down = function (x, y, obj) { powerUpTabContainer.visible = false; buildingTabContainer.visible = true; powerUpTabBtn.fill = 0x666666; buildingTabBtn.fill = 0x8B4513; }; // Building purchase handlers hauntedMansionBtn.down = function (x, y, obj) { buyHauntedMansion(); }; witchHutBtn.down = function (x, y, obj) { buyWitchHut(); }; pumpkinPatchBtn.down = function (x, y, obj) { buyPumpkinPatch(); }; ghostlyTowerBtn.down = function (x, y, obj) { buyGhostlyTower(); }; vampireCastleBtn.down = function (x, y, obj) { buyVampireCastle(); }; friendlyGhostBtn.down = function (x, y, obj) { buyFriendlyGhost(); }; wizardBtn.down = function (x, y, obj) { buyWizard(); }; blackCatBtn.down = function (x, y, obj) { buyBlackCat(); }; // Shop power-up purchase handlers shopBombBtn.down = function (x, y, obj) { buyBomb(); }; shopHintBtn.down = function (x, y, obj) { buyHint(); }; shopClockBtn.down = function (x, y, obj) { buyClock(); }; shopTimerBtn.down = function (x, y, obj) { buyTimer(); }; shopSkipBtn.down = function (x, y, obj) { buySkip(); }; // Back to menu button handler shopBackBtn.down = function (x, y, obj) { shopContainer.visible = false; menuContainer.visible = true; coinsInfoTxt.setText('Coins: ' + coins); }; // Create back button for play function var playBackBtn = new Text2('BACK TO MENU', { size: 60, fill: 0xCCCCCC, fontWeight: 'bold' }); playBackBtn.anchor.set(0.5, 0); LK.gui.topRight.addChild(playBackBtn); playBackBtn.x = -100; playBackBtn.y = 100; playBackBtn.visible = false; // Back button click handler for play function playBackBtn.down = function (x, y, obj) { // Return to menu showMenu = true; menuContainer.visible = true; // Hide game UI elements movesTxt.visible = false; timerTxt.visible = false; coinsTxt.visible = false; levelTxt.visible = false; bombTxt.visible = false; lightbulbTxt.visible = false; clockTxt.visible = false; timerPowerTxt.visible = false; skipTxt.visible = false; playBackBtn.visible = false; // Clear existing cards for (var i = 0; i < cards.length; i++) { cards[i].destroy(); } cards = []; flippedCards = []; // Reset game state variables moves = 0; gameCompleted = false; canFlipCards = true; gameOver = false; // Hide level complete text if visible levelCompleteTxt.visible = false; // Update menu display with current values levelInfoTxt.setText('Current Level: ' + currentLevel); coinsInfoTxt.setText('Coins: ' + coins); progressTxt.setText('Progress: ' + currentLevel + '/500'); }; // Play button click handler playBtn.down = function (x, y, obj) { // Always start from level 1 when play button is pressed currentLevel = 1; storage.currentLevel = currentLevel; // Reset coin count when play button is pressed coins = 0; storage.coins = coins; coinsTxt.setText('Coins: ' + coins); coinsInfoTxt.setText('Coins: ' + coins); levelTxt.setText('Level: ' + currentLevel); levelInfoTxt.setText('Current Level: ' + currentLevel); progressTxt.setText('Progress: ' + currentLevel + '/500'); // Reset game state variables for fresh start moves = 0; gameCompleted = false; canFlipCards = true; gameOver = false; flippedCards = []; // Clear existing cards if any for (var i = 0; i < cards.length; i++) { cards[i].destroy(); } cards = []; startGame(); }; // Hide game UI elements initially (show only in game) movesTxt.visible = false; timerTxt.visible = false; coinsTxt.visible = false; levelTxt.visible = false; bombTxt.visible = false; lightbulbTxt.visible = false; clockTxt.visible = false; timerPowerTxt.visible = false; skipTxt.visible = false; // Don't initialize cards immediately - wait for menu // initializeCards(); // This will be called when starting the game // Main game update loop game.update = function () { // Only update game logic if not in menu if (!showMenu) { // Update timer if (!gameCompleted && !gameOver) { var elapsedTime = Math.floor((Date.now() - gameStartTime) / 1000); var remainingTime = Math.max(0, LEVEL_TIME_LIMIT - elapsedTime); timerTxt.setText('Time: ' + formatTime(remainingTime)); // Check if time is up if (remainingTime <= 0) { gameOver = true; // Save current level progress before game over storage.currentLevel = currentLevel; // Auto-save failed attempt autoSaveGame('Failed - Time Limit'); LK.showGameOver(); } } } }; // Start background music LK.playMusic('bgmusic');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
coins: 0,
currentLevel: 1,
bombCount: 0,
hintCount: 0,
clockCount: 0,
timerCount: 0,
skipCount: 0,
mansionCount: 0,
hutCount: 0,
patchCount: 0,
towerCount: 0,
castleCount: 0,
ghostCount: 0,
wizardCount: 0,
catCount: 0,
buildingPositions: {}
});
/****
* Classes
****/
var Card = Container.expand(function (symbolType) {
var self = Container.call(this);
self.symbolType = symbolType;
self.isFlipped = false;
self.isMatched = false;
self.canFlip = true;
// Card back (always visible when not flipped)
var cardBack = LK.getAsset('cardBack', {
anchorX: 0.5,
anchorY: 0.5
});
self.addChild(cardBack);
// Card front (white background)
var cardFront = LK.getAsset('cardFront', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.addChild(cardFront);
// Symbol on the card
var symbol = LK.getAsset('symbol' + symbolType, {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.addChild(symbol);
self.flip = function () {
if (!self.canFlip || self.isMatched) {
return;
}
LK.getSound('cardFlip').play();
self.isFlipped = !self.isFlipped;
if (self.isFlipped) {
// Show front and symbol
tween(cardFront, {
alpha: 1
}, {
duration: 200
});
tween(symbol, {
alpha: 1
}, {
duration: 200
});
} else {
// Hide front and symbol
tween(cardFront, {
alpha: 0
}, {
duration: 200
});
tween(symbol, {
alpha: 0
}, {
duration: 200
});
}
};
self.setMatched = function () {
self.isMatched = true;
self.canFlip = false;
// Add a subtle scale effect for matched cards
tween(self, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 300,
easing: tween.easeOut
});
};
self.down = function (x, y, obj) {
if (self.canFlip && !self.isFlipped && !self.isMatched) {
handleCardTap(self);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game variables
// Game state variables
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 cards = [];
var flippedCards = [];
var moves = 0;
var gameCompleted = false;
var canFlipCards = true;
var gameOver = false;
var showMenu = true;
// Level and timing variables
var currentLevel = storage.currentLevel || 1;
var startTime = Date.now();
var gameStartTime = Date.now();
var LEVEL_TIME_LIMIT = 120; // 2 minutes in seconds
var MOVE_LIMIT = 15;
// Grid configuration
var GRID_COLS = 4;
var GRID_ROWS = 4;
var CARD_SIZE = 200;
var CARD_SPACING = 20;
// UI elements
var movesTxt = new Text2('Moves: 0', {
size: 60,
fill: 0x000000,
fontWeight: 'bold'
});
movesTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(movesTxt);
movesTxt.y = 100;
var timerTxt = new Text2('Time: 0:00', {
size: 60,
fill: 0x000000,
fontWeight: 'bold'
});
timerTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timerTxt);
timerTxt.y = 180;
// Initialize storage with defaults to prevent undefined access errors
// Initialize coins from storage
var coins = storage.coins || 0;
var coinsTxt = new Text2('Coins: ' + coins, {
size: 60,
fill: 0xFFD700,
fontWeight: 'bold'
});
coinsTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(coinsTxt);
coinsTxt.y = 260;
// Initialize saved games from individual storage slots with validation
var savedGames = [];
for (var i = 0; i < 5; i++) {
var slotData = storage['savedGame' + i] || null;
// Validate slotData structure
if (slotData && _typeof(slotData) === 'object' && typeof slotData.level === 'number' && typeof slotData.coins === 'number') {
savedGames.push(slotData);
} else {
savedGames.push(null);
}
}
if (!Array.isArray(savedGames)) {
savedGames = [];
}
while (savedGames.length < 5) {
savedGames.push(null);
}
var levelTxt = new Text2('Level: ' + currentLevel, {
size: 60,
fill: 0x000000,
fontWeight: 'bold'
});
levelTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(levelTxt);
levelTxt.y = 340;
// Level completion notification text
var levelCompleteTxt = new Text2('LEVEL COMPLETE!', {
size: 100,
fill: 0x00FF00,
fontWeight: 'bold'
});
levelCompleteTxt.anchor.set(0.5, 0.5);
levelCompleteTxt.x = 2048 / 2;
levelCompleteTxt.y = 2732 / 2;
levelCompleteTxt.visible = false;
game.addChild(levelCompleteTxt);
// Power-up UI elements
var bombTxt = new Text2('Bomb: ' + (storage.bombCount || 0), {
size: 40,
fill: 0xFF6B6B,
fontWeight: 'bold'
});
bombTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(bombTxt);
bombTxt.x = 120;
bombTxt.y = 100;
var lightbulbTxt = new Text2('Hint: ' + (storage.hintCount || 0), {
size: 40,
fill: 0xFFD700,
fontWeight: 'bold'
});
lightbulbTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(lightbulbTxt);
lightbulbTxt.x = 120;
lightbulbTxt.y = 160;
var clockTxt = new Text2('Clock: ' + (storage.clockCount || 0), {
size: 40,
fill: 0x4ECDC4,
fontWeight: 'bold'
});
clockTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(clockTxt);
clockTxt.x = 120;
clockTxt.y = 220;
var timerPowerTxt = new Text2('Timer: ' + (storage.timerCount || 0), {
size: 40,
fill: 0x96CEB4,
fontWeight: 'bold'
});
timerPowerTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(timerPowerTxt);
timerPowerTxt.x = 120;
timerPowerTxt.y = 280;
var skipTxt = new Text2('Skip: ' + (storage.skipCount || 0), {
size: 40,
fill: 0xFF9FF3,
fontWeight: 'bold'
});
skipTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(skipTxt);
skipTxt.x = 120;
skipTxt.y = 340;
// Menu screen elements
var menuContainer = new Container();
game.addChild(menuContainer);
var titleTxt = new Text2('SPOOKY MEMORY MATCH', {
size: 120,
fill: 0xFF6600,
fontWeight: 'bold'
});
titleTxt.anchor.set(0.5, 0.5);
titleTxt.x = 2048 / 2;
titleTxt.y = 500;
menuContainer.addChild(titleTxt);
var levelInfoTxt = new Text2('Current Level: ' + currentLevel, {
size: 80,
fill: 0xFFD700,
fontWeight: 'bold'
});
levelInfoTxt.anchor.set(0.5, 0.5);
levelInfoTxt.x = 2048 / 2;
levelInfoTxt.y = 700;
menuContainer.addChild(levelInfoTxt);
var coinsInfoTxt = new Text2('Coins: ' + coins, {
size: 80,
fill: 0xFFD700,
fontWeight: 'bold'
});
coinsInfoTxt.anchor.set(0.5, 0.5);
coinsInfoTxt.x = 2048 / 2;
coinsInfoTxt.y = 850;
menuContainer.addChild(coinsInfoTxt);
var playBtn = new Text2('PLAY', {
size: 100,
fill: 0x4ECDC4,
fontWeight: 'bold'
});
playBtn.anchor.set(0.5, 0.5);
playBtn.x = 2048 / 2;
playBtn.y = 1050;
menuContainer.addChild(playBtn);
var instructionsTxt = new Text2('Match spooky pairs to advance levels!\nEarn coins to buy magical power-ups!', {
size: 60,
fill: 0xFF6600,
fontWeight: 'bold'
});
instructionsTxt.anchor.set(0.5, 0.5);
instructionsTxt.x = 2048 / 2;
instructionsTxt.y = 2200;
menuContainer.addChild(instructionsTxt);
var progressTxt = new Text2('Progress: ' + currentLevel + '/500', {
size: 70,
fill: 0x96CEB4,
fontWeight: 'bold'
});
progressTxt.anchor.set(0.5, 0.5);
progressTxt.x = 2048 / 2;
progressTxt.y = 2400;
menuContainer.addChild(progressTxt);
// Shop button for buying power-ups
var shopBtn = new Text2('SHOP', {
size: 100,
fill: 0xFFD700,
fontWeight: 'bold'
});
shopBtn.anchor.set(0.5, 0.5);
shopBtn.x = 2048 / 2;
shopBtn.y = 1250;
menuContainer.addChild(shopBtn);
// Shop screen elements
var shopContainer = new Container();
shopContainer.visible = false;
game.addChild(shopContainer);
var shopTitleTxt = new Text2('SHOP', {
size: 120,
fill: 0xFFD700,
fontWeight: 'bold'
});
shopTitleTxt.anchor.set(0.5, 0.5);
shopTitleTxt.x = 2048 / 2;
shopTitleTxt.y = 400;
shopContainer.addChild(shopTitleTxt);
var shopCoinsTxt = new Text2('Coins: ' + coins, {
size: 80,
fill: 0xFFD700,
fontWeight: 'bold'
});
shopCoinsTxt.anchor.set(0.5, 0.5);
shopCoinsTxt.x = 2048 / 2;
shopCoinsTxt.y = 500;
shopContainer.addChild(shopCoinsTxt);
// Tab buttons
var powerUpTabBtn = new Text2('POWER-UPS', {
size: 80,
fill: 0x4ECDC4,
fontWeight: 'bold'
});
powerUpTabBtn.anchor.set(0.5, 0.5);
powerUpTabBtn.x = 2048 / 2 - 200;
powerUpTabBtn.y = 600;
shopContainer.addChild(powerUpTabBtn);
var buildingTabBtn = new Text2('BUILDINGS', {
size: 80,
fill: 0x666666,
fontWeight: 'bold'
});
buildingTabBtn.anchor.set(0.5, 0.5);
buildingTabBtn.x = 2048 / 2 + 200;
buildingTabBtn.y = 600;
shopContainer.addChild(buildingTabBtn);
// Power-ups tab content
var powerUpTabContainer = new Container();
powerUpTabContainer.visible = true; // Start with power-ups tab visible
shopContainer.addChild(powerUpTabContainer);
var shopBombBtn = new Text2('BOMB - 10 Coins\n(Removes 6 random cards)', {
size: 60,
fill: 0xFF6B6B,
fontWeight: 'bold'
});
shopBombBtn.anchor.set(0.5, 0.5);
shopBombBtn.x = 2048 / 2;
shopBombBtn.y = 800;
powerUpTabContainer.addChild(shopBombBtn);
var shopHintBtn = new Text2('HINT - 15 Coins\n(Reveals a matching pair)', {
size: 60,
fill: 0xFFD700,
fontWeight: 'bold'
});
shopHintBtn.anchor.set(0.5, 0.5);
shopHintBtn.x = 2048 / 2;
shopHintBtn.y = 1000;
powerUpTabContainer.addChild(shopHintBtn);
var shopClockBtn = new Text2('CLOCK - 20 Coins\n(Adds 5 minutes)', {
size: 60,
fill: 0x4ECDC4,
fontWeight: 'bold'
});
shopClockBtn.anchor.set(0.5, 0.5);
shopClockBtn.x = 2048 / 2;
shopClockBtn.y = 1200;
powerUpTabContainer.addChild(shopClockBtn);
var shopTimerBtn = new Text2('TIMER - 5 Coins\n(Adds 1 minute)', {
size: 60,
fill: 0x96CEB4,
fontWeight: 'bold'
});
shopTimerBtn.anchor.set(0.5, 0.5);
shopTimerBtn.x = 2048 / 2;
shopTimerBtn.y = 1400;
powerUpTabContainer.addChild(shopTimerBtn);
var shopSkipBtn = new Text2('SKIP - 100 Coins\n(Skip current level)', {
size: 60,
fill: 0xFF9FF3,
fontWeight: 'bold'
});
shopSkipBtn.anchor.set(0.5, 0.5);
shopSkipBtn.x = 2048 / 2;
shopSkipBtn.y = 1600;
powerUpTabContainer.addChild(shopSkipBtn);
// Buildings tab content
var buildingTabContainer = new Container();
buildingTabContainer.visible = false;
shopContainer.addChild(buildingTabContainer);
var hauntedMansionBtn = new Text2('HAUNTED MANSION - 50 Coins\n(Spooky decoration)', {
size: 60,
fill: 0x4B0082,
fontWeight: 'bold'
});
hauntedMansionBtn.anchor.set(0.5, 0.5);
hauntedMansionBtn.x = 2048 / 2;
hauntedMansionBtn.y = 800;
buildingTabContainer.addChild(hauntedMansionBtn);
var witchHutBtn = new Text2('WITCH HUT - 75 Coins\n(Magical dwelling)', {
size: 60,
fill: 0x228B22,
fontWeight: 'bold'
});
witchHutBtn.anchor.set(0.5, 0.5);
witchHutBtn.x = 2048 / 2;
witchHutBtn.y = 950;
buildingTabContainer.addChild(witchHutBtn);
var pumpkinPatchBtn = new Text2('PUMPKIN PATCH - 30 Coins\n(Halloween decoration)', {
size: 60,
fill: 0xFF8C00,
fontWeight: 'bold'
});
pumpkinPatchBtn.anchor.set(0.5, 0.5);
pumpkinPatchBtn.x = 2048 / 2;
pumpkinPatchBtn.y = 1100;
buildingTabContainer.addChild(pumpkinPatchBtn);
var ghostlyTowerBtn = new Text2('GHOSTLY TOWER - 100 Coins\n(Spectral building)', {
size: 60,
fill: 0xF5F5F5,
fontWeight: 'bold'
});
ghostlyTowerBtn.anchor.set(0.5, 0.5);
ghostlyTowerBtn.x = 2048 / 2;
ghostlyTowerBtn.y = 1250;
buildingTabContainer.addChild(ghostlyTowerBtn);
var vampireCastleBtn = new Text2('VAMPIRE CASTLE - 200 Coins\n(Dark fortress)', {
size: 60,
fill: 0x8B0000,
fontWeight: 'bold'
});
vampireCastleBtn.anchor.set(0.5, 0.5);
vampireCastleBtn.x = 2048 / 2;
vampireCastleBtn.y = 1400;
buildingTabContainer.addChild(vampireCastleBtn);
// NPC characters
var friendlyGhostBtn = new Text2('FRIENDLY GHOST - 40 Coins\n(Helpful NPC)', {
size: 60,
fill: 0xD3D3D3,
fontWeight: 'bold'
});
friendlyGhostBtn.anchor.set(0.5, 0.5);
friendlyGhostBtn.x = 2048 / 2;
friendlyGhostBtn.y = 1550;
buildingTabContainer.addChild(friendlyGhostBtn);
var wizardBtn = new Text2('WIZARD - 60 Coins\n(Wise NPC)', {
size: 60,
fill: 0x191970,
fontWeight: 'bold'
});
wizardBtn.anchor.set(0.5, 0.5);
wizardBtn.x = 2048 / 2;
wizardBtn.y = 1700;
buildingTabContainer.addChild(wizardBtn);
var blackCatBtn = new Text2('BLACK CAT - 25 Coins\n(Mystical companion)', {
size: 60,
fill: 0x000000,
fontWeight: 'bold'
});
blackCatBtn.anchor.set(0.5, 0.5);
blackCatBtn.x = 2048 / 2;
blackCatBtn.y = 1850;
buildingTabContainer.addChild(blackCatBtn);
var shopBackBtn = new Text2('BACK TO MENU', {
size: 80,
fill: 0xCCCCCC,
fontWeight: 'bold'
});
shopBackBtn.anchor.set(0.5, 0.5);
shopBackBtn.x = 2048 / 2;
shopBackBtn.y = 2000;
shopContainer.addChild(shopBackBtn);
// Saved Games button
var savedGamesBtn = new Text2('SAVED GAMES', {
size: 100,
fill: 0x96CEB4,
fontWeight: 'bold'
});
savedGamesBtn.anchor.set(0.5, 0.5);
savedGamesBtn.x = 2048 / 2;
savedGamesBtn.y = 1450;
menuContainer.addChild(savedGamesBtn);
// World button
var worldBtn = new Container();
worldBtn.x = 2048 / 2;
worldBtn.y = 1650;
// Add background image
var worldBackground = LK.getAsset('worldbackground', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
worldBtn.addChild(worldBackground);
// Add text on top of background
var worldBtnText = new Text2('WORLD', {
size: 100,
fill: 0x4B0082,
fontWeight: 'bold'
});
worldBtnText.anchor.set(0.5, 0.5);
worldBtn.addChild(worldBtnText);
menuContainer.addChild(worldBtn);
// Saved Games screen container
var savedGamesContainer = new Container();
savedGamesContainer.visible = false;
game.addChild(savedGamesContainer);
var savedGamesTitleTxt = new Text2('SAVED GAMES', {
size: 120,
fill: 0x96CEB4,
fontWeight: 'bold'
});
savedGamesTitleTxt.anchor.set(0.5, 0.5);
savedGamesTitleTxt.x = 2048 / 2;
savedGamesTitleTxt.y = 400;
savedGamesContainer.addChild(savedGamesTitleTxt);
var savedGamesInstructionTxt = new Text2('Click a slot to load or save your game progress', {
size: 60,
fill: 0x000000,
fontWeight: 'bold'
});
savedGamesInstructionTxt.anchor.set(0.5, 0.5);
savedGamesInstructionTxt.x = 2048 / 2;
savedGamesInstructionTxt.y = 550;
savedGamesContainer.addChild(savedGamesInstructionTxt);
// Create 5 save game slot buttons in saved games container
var saveSlots = [];
for (var i = 0; i < 5; i++) {
var slotData = savedGames[i];
var slotText = 'Slot ' + (i + 1);
if (slotData) {
slotText += ' - Level ' + slotData.level + ' (' + slotData.coins + ' coins)';
if (slotData.result) {
slotText += ' - ' + slotData.result;
}
} else {
slotText += ' - Empty';
}
var slotBtn = new Text2(slotText, {
size: 60,
fill: slotData ? 0x4ECDC4 : 0x666666,
fontWeight: 'bold'
});
slotBtn.anchor.set(0.5, 0.5);
slotBtn.x = 2048 / 2;
slotBtn.y = 750 + i * 150;
slotBtn.slotIndex = i;
savedGamesContainer.addChild(slotBtn);
saveSlots.push(slotBtn);
}
// Back to menu button for saved games
var savedGamesBackBtn = new Text2('BACK TO MENU', {
size: 80,
fill: 0xCCCCCC,
fontWeight: 'bold'
});
savedGamesBackBtn.anchor.set(0.5, 0.5);
savedGamesBackBtn.x = 2048 / 2;
savedGamesBackBtn.y = 1500;
savedGamesContainer.addChild(savedGamesBackBtn);
// Create card types array based on level (4 tiles for first level + 6 tiles per additional level)
var totalTiles;
if (currentLevel === 1) {
totalTiles = 4; // First level has exactly 4 tiles
} else {
totalTiles = 4 + (currentLevel - 1) * 6; // 4 base tiles + 6 per level
}
var pairCount = totalTiles / 2;
var cardTypes = [];
for (var i = 1; i <= pairCount; i++) {
// Ensure symbol index stays within valid range (1-25)
var symbolIndex = (i - 1) % 25 + 1; // Cycle through 25 available symbols
cardTypes.push(symbolIndex);
cardTypes.push(symbolIndex); // Add pair
}
// Shuffle function
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
}
// Initialize cards
function initializeCards() {
var shuffledTypes = shuffleArray(cardTypes);
// Calculate dynamic grid size based on total tiles
var totalTiles = cardTypes.length;
GRID_COLS = Math.ceil(Math.sqrt(totalTiles));
GRID_ROWS = Math.ceil(totalTiles / GRID_COLS);
// Adjust card size based on grid size
if (totalTiles > 16) {
CARD_SIZE = Math.max(120, 200 - (totalTiles - 16) * 5);
CARD_SPACING = Math.max(10, 20 - (totalTiles - 16) * 1);
}
// Calculate grid positioning
var gridWidth = GRID_COLS * CARD_SIZE + (GRID_COLS - 1) * CARD_SPACING;
var gridHeight = GRID_ROWS * CARD_SIZE + (GRID_ROWS - 1) * CARD_SPACING;
var startX = (2048 - gridWidth) / 2 + CARD_SIZE / 2;
var startY = (2732 - gridHeight) / 2 + CARD_SIZE / 2;
for (var i = 0; i < totalTiles; i++) {
var row = Math.floor(i / GRID_COLS);
var col = i % GRID_COLS;
var card = new Card(shuffledTypes[i]);
card.x = startX + col * (CARD_SIZE + CARD_SPACING);
card.y = startY + row * (CARD_SIZE + CARD_SPACING);
cards.push(card);
game.addChild(card);
}
}
// Handle card tap
function handleCardTap(card) {
if (!canFlipCards || flippedCards.length >= 2 || gameOver) {
return;
}
card.flip();
flippedCards.push(card);
if (flippedCards.length === 2) {
moves++;
movesTxt.setText('Moves: ' + moves);
// Check if move limit exceeded
if (moves >= MOVE_LIMIT) {
gameOver = true;
// Save current level progress before game over
storage.currentLevel = currentLevel;
// Auto-save failed attempt
autoSaveGame('Failed - Move Limit');
LK.setTimeout(function () {
LK.showGameOver();
}, 1000);
return;
}
canFlipCards = false;
// Check for match after a short delay
LK.setTimeout(function () {
checkForMatch();
}, 1000);
}
}
// Check if two flipped cards match
function checkForMatch() {
var card1 = flippedCards[0];
var card2 = flippedCards[1];
if (card1.symbolType === card2.symbolType) {
// Match found
LK.getSound('match').play();
card1.setMatched();
card2.setMatched();
// Award 5 coins for matching pair
coins += 5;
storage.coins = coins;
coinsTxt.setText('Coins: ' + coins);
// Check if game is complete
var matchedCount = 0;
for (var i = 0; i < cards.length; i++) {
if (cards[i] && typeof cards[i].isMatched !== 'undefined' && cards[i].isMatched) {
matchedCount++;
}
}
if (matchedCount === cards.length) {
gameCompleted = true;
// Save current level completion
storage.currentLevel = currentLevel;
// Auto-save completed level
autoSaveGame('Completed');
// Award bonus coins for completing level
coins += 10;
storage.coins = coins;
coinsTxt.setText('Coins: ' + coins);
// Check if we've completed all 500 levels
if (currentLevel >= 500) {
// Show you win when all levels are completed
LK.setTimeout(function () {
LK.showYouWin();
}, 1000);
} else {
// Advance to next level
currentLevel++;
storage.currentLevel = currentLevel; // Save current level to storage
levelTxt.setText('Level: ' + currentLevel);
// Update menu progress display
levelInfoTxt.setText('Current Level: ' + currentLevel);
progressTxt.setText('Progress: ' + currentLevel + '/500');
// Show level completion message
LK.effects.flashScreen(0x00FF00, 1000);
// Reset for next level
LK.setTimeout(function () {
resetLevel();
}, 1500);
}
}
} else {
// No match
LK.getSound('noMatch').play();
card1.flip();
card2.flip();
}
flippedCards = [];
canFlipCards = true;
}
// Reset level for progression
function resetLevel() {
// Show level completion message briefly if advancing
if (currentLevel > 1) {
levelCompleteTxt.setText('LEVEL ' + (currentLevel - 1) + ' COMPLETE!');
levelCompleteTxt.visible = true;
LK.setTimeout(function () {
levelCompleteTxt.visible = false;
}, 2000);
}
// Clear existing cards
for (var i = 0; i < cards.length; i++) {
if (cards[i] && typeof cards[i].destroy === 'function') {
cards[i].destroy();
}
}
cards = [];
flippedCards = [];
moves = 0;
gameCompleted = false;
canFlipCards = true;
gameOver = false;
gameStartTime = Date.now();
startTime = Date.now();
// Update UI
movesTxt.setText('Moves: 0');
timerTxt.setText('Time: 0:00');
// Recreate card types for new level
var totalTiles;
if (currentLevel === 1) {
totalTiles = 4; // First level has exactly 4 tiles
} else {
totalTiles = 4 + (currentLevel - 1) * 6; // 4 base tiles + 6 per level
}
var pairCount = totalTiles / 2;
cardTypes = [];
for (var i = 1; i <= pairCount; i++) {
// Ensure symbol index stays within valid range (1-25)
var symbolIndex = (i - 1) % 25 + 1; // Cycle through 25 available symbols
cardTypes.push(symbolIndex);
cardTypes.push(symbolIndex);
}
// Initialize new cards
initializeCards();
}
// Format time display
function formatTime(seconds) {
var minutes = Math.floor(seconds / 60);
var remainingSeconds = seconds % 60;
return minutes + ':' + (remainingSeconds < 10 ? '0' : '') + remainingSeconds;
}
// Building purchase functions
function buyHauntedMansion() {
if (coins >= 50) {
coins = Math.max(0, coins - 50);
storage.coins = coins;
shopCoinsTxt.setText('Coins: ' + coins);
coinsInfoTxt.setText('Coins: ' + coins);
var mansionCount = storage.mansionCount || 0;
storage.mansionCount = mansionCount + 1;
LK.effects.flashScreen(0x4B0082, 500);
}
}
function buyWitchHut() {
if (coins >= 75) {
coins = Math.max(0, coins - 75);
storage.coins = coins;
shopCoinsTxt.setText('Coins: ' + coins);
coinsInfoTxt.setText('Coins: ' + coins);
var hutCount = storage.hutCount || 0;
storage.hutCount = hutCount + 1;
LK.effects.flashScreen(0x228B22, 500);
}
}
function buyPumpkinPatch() {
if (coins >= 30) {
coins = Math.max(0, coins - 30);
storage.coins = coins;
shopCoinsTxt.setText('Coins: ' + coins);
coinsInfoTxt.setText('Coins: ' + coins);
var patchCount = storage.patchCount || 0;
storage.patchCount = patchCount + 1;
LK.effects.flashScreen(0xFF8C00, 500);
}
}
function buyGhostlyTower() {
if (coins >= 100) {
coins = Math.max(0, coins - 100);
storage.coins = coins;
shopCoinsTxt.setText('Coins: ' + coins);
coinsInfoTxt.setText('Coins: ' + coins);
var towerCount = storage.towerCount || 0;
storage.towerCount = towerCount + 1;
LK.effects.flashScreen(0xF5F5F5, 500);
}
}
function buyVampireCastle() {
if (coins >= 200) {
coins = Math.max(0, coins - 200);
storage.coins = coins;
shopCoinsTxt.setText('Coins: ' + coins);
coinsInfoTxt.setText('Coins: ' + coins);
var castleCount = storage.castleCount || 0;
storage.castleCount = castleCount + 1;
LK.effects.flashScreen(0x8B0000, 500);
}
}
function buyFriendlyGhost() {
if (coins >= 40) {
coins = Math.max(0, coins - 40);
storage.coins = coins;
shopCoinsTxt.setText('Coins: ' + coins);
coinsInfoTxt.setText('Coins: ' + coins);
var ghostCount = storage.ghostCount || 0;
storage.ghostCount = ghostCount + 1;
LK.effects.flashScreen(0xD3D3D3, 500);
}
}
function buyWizard() {
if (coins >= 60) {
coins = Math.max(0, coins - 60);
storage.coins = coins;
shopCoinsTxt.setText('Coins: ' + coins);
coinsInfoTxt.setText('Coins: ' + coins);
var wizardCount = storage.wizardCount || 0;
storage.wizardCount = wizardCount + 1;
LK.effects.flashScreen(0x191970, 500);
}
}
function buyBlackCat() {
if (coins >= 25) {
coins = Math.max(0, coins - 25);
storage.coins = coins;
shopCoinsTxt.setText('Coins: ' + coins);
coinsInfoTxt.setText('Coins: ' + coins);
var catCount = storage.catCount || 0;
storage.catCount = catCount + 1;
LK.effects.flashScreen(0x000000, 500);
}
}
// Shop power-up purchase functions
function buyBomb() {
if (coins >= 10) {
coins = Math.max(0, coins - 10);
storage.coins = coins;
shopCoinsTxt.setText('Coins: ' + coins);
coinsInfoTxt.setText('Coins: ' + coins);
// Add bomb to inventory (stored in storage)
var bombCount = storage.bombCount || 0;
storage.bombCount = bombCount + 1;
bombTxt.setText('Bomb: ' + (storage.bombCount || 0));
LK.effects.flashScreen(0x00FF00, 500);
}
}
function buyHint() {
if (coins >= 15) {
coins = Math.max(0, coins - 15);
storage.coins = coins;
shopCoinsTxt.setText('Coins: ' + coins);
coinsInfoTxt.setText('Coins: ' + coins);
// Add hint to inventory
var hintCount = storage.hintCount || 0;
storage.hintCount = hintCount + 1;
lightbulbTxt.setText('Hint: ' + (storage.hintCount || 0));
LK.effects.flashScreen(0x00FF00, 500);
}
}
function buyClock() {
if (coins >= 20) {
coins = Math.max(0, coins - 20);
storage.coins = coins;
shopCoinsTxt.setText('Coins: ' + coins);
coinsInfoTxt.setText('Coins: ' + coins);
// Add clock to inventory
var clockCount = storage.clockCount || 0;
storage.clockCount = clockCount + 1;
clockTxt.setText('Clock: ' + (storage.clockCount || 0));
LK.effects.flashScreen(0x00FF00, 500);
}
}
function buyTimer() {
if (coins >= 5) {
coins = Math.max(0, coins - 5);
storage.coins = coins;
shopCoinsTxt.setText('Coins: ' + coins);
coinsInfoTxt.setText('Coins: ' + coins);
// Add timer to inventory
var timerCount = storage.timerCount || 0;
storage.timerCount = timerCount + 1;
timerPowerTxt.setText('Timer: ' + (storage.timerCount || 0));
LK.effects.flashScreen(0x00FF00, 500);
}
}
function buySkip() {
if (coins >= 100) {
coins = Math.max(0, coins - 100);
storage.coins = coins;
shopCoinsTxt.setText('Coins: ' + coins);
coinsInfoTxt.setText('Coins: ' + coins);
// Add skip to inventory
var skipCount = storage.skipCount || 0;
storage.skipCount = skipCount + 1;
skipTxt.setText('Skip: ' + (storage.skipCount || 0));
LK.effects.flashScreen(0x00FF00, 500);
}
}
// Power-up functions
function useBomb() {
var bombCount = storage.bombCount || 0;
if (bombCount > 0) {
storage.bombCount = bombCount - 1;
// Update display
bombTxt.setText('Bomb: ' + (storage.bombCount || 0));
// Delete 6 random non-matched cards
var availableCards = [];
for (var i = 0; i < cards.length; i++) {
if (cards[i] && typeof cards[i].isMatched !== 'undefined' && !cards[i].isMatched) {
availableCards.push(cards[i]);
}
}
var cardsToRemove = Math.min(6, availableCards.length);
for (var i = 0; i < cardsToRemove; i++) {
if (availableCards.length > 0) {
var randomIndex = Math.floor(Math.random() * availableCards.length);
var cardToRemove = availableCards[randomIndex];
if (cardToRemove && cardToRemove.destroy) {
cardToRemove.destroy();
var cardIndex = cards.indexOf(cardToRemove);
if (cardIndex !== -1) {
cards.splice(cardIndex, 1);
}
availableCards.splice(randomIndex, 1);
}
}
}
}
}
function useLightbulb() {
var hintCount = storage.hintCount || 0;
if (hintCount > 0) {
storage.hintCount = hintCount - 1;
// Update display
lightbulbTxt.setText('Hint: ' + (storage.hintCount || 0));
// Find a matching pair that's not matched yet
var unmatchedCards = [];
for (var i = 0; i < cards.length; i++) {
if (cards[i] && typeof cards[i].isMatched !== 'undefined' && !cards[i].isMatched) {
unmatchedCards.push(cards[i]);
}
}
// Group by symbol type
var symbolGroups = {};
for (var i = 0; i < unmatchedCards.length; i++) {
var card = unmatchedCards[i];
if (!symbolGroups[card.symbolType]) {
symbolGroups[card.symbolType] = [];
}
symbolGroups[card.symbolType].push(card);
}
// Find first pair and show them
for (var symbolType in symbolGroups) {
if (symbolGroups[symbolType].length >= 2) {
var pair = symbolGroups[symbolType].slice(0, 2);
for (var i = 0; i < pair.length; i++) {
if (!pair[i].isFlipped) {
pair[i].flip();
}
}
break;
}
}
}
}
function useClock() {
var clockCount = storage.clockCount || 0;
if (clockCount > 0) {
storage.clockCount = clockCount - 1;
// Update display
clockTxt.setText('Clock: ' + (storage.clockCount || 0));
// Add 5 minutes (300 seconds) to game time
gameStartTime -= 300000; // Subtract 5 minutes from start time to effectively add time
}
}
function useTimer() {
var timerCount = storage.timerCount || 0;
if (timerCount > 0) {
storage.timerCount = timerCount - 1;
// Update display
timerPowerTxt.setText('Timer: ' + (storage.timerCount || 0));
// Add 1 minute (60 seconds) to game time
gameStartTime -= 60000; // Subtract 1 minute from start time to effectively add time
}
}
function useSkip() {
var skipCount = storage.skipCount || 0;
if (skipCount > 0) {
storage.skipCount = skipCount - 1;
// Update display
skipTxt.setText('Skip: ' + (storage.skipCount || 0));
// Save current level before skipping
storage.currentLevel = currentLevel;
// Check if we've completed all 500 levels
if (currentLevel >= 500) {
// Show you win when all levels are completed
LK.setTimeout(function () {
LK.showYouWin();
}, 1000);
} else {
// Advance to next level
currentLevel++;
storage.currentLevel = currentLevel; // Save current level to storage
levelTxt.setText('Level: ' + currentLevel);
// Reset for next level
LK.setTimeout(function () {
resetLevel();
}, 1000);
}
}
}
// Function to save current game state
function saveGame(slotIndex) {
// Create flattened gameData object with only literals
var gameData = {
level: currentLevel,
coins: coins,
timestamp: Date.now()
};
// Ensure savedGames is initialized as an array
if (!Array.isArray(savedGames)) {
savedGames = [];
}
// Ensure we have enough slots
while (savedGames.length <= slotIndex) {
savedGames.push(null);
}
savedGames[slotIndex] = gameData;
storage['savedGame' + slotIndex] = gameData;
// Update the slot button text only if saveSlots exists and has the slot
if (saveSlots && saveSlots[slotIndex]) {
var slotBtn = saveSlots[slotIndex];
slotBtn.setText('Slot ' + (slotIndex + 1) + ' - Level ' + gameData.level + ' (' + gameData.coins + ' coins)');
slotBtn.tint = 0x4ECDC4;
}
}
// Function to auto-save to circular buffer of latest 5 games
function autoSaveGame(gameResult) {
// Create flattened gameData object with only literals
var gameData = {
level: currentLevel,
coins: coins,
timestamp: Date.now(),
result: gameResult
};
// Ensure savedGames is initialized as an array
if (!Array.isArray(savedGames)) {
savedGames = [];
}
// Create a new array to avoid reference issues
var newSavedGames = [];
// Add new game to the beginning
newSavedGames.push(gameData);
// Add existing games (up to 4 more)
for (var i = 0; i < Math.min(4, savedGames.length); i++) {
if (savedGames[i]) {
newSavedGames.push(savedGames[i]);
}
}
savedGames = newSavedGames;
// Keep only the latest 5 games
if (savedGames.length > 5) {
savedGames = savedGames.slice(0, 5);
}
// Save each slot individually to storage with only literals
for (var i = 0; i < 5; i++) {
if (i < savedGames.length && savedGames[i]) {
storage['savedGame' + i] = {
level: savedGames[i].level,
coins: savedGames[i].coins,
timestamp: savedGames[i].timestamp,
result: savedGames[i].result || ''
};
} else {
storage['savedGame' + i] = null;
}
}
// Update all slot buttons if they exist
if (saveSlots) {
for (var i = 0; i < 5; i++) {
if (saveSlots[i]) {
var slotData = savedGames[i];
var slotText = 'Slot ' + (i + 1);
if (slotData) {
slotText += ' - Level ' + slotData.level + ' (' + slotData.coins + ' coins)';
if (slotData.result) {
slotText += ' - ' + slotData.result;
}
} else {
slotText += ' - Empty';
}
saveSlots[i].setText(slotText);
saveSlots[i].tint = slotData ? 0x4ECDC4 : 0x666666;
}
}
}
}
// Function to load saved game
function loadGame(slotIndex) {
if (slotIndex >= 0 && slotIndex < savedGames.length && savedGames[slotIndex]) {
var gameData = savedGames[slotIndex];
if (gameData && typeof gameData.level === 'number' && typeof gameData.coins === 'number') {
currentLevel = Math.max(1, Math.min(500, gameData.level));
coins = Math.max(0, gameData.coins);
storage.currentLevel = currentLevel;
storage.coins = coins;
// Update UI
levelInfoTxt.setText('Current Level: ' + currentLevel);
coinsInfoTxt.setText('Coins: ' + coins);
progressTxt.setText('Progress: ' + currentLevel + '/500');
}
}
}
// Function to update power-up inventory display
function updatePowerUpDisplay() {
bombTxt.setText('Bomb: ' + (storage.bombCount || 0));
lightbulbTxt.setText('Hint: ' + (storage.hintCount || 0));
clockTxt.setText('Clock: ' + (storage.clockCount || 0));
timerPowerTxt.setText('Timer: ' + (storage.timerCount || 0));
skipTxt.setText('Skip: ' + (storage.skipCount || 0));
}
// Function to start the game
function startGame() {
showMenu = false;
menuContainer.visible = false;
// Show game UI elements
movesTxt.visible = true;
timerTxt.visible = true;
coinsTxt.visible = true;
levelTxt.visible = true;
bombTxt.visible = true;
lightbulbTxt.visible = true;
clockTxt.visible = true;
timerPowerTxt.visible = true;
skipTxt.visible = true;
playBackBtn.visible = true;
// Update power-up display
updatePowerUpDisplay();
// Initialize game
initializeCards();
gameStartTime = Date.now();
startTime = Date.now();
}
// Add click handlers for power-ups
bombTxt.down = function (x, y, obj) {
useBomb();
};
lightbulbTxt.down = function (x, y, obj) {
useLightbulb();
};
clockTxt.down = function (x, y, obj) {
useClock();
};
timerPowerTxt.down = function (x, y, obj) {
useTimer();
};
skipTxt.down = function (x, y, obj) {
useSkip();
};
// Saved Games button click handler
savedGamesBtn.down = function (x, y, obj) {
menuContainer.visible = false;
savedGamesContainer.visible = true;
// Update saved games display
for (var i = 0; i < saveSlots.length; i++) {
var slotData = savedGames[i];
var slotText = 'Slot ' + (i + 1);
if (slotData) {
slotText += ' - Level ' + slotData.level + ' (' + slotData.coins + ' coins)';
if (slotData.result) {
slotText += ' - ' + slotData.result;
}
} else {
slotText += ' - Empty';
}
saveSlots[i].setText(slotText);
saveSlots[i].tint = slotData ? 0x4ECDC4 : 0x666666;
}
};
// World screen container
var worldContainer = new Container();
worldContainer.visible = false;
// Add worldbackground as background
var worldContainerBackground = LK.getAsset('worldbackground', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 20,
scaleY: 27
});
worldContainerBackground.x = 2048 / 2;
worldContainerBackground.y = 2732 / 2;
worldContainer.addChild(worldContainerBackground);
game.addChild(worldContainer);
var worldTitleTxt = new Text2('YOUR SPOOKY WORLD', {
size: 120,
fill: 0x4B0082,
fontWeight: 'bold'
});
worldTitleTxt.anchor.set(0.5, 0.5);
worldTitleTxt.x = 2048 / 2;
worldTitleTxt.y = 400;
worldContainer.addChild(worldTitleTxt);
var worldInstructionTxt = new Text2('Drag buildings to place them in your world', {
size: 60,
fill: 0x000000,
fontWeight: 'bold'
});
worldInstructionTxt.anchor.set(0.5, 0.5);
worldInstructionTxt.x = 2048 / 2;
worldInstructionTxt.y = 500;
worldContainer.addChild(worldInstructionTxt);
// World back button
var worldBackBtn = new Text2('BACK TO MENU', {
size: 80,
fill: 0xCCCCCC,
fontWeight: 'bold'
});
worldBackBtn.anchor.set(0.5, 0.5);
worldBackBtn.x = 2048 / 2;
worldBackBtn.y = 2400;
worldContainer.addChild(worldBackBtn);
// Array to store placed buildings
var placedBuildings = [];
// World button click handler
worldBtn.down = function (x, y, obj) {
menuContainer.visible = false;
worldContainer.visible = true;
createWorldBuildings();
};
// World back button handler
worldBackBtn.down = function (x, y, obj) {
worldContainer.visible = false;
menuContainer.visible = true;
saveWorldState();
};
// Function to create world buildings based on purchased items
function createWorldBuildings() {
// Clear existing buildings
for (var i = 0; i < placedBuildings.length; i++) {
placedBuildings[i].destroy();
}
placedBuildings = [];
// Load saved positions from flattened storage structure
var savedPositions = {};
for (var i = 0; i < placedBuildings.length; i++) {
var building = placedBuildings[i];
var x = storage['buildingPos_' + building.buildingId + '_x'];
var y = storage['buildingPos_' + building.buildingId + '_y'];
if (x !== undefined && y !== undefined) {
savedPositions[building.buildingId] = {
x: x,
y: y
};
}
}
var buildingY = 700;
var buildingX = 150;
var buildingSpacing = 300;
// Create buildings based on purchased counts
var mansionCount = storage.mansionCount || 0;
for (var i = 0; i < mansionCount; i++) {
var mansion = createBuilding('Haunted Mansion', 0x4B0082, buildingX, buildingY, 'mansion_' + i);
placedBuildings.push(mansion);
worldContainer.addChild(mansion);
buildingX += buildingSpacing;
if (buildingX > 1800) {
buildingX = 150;
buildingY += 250;
}
}
var hutCount = storage.hutCount || 0;
for (var i = 0; i < hutCount; i++) {
var hut = createBuilding('Witch Hut', 0x228B22, buildingX, buildingY, 'hut_' + i);
placedBuildings.push(hut);
worldContainer.addChild(hut);
buildingX += buildingSpacing;
if (buildingX > 1800) {
buildingX = 150;
buildingY += 250;
}
}
var patchCount = storage.patchCount || 0;
for (var i = 0; i < patchCount; i++) {
var patch = createBuilding('Pumpkin Patch', 0xFF8C00, buildingX, buildingY, 'patch_' + i);
placedBuildings.push(patch);
worldContainer.addChild(patch);
buildingX += buildingSpacing;
if (buildingX > 1800) {
buildingX = 150;
buildingY += 250;
}
}
var towerCount = storage.towerCount || 0;
for (var i = 0; i < towerCount; i++) {
var tower = createBuilding('Ghostly Tower', 0xF5F5F5, buildingX, buildingY, 'tower_' + i);
placedBuildings.push(tower);
worldContainer.addChild(tower);
buildingX += buildingSpacing;
if (buildingX > 1800) {
buildingX = 150;
buildingY += 250;
}
}
var castleCount = storage.castleCount || 0;
for (var i = 0; i < castleCount; i++) {
var castle = createBuilding('Vampire Castle', 0x8B0000, buildingX, buildingY, 'castle_' + i);
placedBuildings.push(castle);
worldContainer.addChild(castle);
buildingX += buildingSpacing;
if (buildingX > 1800) {
buildingX = 150;
buildingY += 250;
}
}
var ghostCount = storage.ghostCount || 0;
for (var i = 0; i < ghostCount; i++) {
var ghost = createBuilding('Friendly Ghost', 0xD3D3D3, buildingX, buildingY, 'ghost_' + i);
placedBuildings.push(ghost);
worldContainer.addChild(ghost);
buildingX += buildingSpacing;
if (buildingX > 1800) {
buildingX = 150;
buildingY += 250;
}
}
var wizardCount = storage.wizardCount || 0;
for (var i = 0; i < wizardCount; i++) {
var wizard = createBuilding('Wizard', 0x191970, buildingX, buildingY, 'wizard_' + i);
placedBuildings.push(wizard);
worldContainer.addChild(wizard);
buildingX += buildingSpacing;
if (buildingX > 1800) {
buildingX = 150;
buildingY += 250;
}
}
var catCount = storage.catCount || 0;
for (var i = 0; i < catCount; i++) {
var cat = createBuilding('Black Cat', 0x000000, buildingX, buildingY, 'cat_' + i);
placedBuildings.push(cat);
worldContainer.addChild(cat);
buildingX += buildingSpacing;
if (buildingX > 1800) {
buildingX = 150;
buildingY += 250;
}
}
// Apply saved positions
for (var i = 0; i < placedBuildings.length; i++) {
var building = placedBuildings[i];
if (savedPositions[building.buildingId]) {
building.x = savedPositions[building.buildingId].x;
building.y = savedPositions[building.buildingId].y;
}
}
}
// Function to create a draggable building
function createBuilding(name, color, x, y, buildingId) {
var building = new Container();
building.buildingId = buildingId;
// Create building visual - use appropriate asset based on building type
var assetName = 'hauntedMansion'; // default fallback
if (name === 'Haunted Mansion') assetName = 'hauntedMansion';else if (name === 'Witch Hut') assetName = 'witchHut';else if (name === 'Pumpkin Patch') assetName = 'pumpkinPatch';else if (name === 'Ghostly Tower') assetName = 'ghostlyTower';else if (name === 'Vampire Castle') assetName = 'vampireCastle';else if (name === 'Friendly Ghost') assetName = 'friendlyGhost';else if (name === 'Wizard') assetName = 'wizard';else if (name === 'Black Cat') assetName = 'blackCat';
var buildingShape = LK.getAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
building.addChild(buildingShape);
// Create building label
var buildingLabel = new Text2(name, {
size: 30,
fill: 0x000000,
fontWeight: 'bold'
});
buildingLabel.anchor.set(0.5, 0.5);
buildingLabel.y = 100;
building.addChild(buildingLabel);
building.x = x;
building.y = y;
// Make building draggable
building.isDragging = false;
building.down = function (x, y, obj) {
if (building && typeof building.x !== 'undefined' && typeof building.y !== 'undefined') {
building.isDragging = true;
// Convert coordinates to local space for proper offset calculation
var localPos = worldContainer.toLocal({
x: x,
y: y
});
building.dragOffsetX = localPos.x - building.x;
building.dragOffsetY = localPos.y - building.y;
}
};
building.up = function (x, y, obj) {
building.isDragging = false;
};
return building;
}
// Function to save world state
function saveWorldState() {
var positions = {};
for (var i = 0; i < placedBuildings.length; i++) {
var building = placedBuildings[i];
positions[building.buildingId] = {
x: building.x,
y: building.y
};
}
// Store positions as individual key-value pairs to avoid object nesting issues
for (var buildingId in positions) {
storage['buildingPos_' + buildingId + '_x'] = positions[buildingId].x;
storage['buildingPos_' + buildingId + '_y'] = positions[buildingId].y;
}
}
// Handle building dragging
var draggedBuilding = null;
// World container mouse handlers
worldContainer.move = function (x, y, obj) {
for (var i = 0; i < placedBuildings.length; i++) {
var building = placedBuildings[i];
if (building && building.isDragging) {
// Convert coordinates to world container local space
var localPos = worldContainer.toLocal({
x: x,
y: y
});
// Keep buildings within world bounds
var newX = Math.max(100, Math.min(1948, localPos.x - (building.dragOffsetX || 0)));
var newY = Math.max(600, Math.min(2300, localPos.y - (building.dragOffsetY || 0)));
building.x = newX;
building.y = newY;
break;
}
}
};
worldContainer.up = function (x, y, obj) {
for (var i = 0; i < placedBuildings.length; i++) {
var building = placedBuildings[i];
if (building.isDragging) {
building.isDragging = false;
break;
}
}
};
// Saved Games back button click handler
savedGamesBackBtn.down = function (x, y, obj) {
savedGamesContainer.visible = false;
menuContainer.visible = true;
};
// Save game slot click handlers
for (var i = 0; i < saveSlots.length; i++) {
saveSlots[i].down = function (x, y, obj) {
var slotIndex = obj.slotIndex;
var gameData = savedGames[slotIndex];
if (gameData) {
// Load existing save and go back to menu
loadGame(slotIndex);
savedGamesContainer.visible = false;
menuContainer.visible = true;
} else {
// Save current game to empty slot
saveGame(slotIndex);
}
};
}
// Shop button click handler
shopBtn.down = function (x, y, obj) {
menuContainer.visible = false;
shopContainer.visible = true;
shopCoinsTxt.setText('Coins: ' + coins);
};
// Tab switching handlers
powerUpTabBtn.down = function (x, y, obj) {
powerUpTabContainer.visible = true;
buildingTabContainer.visible = false;
powerUpTabBtn.fill = 0x4ECDC4;
buildingTabBtn.fill = 0x666666;
};
buildingTabBtn.down = function (x, y, obj) {
powerUpTabContainer.visible = false;
buildingTabContainer.visible = true;
powerUpTabBtn.fill = 0x666666;
buildingTabBtn.fill = 0x8B4513;
};
// Building purchase handlers
hauntedMansionBtn.down = function (x, y, obj) {
buyHauntedMansion();
};
witchHutBtn.down = function (x, y, obj) {
buyWitchHut();
};
pumpkinPatchBtn.down = function (x, y, obj) {
buyPumpkinPatch();
};
ghostlyTowerBtn.down = function (x, y, obj) {
buyGhostlyTower();
};
vampireCastleBtn.down = function (x, y, obj) {
buyVampireCastle();
};
friendlyGhostBtn.down = function (x, y, obj) {
buyFriendlyGhost();
};
wizardBtn.down = function (x, y, obj) {
buyWizard();
};
blackCatBtn.down = function (x, y, obj) {
buyBlackCat();
};
// Shop power-up purchase handlers
shopBombBtn.down = function (x, y, obj) {
buyBomb();
};
shopHintBtn.down = function (x, y, obj) {
buyHint();
};
shopClockBtn.down = function (x, y, obj) {
buyClock();
};
shopTimerBtn.down = function (x, y, obj) {
buyTimer();
};
shopSkipBtn.down = function (x, y, obj) {
buySkip();
};
// Back to menu button handler
shopBackBtn.down = function (x, y, obj) {
shopContainer.visible = false;
menuContainer.visible = true;
coinsInfoTxt.setText('Coins: ' + coins);
};
// Create back button for play function
var playBackBtn = new Text2('BACK TO MENU', {
size: 60,
fill: 0xCCCCCC,
fontWeight: 'bold'
});
playBackBtn.anchor.set(0.5, 0);
LK.gui.topRight.addChild(playBackBtn);
playBackBtn.x = -100;
playBackBtn.y = 100;
playBackBtn.visible = false;
// Back button click handler for play function
playBackBtn.down = function (x, y, obj) {
// Return to menu
showMenu = true;
menuContainer.visible = true;
// Hide game UI elements
movesTxt.visible = false;
timerTxt.visible = false;
coinsTxt.visible = false;
levelTxt.visible = false;
bombTxt.visible = false;
lightbulbTxt.visible = false;
clockTxt.visible = false;
timerPowerTxt.visible = false;
skipTxt.visible = false;
playBackBtn.visible = false;
// Clear existing cards
for (var i = 0; i < cards.length; i++) {
cards[i].destroy();
}
cards = [];
flippedCards = [];
// Reset game state variables
moves = 0;
gameCompleted = false;
canFlipCards = true;
gameOver = false;
// Hide level complete text if visible
levelCompleteTxt.visible = false;
// Update menu display with current values
levelInfoTxt.setText('Current Level: ' + currentLevel);
coinsInfoTxt.setText('Coins: ' + coins);
progressTxt.setText('Progress: ' + currentLevel + '/500');
};
// Play button click handler
playBtn.down = function (x, y, obj) {
// Always start from level 1 when play button is pressed
currentLevel = 1;
storage.currentLevel = currentLevel;
// Reset coin count when play button is pressed
coins = 0;
storage.coins = coins;
coinsTxt.setText('Coins: ' + coins);
coinsInfoTxt.setText('Coins: ' + coins);
levelTxt.setText('Level: ' + currentLevel);
levelInfoTxt.setText('Current Level: ' + currentLevel);
progressTxt.setText('Progress: ' + currentLevel + '/500');
// Reset game state variables for fresh start
moves = 0;
gameCompleted = false;
canFlipCards = true;
gameOver = false;
flippedCards = [];
// Clear existing cards if any
for (var i = 0; i < cards.length; i++) {
cards[i].destroy();
}
cards = [];
startGame();
};
// Hide game UI elements initially (show only in game)
movesTxt.visible = false;
timerTxt.visible = false;
coinsTxt.visible = false;
levelTxt.visible = false;
bombTxt.visible = false;
lightbulbTxt.visible = false;
clockTxt.visible = false;
timerPowerTxt.visible = false;
skipTxt.visible = false;
// Don't initialize cards immediately - wait for menu
// initializeCards(); // This will be called when starting the game
// Main game update loop
game.update = function () {
// Only update game logic if not in menu
if (!showMenu) {
// Update timer
if (!gameCompleted && !gameOver) {
var elapsedTime = Math.floor((Date.now() - gameStartTime) / 1000);
var remainingTime = Math.max(0, LEVEL_TIME_LIMIT - elapsedTime);
timerTxt.setText('Time: ' + formatTime(remainingTime));
// Check if time is up
if (remainingTime <= 0) {
gameOver = true;
// Save current level progress before game over
storage.currentLevel = currentLevel;
// Auto-save failed attempt
autoSaveGame('Failed - Time Limit');
LK.showGameOver();
}
}
}
};
// Start background music
LK.playMusic('bgmusic');