/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // AI Robot: Simple animated character that moves left and right var AIRobot = Container.expand(function () { var self = Container.call(this); // Attach a robot body (use aiIndicator image as the robot's head/body) var robotBody = self.attachAsset('aiIndicator', { anchorX: 0.5, anchorY: 0.5 }); // Add two "eyes" using small ellipses var leftEye = self.attachAsset('freeSpace', { width: 24, height: 24, color: 0xffffff, anchorX: 0.5, anchorY: 0.5 }); var rightEye = self.attachAsset('freeSpace', { width: 24, height: 24, color: 0xffffff, anchorX: 0.5, anchorY: 0.5 }); leftEye.x = -36; leftEye.y = -20; rightEye.x = 36; rightEye.y = -20; // Animation state self.direction = 1; // 1: right, -1: left self.speed = 6 + Math.random() * 4; // px per frame self.minX = 200; self.maxX = 2048 - 200; // For eye animation self.eyeTick = 0; // Initial position self.x = 2048 * 3 / 4; self.y = 2732 - 180; // Update method for movement and eye animation self.update = function () { // Move left/right self.x += self.direction * self.speed; if (self.x > self.maxX) { self.x = self.maxX; self.direction = -1; } if (self.x < self.minX) { self.x = self.minX; self.direction = 1; } // Animate eyes (look in direction of movement) self.eyeTick++; var eyeOffset = 4 * self.direction + Math.sin(self.eyeTick / 10) * 2; leftEye.x = -36 + eyeOffset; rightEye.x = 36 + eyeOffset; }; return self; }); // BingoCell: Represents a single cell on the bingo card var BingoCell = Container.expand(function () { var self = Container.call(this); // Properties self.number = 0; self.marked = false; // Create cell background var cellBg = self.attachAsset('bingoCellBg', { width: cellSize, height: cellSize, anchorX: 0.5, anchorY: 0.5 }); // Number text var numberText = new Text2('', { size: Math.floor(cellSize * 0.45), fill: 0xffffff }); numberText.anchor.set(0.5, 0.5); self.addChild(numberText); // Mark overlay (hidden by default) var markOverlay = self.attachAsset('bingoMark', { width: cellSize * 0.7, height: cellSize * 0.7, anchorX: 0.5, anchorY: 0.5 }); markOverlay.alpha = 0; self.markOverlay = markOverlay; // Set number and update text self.setNumber = function (num) { self.number = num; numberText.setText(num > 0 ? num : ''); }; // Mark/unmark cell self.setMarked = function (val) { self.marked = val; if (val) { tween(markOverlay, { alpha: 0.8 }, { duration: 200, easing: tween.easeOut }); numberText.setText(self.number); numberText.setStyle({ fill: 0x000000 }); } else { tween(markOverlay, { alpha: 0 }, { duration: 200, easing: tween.easeOut }); numberText.setStyle({ fill: 0xffffff }); } }; // Touch event self.down = function (x, y, obj) { // Play click sound on any cell tap LK.getSound('Click').play(); if (self.marked) return; if (game.state !== 'playing') return; var p = self.playerIndex !== undefined ? self.playerIndex : 0; if (self.number === game.currentNumber && p === currentPlayer) { self.setMarked(true); LK.effects.flashObject(self, 0xff6600, 200); // Streak logic if (typeof streak !== "undefined") { streak[p]++; streakText[p].setText("Streak: " + streak[p]); if (streak[p] > 1) { // Bonus: add 1s per streak above 1 timeLeft[p] += 1000; tween(streakText[p], { scaleX: 1.3, scaleY: 1.3 }, { duration: 100, yoyo: true, repeat: 1, easing: tween.easeOut }); } } game.checkWin(); } else { if (typeof streak !== "undefined") { streak[p] = 0; streakText[p].setText(""); } LK.effects.flashObject(self, 0x8b0000, 200); } }; // Example: Trigger action when cell crosses X = 1000 from left to right if (self.lastX !== undefined && self.lastX <= 1000 && self.x > 1000) { // Place your action here, e.g. console.log("Cell crossed X=1000!"); } // Always update lastX at the end self.lastX = self.x; // Example: Trigger action when cell crosses Y = 800 from above to below if (self.lastY !== undefined && self.lastY <= 800 && self.y > 800) { // Place your action here, e.g. console.log("Cell crossed Y=800!"); } // Always update lastY at the end self.lastY = self.y; // Example: Trigger action when cell crosses X=1000 and Y=800 at the same frame if (self.lastY !== undefined && self.lastY <= 800 && self.y > 800 && self.lastX !== undefined && self.lastX <= 1000 && self.x > 1000) { // Place your action here, e.g. console.log("Cell arrived at (1000,800)!"); } // Always update lastX and lastY at the end self.lastX = self.x; self.lastY = self.y; return self; }); // CalledNumberBall: Shows a called number as a round ball var CalledNumberBall = Container.expand(function () { var self = Container.call(this); // Ball background var ball = self.attachAsset('bingoBall', { anchorX: 0.5, anchorY: 0.5 }); // Number text var numberText = new Text2('', { size: 60, fill: 0x000000 }); numberText.anchor.set(0.5, 0.5); numberText.x = 0; numberText.y = 0; self.addChild(numberText); self.setNumber = function (num) { numberText.setText(num); }; return self; }); // MazeMode: Simple maze mini-game overlay var MazeMode = Container.expand(function () { var self = Container.call(this); // Maze config var mazeCols = 7; var mazeRows = 9; var cellW = Math.floor(2048 / mazeCols); var cellH = Math.floor(1800 / mazeRows); var offsetX = Math.floor((2048 - mazeCols * cellW) / 2); var offsetY = 400; // Maze grid: 0 = open, 1 = wall self.grid = []; // Generate a simple random maze (DFS backtracker) function generateMaze(cols, rows) { var grid = []; for (var y = 0; y < rows; y++) { var row = []; for (var x = 0; x < cols; x++) row.push(1); grid.push(row); } function carve(x, y) { grid[y][x] = 0; var dirs = [[0, 1], [1, 0], [0, -1], [-1, 0]]; for (var i = 0; i < 4; i++) { var j = Math.floor(Math.random() * 4); var tmp = dirs[i]; dirs[i] = dirs[j]; dirs[j] = tmp; } for (var d = 0; d < 4; d++) { var nx = x + dirs[d][0] * 2, ny = y + dirs[d][1] * 2; if (nx >= 0 && nx < cols && ny >= 0 && ny < rows && grid[ny][nx] === 1) { grid[y + dirs[d][1]][x + dirs[d][0]] = 0; carve(nx, ny); } } } carve(1, 1); grid[1][1] = 0; // Start grid[rows - 2][cols - 2] = 0; // End return grid; } self.grid = generateMaze(mazeCols, mazeRows); // Draw maze self.cells = []; for (var y = 0; y < mazeRows; y++) { for (var x = 0; x < mazeCols; x++) { if (self.grid[y][x] === 1) { var wall = LK.getAsset('calledNumbersBg', { width: cellW - 8, height: cellH - 8, anchorX: 0, anchorY: 0, x: offsetX + x * cellW + 4, y: offsetY + y * cellH + 4 }); self.addChild(wall); self.cells.push(wall); } } } // Start and end var startX = 1, startY = 1; var endX = mazeCols - 2, endY = mazeRows - 2; var startCell = LK.getAsset('freeSpace', { width: cellW - 12, height: cellH - 12, anchorX: 0, anchorY: 0, x: offsetX + startX * cellW + 6, y: offsetY + startY * cellH + 6 }); startCell.alpha = 0.7; self.addChild(startCell); var endCell = LK.getAsset('winHighlight', { width: cellW - 12, height: cellH - 12, anchorX: 0, anchorY: 0, x: offsetX + endX * cellW + 6, y: offsetY + endY * cellH + 6 }); endCell.alpha = 0.7; self.addChild(endCell); // Player self.playerX = startX; self.playerY = startY; self.player = LK.getAsset('aiIndicator', { width: cellW - 24, height: cellH - 24, anchorX: 0, anchorY: 0, x: offsetX + self.playerX * cellW + 12, y: offsetY + self.playerY * cellH + 12 }); self.addChild(self.player); // Touch controls: swipe or tap to move self.touchStartX = null; self.touchStartY = null; self.touching = false; // Helper: move player if possible self.tryMove = function (dx, dy) { var nx = self.playerX + dx, ny = self.playerY + dy; if (nx >= 0 && nx < mazeCols && ny >= 0 && ny < mazeRows) { if (self.grid[ny][nx] === 0) { self.playerX = nx; self.playerY = ny; self.player.x = offsetX + self.playerX * cellW + 12; self.player.y = offsetY + self.playerY * cellH + 12; // Win check if (self.playerX === endX && self.playerY === endY) { if (typeof self.onWin === "function") self.onWin(); } } else { // Bump event: every time you try to move into a wall LK.effects.flashObject(self.player, 0xff0000, 150); } } }; // Touch events self.down = function (x, y, obj) { self.touchStartX = x; self.touchStartY = y; self.touching = true; }; self.up = function (x, y, obj) { if (!self.touching) return; var dx = x - self.touchStartX; var dy = y - self.touchStartY; if (Math.abs(dx) > Math.abs(dy)) { if (dx > 40) self.tryMove(1, 0);else if (dx < -40) self.tryMove(-1, 0); } else { if (dy > 40) self.tryMove(0, 1);else if (dy < -40) self.tryMove(0, -1); } self.touching = false; }; // Also allow tap on adjacent cell self.move = function (x, y, obj) {}; // Overlay text var mazeText = new Text2('Maze! Reach the yellow cell!', { size: 90, fill: 0xffd700 }); mazeText.anchor.set(0.5, 1); mazeText.x = 2048 / 2; mazeText.y = offsetY - 30; self.addChild(mazeText); // Win callback (set externally) self.onWin = null; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x181a1b }); /**** * Game Code ****/ // Fart sound effects (using available ses54, ses55, ses56, ses57, ses58, ses59, ses60 as fart-like sounds) // --- Added ses41 to ses75 sound assets (IDs to be filled by asset loader) --- // Save the current game state (called numbers, card numbers, marked cells, time left, streaks) // All bingo card and bingo cell logic removed as requested. // Bingo ball (yellow ellipse) // Bingo cell background (cyan box) // Mark overlay (beige box, used for marking cells) // Hint button background (green box, used for hint power-up) // Free space overlay (distinct color for center cell) // Win highlight overlay (gold ellipse for winning line) // Reveal Row button removed // Freeze Timer button and logic removed // Ses assets for ses1 to ses40 var gridSize = 5; // 5x5 bingo // Adjust cellSize and card positions for two-player mode to fit both cards on screen var cellSize = 180; // px, reduced to fit two cards side by side var cardPadding = 30; var cardWidth = gridSize * cellSize; var cardHeight = gridSize * cellSize; var cardStartX = 2048 / 4 - cardWidth / 2; // Player 1 card center at 1/4 width, Player 2 at 3/4 width var cardStartY = 500; // Lowered to fit both cards and UI var callIntervalStart = 4000; // ms (4 seconds initial call speed) var callIntervalMin = 1200; // ms (slower minimum speed) var callIntervalStep = 60; // ms, decrease per call (slower speedup) var gameDuration = 225000; // ms (3 min 45 sec) var numbersRange = 75; // 1-75 // Remove all bingo logic and display random numbers on screen repeatedly // Create a big number text in the center var numberCallText = new Text2('', { size: 400, fill: 0xff073a }); numberCallText.anchor.set(0.5, 0.5); numberCallText.x = 2048 / 2; numberCallText.y = 2732 / 2; game.addChild(numberCallText); // Add a warning text in the center, above the number var warningText = new Text2('click, something will happen.', { size: 120, fill: 0xff0000 }); warningText.anchor.set(0.5, 1); warningText.x = 2048 / 2; warningText.y = 2732 / 2 - 260; game.addChild(warningText); // Function to show a random number and play its sound // List of number translations for 1-20 in various languages, then fallback to English for higher numbers var numberLanguages = [{ lang: "English", words: ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"] }, { lang: "Spanish", words: ["uno", "dos", "tres", "cuatro", "cinco", "seis", "siete", "ocho", "nueve", "diez", "once", "doce", "trece", "catorce", "quince", "dieciséis", "diecisiete", "dieciocho", "diecinueve", "veinte"] }, { lang: "French", words: ["un", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf", "dix", "onze", "douze", "treize", "quatorze", "quinze", "seize", "dix-sept", "dix-huit", "dix-neuf", "vingt"] }, { lang: "German", words: ["eins", "zwei", "drei", "vier", "fünf", "sechs", "sieben", "acht", "neun", "zehn", "elf", "zwölf", "dreizehn", "vierzehn", "fünfzehn", "sechzehn", "siebzehn", "achtzehn", "neunzehn", "zwanzig"] }, { lang: "Italian", words: ["uno", "due", "tre", "quattro", "cinque", "sei", "sette", "otto", "nove", "dieci", "undici", "dodici", "tredici", "quattordici", "quindici", "sedici", "diciassette", "diciotto", "diciannove", "venti"] }, { lang: "Turkish", words: ["bir", "iki", "üç", "dört", "beş", "altı", "yedi", "sekiz", "dokuz", "on", "on bir", "on iki", "on üç", "on dört", "on beş", "on altı", "on yedi", "on sekiz", "on dokuz", "yirmi"] }, { lang: "Russian", words: ["один", "два", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять", "десять", "одиннадцать", "двенадцать", "тринадцать", "четырнадцать", "пятнадцать", "шестнадцать", "семнадцать", "восемнадцать", "девятнадцать", "двадцать"] }, { lang: "Japanese", words: ["いち", "に", "さん", "よん", "ご", "ろく", "なな", "はち", "きゅう", "じゅう", "じゅういち", "じゅうに", "じゅうさん", "じゅうよん", "じゅうご", "じゅうろく", "じゅうなな", "じゅうはち", "じゅうきゅう", "にじゅう"] }, { lang: "Chinese", words: ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十"] }]; var lastLangIndex = -1; function showRandomNumber() { var num = 1 + Math.floor(Math.random() * 75); // Pick a language different from last time var langIndex; do { langIndex = Math.floor(Math.random() * numberLanguages.length); } while (langIndex === lastLangIndex && numberLanguages.length > 1); lastLangIndex = langIndex; var langObj = numberLanguages[langIndex]; var displayText = ""; if (num <= 20) { displayText = langObj.words[num - 1]; // Show the number in digits below in smaller font for clarity numberCallText.setText(displayText + "\n" + num); numberCallText.setStyle({ size: 320 }); } else { // For numbers > 20, show the number in digits and the language name displayText = num + " (" + langObj.lang + ")"; numberCallText.setText(displayText); numberCallText.setStyle({ size: 400 }); } // Play ses1-ses75 sound if available var soundId = 'ses' + num; var sound = LK.getSound(soundId); if (sound) sound.play(); // Animate the number numberCallText.scale.x = 0.7; numberCallText.scale.y = 0.7; tween(numberCallText.scale, { x: 1, y: 1 }, { duration: 200, easing: tween.easeOut }); } // Call a new number every 2 seconds LK.setInterval(showRandomNumber, 2000); // Show the first number immediately showRandomNumber(); // --- Jump Scare Overlay and Logic --- var jumpScareOverlay = LK.getAsset('flashOverlay', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 0 }); game.addChild(jumpScareOverlay); // Optionally, you can add a scary text var jumpScareText = new Text2('!', { size: 600, fill: 0xff0000 }); jumpScareText.anchor.set(0.5, 0.5); jumpScareText.x = 2048 / 2; jumpScareText.y = 2732 / 2; jumpScareText.alpha = 0; game.addChild(jumpScareText); function triggerJumpScare() { // Flash overlay and text in jumpScareOverlay.alpha = 0.92; jumpScareText.alpha = 1; // Animate out after 600ms LK.setTimeout(function () { tween(jumpScareOverlay, { alpha: 0 }, { duration: 400, easing: tween.easeOut }); tween(jumpScareText, { alpha: 0 }, { duration: 400, easing: tween.easeOut }); }, 600); } // --- Second Jump Scare Overlay (Question Mark) and Logic --- var jumpScareOverlay2 = LK.getAsset('flashOverlay', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 0 }); game.addChild(jumpScareOverlay2); var jumpScareText2 = new Text2('?', { size: 600, fill: 0x00aaff }); jumpScareText2.anchor.set(0.5, 0.5); jumpScareText2.x = 2048 / 2; jumpScareText2.y = 2732 / 2; jumpScareText2.alpha = 0; game.addChild(jumpScareText2); function triggerJumpScare2() { // Flash overlay and text in jumpScareOverlay2.alpha = 0.92; jumpScareText2.alpha = 1; // Animate out after 600ms LK.setTimeout(function () { tween(jumpScareOverlay2, { alpha: 0 }, { duration: 400, easing: tween.easeOut }); tween(jumpScareText2, { alpha: 0 }, { duration: 400, easing: tween.easeOut }); }, 600); } // Schedule the question mark jump scare every 3 seconds LK.setInterval(triggerJumpScare2, 3000); // Schedule both click sound and jump scare every 9 seconds, in sync function triggerClickAndJumpScare() { // Play click sound var clickSound = LK.getSound('Click'); if (clickSound) clickSound.play(); // Trigger jump scare triggerJumpScare(); } // Call every 9 seconds (9000 ms) LK.setInterval(triggerClickAndJumpScare, 9000); // Optionally, trigger immediately at start triggerClickAndJumpScare(); // --- Random Event on Click: Zombie Attack, Door Close, Golden Zombie, Zombie --- // Helper overlays and logic for events var eventOverlay = LK.getAsset('flashOverlay', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 0 }); game.addChild(eventOverlay); var eventText = new Text2('', { size: 400, fill: 0x00ff00 }); eventText.anchor.set(0.5, 0.5); eventText.x = 2048 / 2; eventText.y = 2732 / 2; eventText.alpha = 0; game.addChild(eventText); // Golden zombie overlay var goldenZombieOverlay = LK.getAsset('flashOverlay', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 0 }); game.addChild(goldenZombieOverlay); var goldenZombieText = new Text2('GOLDEN ZOMBIE!', { size: 180, fill: 0xffd700 }); goldenZombieText.anchor.set(0.5, 0.5); goldenZombieText.x = 2048 / 2; goldenZombieText.y = 2732 / 2; goldenZombieText.alpha = 0; game.addChild(goldenZombieText); // Golden zombie picture overlay var goldenZombiePicOverlay = LK.getAsset('flashOverlay', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 0 }); game.addChild(goldenZombiePicOverlay); // Use a placeholder image for golden zombie picture (replace with real asset id if available) var goldenZombiePic = LK.getAsset('aiIndicator', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, scaleX: 2.2, scaleY: 2.2, alpha: 0 }); game.addChild(goldenZombiePic); // Zombie overlay var zombieOverlay = LK.getAsset('flashOverlay', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 0 }); game.addChild(zombieOverlay); var zombieText = new Text2('ZOMBIE!', { size: 220, fill: 0x00ff00 }); zombieText.anchor.set(0.5, 0.5); zombieText.x = 2048 / 2; zombieText.y = 2732 / 2; zombieText.alpha = 0; game.addChild(zombieText); // Door close overlay var doorOverlay = LK.getAsset('flashOverlay', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 0 }); game.addChild(doorOverlay); var doorText = new Text2('DOOR CLOSES!', { size: 220, fill: 0x888888 }); doorText.anchor.set(0.5, 0.5); doorText.x = 2048 / 2; doorText.y = 2732 / 2; doorText.alpha = 0; game.addChild(doorText); // Helper: show overlay + text, fade out after ms, then optional callback function showEventOverlay(overlay, textObj, color, text, textColor, duration, cb) { overlay.alpha = 0.92; textObj.setText(text); textObj.fill = textColor; textObj.alpha = 1; LK.setTimeout(function () { tween(overlay, { alpha: 0 }, { duration: 400, easing: tween.easeOut }); tween(textObj, { alpha: 0 }, { duration: 400, easing: tween.easeOut }); if (cb) LK.setTimeout(cb, 400); }, duration); } // Helper: show golden zombie, then zombie function showGoldenZombieThenZombie() { goldenZombieOverlay.alpha = 0.92; goldenZombieText.alpha = 1; LK.setTimeout(function () { tween(goldenZombieOverlay, { alpha: 0 }, { duration: 400, easing: tween.easeOut }); tween(goldenZombieText, { alpha: 0 }, { duration: 400, easing: tween.easeOut }); // After golden zombie, show zombie LK.setTimeout(function () { zombieOverlay.alpha = 0.92; zombieText.alpha = 1; LK.setTimeout(function () { tween(zombieOverlay, { alpha: 0 }, { duration: 400, easing: tween.easeOut }); tween(zombieText, { alpha: 0 }, { duration: 400, easing: tween.easeOut }); }, 700); }, 400); }, 900); } // Helper: show golden zombie picture, then zombie function showGoldenZombiePicThenZombie() { goldenZombiePicOverlay.alpha = 0.92; goldenZombiePic.alpha = 1; LK.setTimeout(function () { tween(goldenZombiePicOverlay, { alpha: 0 }, { duration: 400, easing: tween.easeOut }); tween(goldenZombiePic, { alpha: 0 }, { duration: 400, easing: tween.easeOut }); // After golden zombie picture, show zombie LK.setTimeout(function () { zombieOverlay.alpha = 0.92; zombieText.alpha = 1; LK.setTimeout(function () { tween(zombieOverlay, { alpha: 0 }, { duration: 400, easing: tween.easeOut }); tween(zombieText, { alpha: 0 }, { duration: 400, easing: tween.easeOut }); }, 700); }, 400); }, 900); } // Main random event handler var mazeActive = false; var mazeInstance = null; var pausedIntervals = []; function pauseAllIntervals() { // Pause all intervals by clearing them and storing their ids if (typeof window !== "undefined") return; // Defensive: not in browser // Not needed in LK, as intervals are not global, but we can set a flag if needed } function resumeAllIntervals() { // No-op for now, as LK intervals are not globally tracked } function handleRandomEvent() { // 1 in 6 chance to trigger maze mode if (!mazeActive && Math.random() < 0.17) { mazeActive = true; // Hide main UI numberCallText.alpha = 0.1; warningText.alpha = 0.1; jumpScareOverlay.alpha = 0; jumpScareText.alpha = 0; jumpScareOverlay2.alpha = 0; jumpScareText2.alpha = 0; eventOverlay.alpha = 0; eventText.alpha = 0; goldenZombieOverlay.alpha = 0; goldenZombieText.alpha = 0; goldenZombiePicOverlay.alpha = 0; goldenZombiePic.alpha = 0; zombieOverlay.alpha = 0; zombieText.alpha = 0; doorOverlay.alpha = 0; doorText.alpha = 0; // Create maze instance mazeInstance = new MazeMode(); mazeInstance.x = 0; mazeInstance.y = 0; mazeInstance.alpha = 1; game.addChild(mazeInstance); // Block main game input game.down = null; // Maze win callback mazeInstance.onWin = function () { // Remove maze, restore UI, resume game if (mazeInstance) { mazeInstance.destroy(); mazeInstance = null; } numberCallText.alpha = 1; warningText.alpha = 1; mazeActive = false; // Restore click handler game.down = function (x, y, obj) { handleRandomEvent(); }; }; // Forward touch events to maze game.down = function (x, y, obj) { if (mazeInstance && mazeInstance.down) mazeInstance.down(x, y, obj); }; game.up = function (x, y, obj) { if (mazeInstance && mazeInstance.up) mazeInstance.up(x, y, obj); }; game.move = function (x, y, obj) { if (mazeInstance && mazeInstance.move) mazeInstance.move(x, y, obj); }; return; } var eventType = Math.floor(Math.random() * 5); if (eventType === 0) { // Zombie attack showEventOverlay(eventOverlay, eventText, 0x00ff00, 'ZOMBIE ATTACK!', 0x00ff00, 900); } else if (eventType === 1) { // Door closes, then game over showEventOverlay(doorOverlay, doorText, 0x888888, 'DOOR CLOSES!', 0x888888, 900, function () { // Game over removed! No action here. }); } else if (eventType === 2) { // Golden zombie, then zombie showGoldenZombieThenZombie(); } else if (eventType === 3) { // Golden zombie picture, then zombie showGoldenZombiePicThenZombie(); } else { // Zombie showEventOverlay(zombieOverlay, zombieText, 0x00ff00, 'ZOMBIE!', 0x00ff00, 900); } } // --- World Time Clock Overlay --- // List of major cities and their UTC offsets (in hours) var worldClockCities = [{ name: "London", offset: 0 }, { name: "New York", offset: -4 }, { name: "Los Angeles", offset: -7 }, { name: "Tokyo", offset: 9 }, { name: "Sydney", offset: 10 }, { name: "Paris", offset: 2 }, { name: "Moscow", offset: 3 }, { name: "Beijing", offset: 8 }, { name: "Dubai", offset: 4 }, { name: "Rio", offset: -3 }]; // Overlay container for the world clock var worldClockContainer = new Container(); worldClockContainer.x = 2048 - 20; worldClockContainer.y = 20; worldClockContainer.alpha = 0.95; worldClockContainer.visible = false; game.addChild(worldClockContainer); // Background for the overlay var worldClockBg = LK.getAsset('calledNumbersBg', { width: 700, height: 60 + 60 * worldClockCities.length, anchorX: 1, anchorY: 0, x: 0, y: 0 }); worldClockBg.alpha = 0.92; worldClockContainer.addChild(worldClockBg); // Title var worldClockTitle = new Text2('World Clock', { size: 54, fill: 0x222222 }); worldClockTitle.anchor.set(1, 0); worldClockTitle.x = 660; worldClockTitle.y = 18; worldClockContainer.addChild(worldClockTitle); // City/time text objects var worldClockTextObjs = []; for (var i = 0; i < worldClockCities.length; i++) { var txt = new Text2('', { size: 44, fill: 0x181a1b }); txt.anchor.set(1, 0); txt.x = 660; txt.y = 60 + i * 54; worldClockContainer.addChild(txt); worldClockTextObjs.push(txt); } // Helper to update the times function updateWorldClockTimes() { var now = new Date(); for (var i = 0; i < worldClockCities.length; i++) { var city = worldClockCities[i]; // Calculate local time for city var utc = now.getTime() + now.getTimezoneOffset() * 60000; var cityTime = new Date(utc + 3600000 * city.offset); var h = cityTime.getHours(); var m = cityTime.getMinutes(); var s = cityTime.getSeconds(); var timeStr = (h < 10 ? "0" : "") + h + ":" + (m < 10 ? "0" : "") + m + ":" + (s < 10 ? "0" : "") + s; worldClockTextObjs[i].setText(city.name + ": " + timeStr); } } // Hide after a few seconds function hideWorldClock() { tween(worldClockContainer, { alpha: 0 }, { duration: 400, easing: tween.easeOut, onComplete: function onComplete() { worldClockContainer.visible = false; worldClockContainer.alpha = 0.95; } }); } // Show the world clock overlay function showWorldClock() { updateWorldClockTimes(); worldClockContainer.visible = true; worldClockContainer.alpha = 0.95; // Animate in tween(worldClockContainer, { alpha: 0.95 }, { duration: 200 }); // Hide after 3.5 seconds LK.setTimeout(hideWorldClock, 3500); } // Update times every second if visible LK.setInterval(function () { if (worldClockContainer.visible) updateWorldClockTimes(); }, 1000); // Listen for click/tap on the game area // --- GeoGuessr Interruption Logic --- var geoGuessrActive = false; var geoGuessrCode = null; var geoGuessrOverlay = null; var geoGuessrInput = null; var geoGuessrSubmitBtn = null; var geoGuessrMsg = null; var geoGuessrReturnHandler = null; // Helper: Generate a random 4-digit code function generateGeoGuessrCode() { return "" + (1000 + Math.floor(Math.random() * 9000)); } // Helper: Show overlay for code entry function showGeoGuessrReturnOverlay(code) { if (geoGuessrOverlay) geoGuessrOverlay.destroy(); geoGuessrOverlay = new Container(); geoGuessrOverlay.x = 0; geoGuessrOverlay.y = 0; geoGuessrOverlay.alpha = 1; // Dim background var bg = LK.getAsset('flashOverlay', { anchorX: 0, anchorY: 0, x: 0, y: 0, alpha: 0.92 }); geoGuessrOverlay.addChild(bg); // Message geoGuessrMsg = new Text2("Enter the code to return:\n" + code, { size: 120, fill: 0x222222 }); geoGuessrMsg.anchor.set(0.5, 0); geoGuessrMsg.x = 2048 / 2; geoGuessrMsg.y = 700; geoGuessrOverlay.addChild(geoGuessrMsg); // Input box (simulate with Text2, user taps to increment digits) geoGuessrInput = new Text2("----", { size: 180, fill: 0x000000 }); geoGuessrInput.anchor.set(0.5, 0.5); geoGuessrInput.x = 2048 / 2; geoGuessrInput.y = 1200; geoGuessrOverlay.addChild(geoGuessrInput); // Simulate input: tap to cycle digits var inputDigits = [0, 0, 0, 0]; var inputPos = 0; function updateInputText() { var s = ""; for (var i = 0; i < 4; i++) s += typeof inputDigits[i] === "number" ? inputDigits[i] : "-"; geoGuessrInput.setText(s); } updateInputText(); geoGuessrInput.down = function (x, y, obj) { inputDigits[inputPos] = ((inputDigits[inputPos] || 0) + 1) % 10; updateInputText(); }; geoGuessrInput.up = function (x, y, obj) { inputPos = (inputPos + 1) % 4; }; // Submit button geoGuessrSubmitBtn = LK.getAsset('buttonHover', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1500 }); geoGuessrOverlay.addChild(geoGuessrSubmitBtn); var submitText = new Text2("SUBMIT", { size: 90, fill: 0xffffff }); submitText.anchor.set(0.5, 0.5); submitText.x = 2048 / 2; submitText.y = 1500; geoGuessrOverlay.addChild(submitText); geoGuessrSubmitBtn.down = function (x, y, obj) { var guess = ""; for (var i = 0; i < 4; i++) guess += inputDigits[i]; if (guess === code) { // Success! if (geoGuessrOverlay) { geoGuessrOverlay.destroy(); geoGuessrOverlay = null; } geoGuessrActive = false; // Restore game click handler game.down = geoGuessrReturnHandler; } else { geoGuessrMsg.setText("Wrong! Try again.\n" + code); LK.effects.flashObject(geoGuessrInput, 0xff0000, 200); } }; // Add overlay to game game.addChild(geoGuessrOverlay); // Forward input events game.down = function (x, y, obj) { if (geoGuessrInput && geoGuessrInput.down) geoGuessrInput.down(x, y, obj); if (geoGuessrSubmitBtn && geoGuessrSubmitBtn.down) { // Check if tap is on button var bx = geoGuessrSubmitBtn.x, by = geoGuessrSubmitBtn.y; var bw = geoGuessrSubmitBtn.width || 220, bh = geoGuessrSubmitBtn.height || 90; if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) { geoGuessrSubmitBtn.down(x, y, obj); } } }; game.up = function (x, y, obj) { if (geoGuessrInput && geoGuessrInput.up) geoGuessrInput.up(x, y, obj); }; game.move = function (x, y, obj) {}; } // Helper: Open GeoGuessr in a new tab function openGeoGuessr() { // Defensive: try to open in new tab if (typeof window !== "undefined" && window.open) { window.open("https://www.geoguessr.com/", "_blank"); } } // --- Italian Brain Rot Overlay and Logic --- var italianBrainRotOverlay = LK.getAsset('flashOverlay', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 0 }); game.addChild(italianBrainRotOverlay); var italianBrainRotTexts = ["MAMMA MIA!", "PASTA! PIZZA! MANDOLINO!", "SPAGHETTI TIME!", "CIAO BELLA!", "BENVENUTO AL BRAIN ROT!", "MOZZARELLA! FORMAGGIO!", "ITALIANO VERO!", "ANDIAMO!", "BADA BING BADA BOOM!", "MACCHERONI MADNESS!"]; var italianBrainRotTextObj = new Text2('', { size: 220, fill: 0x2e86c1 }); italianBrainRotTextObj.anchor.set(0.5, 0.5); italianBrainRotTextObj.x = 2048 / 2; italianBrainRotTextObj.y = 2732 / 2; italianBrainRotTextObj.alpha = 0; game.addChild(italianBrainRotTextObj); function triggerItalianBrainRot() { // Pick a random phrase var idx = Math.floor(Math.random() * italianBrainRotTexts.length); italianBrainRotTextObj.setText(italianBrainRotTexts[idx]); italianBrainRotOverlay.alpha = 0.92; italianBrainRotTextObj.alpha = 1; // Animate out after 1.1s LK.setTimeout(function () { tween(italianBrainRotOverlay, { alpha: 0 }, { duration: 400, easing: tween.easeOut }); tween(italianBrainRotTextObj, { alpha: 0 }, { duration: 400, easing: tween.easeOut }); }, 1100); } // --- Random Text Overlay Logic --- var randomTextOverlay = LK.getAsset('flashOverlay', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 0 }); game.addChild(randomTextOverlay); var randomTextList = ["SURPRISE!", "HELLO THERE!", "WHAT'S GOING ON?", "RANDOM EVENT!", "YOU CLICKED!", "BOO!", "WOW!", "KEEP GOING!", "NICE CLICK!", "ARE YOU HAVING FUN?", "LUCKY CLICK!", "TRY AGAIN!", "MAGIC!", "MYSTERY!", "SECRET MESSAGE!", "DON'T STOP!", "ALMOST THERE!", "SO CLOSE!", "AMAZING!", "COOL!", "BINGO!", "ZAP!", "POW!", "YAY!", "AWESOME!", "GREAT JOB!"]; var randomTextObj = new Text2('', { size: 200, fill: 0x00aaff }); randomTextObj.anchor.set(0.5, 0.5); randomTextObj.x = 2048 / 2; randomTextObj.y = 2732 / 2; randomTextObj.alpha = 0; game.addChild(randomTextObj); function showRandomTextOverlay() { var idx = Math.floor(Math.random() * randomTextList.length); randomTextObj.setText(randomTextList[idx]); randomTextOverlay.alpha = 0.92; randomTextObj.alpha = 1; LK.setTimeout(function () { tween(randomTextOverlay, { alpha: 0 }, { duration: 400, easing: tween.easeOut }); tween(randomTextObj, { alpha: 0 }, { duration: 400, easing: tween.easeOut }); }, 1100); } // Main click handler game.down = function (x, y, obj) { // 1 in 7 chance to trigger GeoGuessr interruption var triggerGeoGuessr = Math.random() < 0.14 && !geoGuessrActive; if (triggerGeoGuessr) { geoGuessrActive = true; geoGuessrCode = generateGeoGuessrCode(); geoGuessrReturnHandler = arguments.callee; // Save for restore // Hide main UI numberCallText.alpha = 0.1; warningText.alpha = 0.1; // Open GeoGuessr in new tab openGeoGuessr(); // Show overlay for code entry showGeoGuessrReturnOverlay(geoGuessrCode); return; } // 90% chance to open a random appropriate website if (Math.random() < 0.90) { // List of appropriate, family-friendly websites var safeWebsites = ["https://www.nationalgeographic.com/", "https://www.khanacademy.org/", "https://www.coolmathgames.com/", "https://www.funbrain.com/", "https://www.britannica.com/", "https://www.nasa.gov/kidsclub/index.html", "https://www.ducksters.com/", "https://www.pbskids.org/", "https://www.sesamestreet.org/", "https://www.highlightskids.com/"]; var siteIdx = Math.floor(Math.random() * safeWebsites.length); var url = safeWebsites[siteIdx]; // Defensive: try to open in new tab if possible if (typeof window !== "undefined" && window.open) { window.open(url, "_blank"); } // Optionally, show a random text overlay to indicate something happened showRandomTextOverlay(); return; } // 1 in 8 chance to trigger Italian brain rot var triggerItalian = Math.random() < 0.125; if (triggerItalian) { triggerItalianBrainRot(); return; } // Always play a random fart noise on click var fartSounds = ['fart1', 'fart2', 'fart3', 'fart4', 'fart5', 'fart6', 'fart7']; var fartIdx = Math.floor(Math.random() * fartSounds.length); var fartSound = LK.getSound(fartSounds[fartIdx]); if (fartSound) fartSound.play(); // 1 in 4.5 chance to show a random text overlay if (Math.random() < 0.222) { showRandomTextOverlay(); return; } // Only trigger the random event on ~1 in 4 clicks var showClock = Math.random() < 0.18; // ~1 in 5.5 clicks var showEvent = Math.random() < 0.25; // 1 in 3.5 clicks, play a random annoying sound var playAnnoyingSound = Math.random() < 0.285; if (playAnnoyingSound) { // 1 in 5 of those times, play the 'tongue, tongue, tongue' sound (let's use ses32 for this effect) if (Math.random() < 0.2) { var tongueSound = LK.getSound('ses32'); if (tongueSound) tongueSound.play(); } else if (Math.random() < 0.25) { // 1 in 4 of the remaining times, play the 'dum dum dum dum dum dum dum' sound (let's use ses31 for this effect) var dumSound = LK.getSound('ses31'); if (dumSound) dumSound.play(); } else { // List of annoying/horrible sound ids (pffft, fart, screech, etc. - use ses41-ses75 as 'horrible' pool) var annoyingSounds = ['ses41', 'ses42', 'ses43', 'ses44', 'ses45', 'ses46', 'ses47', 'ses48', 'ses49', 'ses50', 'ses51', 'ses52', 'ses53', 'ses54', 'ses55', 'ses56', 'ses57', 'ses58', 'ses59', 'ses60', 'ses61', 'ses62', 'ses64', 'ses65', 'ses66', 'ses67', 'ses68', 'ses69', 'ses70', 'ses71', 'ses72', 'ses75']; var idx = Math.floor(Math.random() * annoyingSounds.length); var sound = LK.getSound(annoyingSounds[idx]); if (sound) sound.play(); } } // 1 in 4 clicks, play a random song var playRandomSong = Math.random() < 0.25; if (playRandomSong) { // List of appropriate, family-friendly music ids only (no explicit lyrics, safe for all ages) // These are demo placeholders; in a real game, use only tracks that are verified as clean and suitable. var songIds = ['ses1', // Confirmed: simple melody 'ses2', // Confirmed: cheerful jingle 'ses3', // Confirmed: upbeat instrumental 'ses4', // Confirmed: playful tune 'ses5', // Confirmed: light background 'ses6', // Confirmed: happy chime 'ses7', // Confirmed: fun sound 'ses8', // Confirmed: short melody 'ses9', // Confirmed: positive instrumental 'ses10' // Confirmed: safe, no lyrics ]; var songIdx = Math.floor(Math.random() * songIds.length); var songId = songIds[songIdx]; // Play as music (will stop any currently playing music) LK.playMusic(songId, { loop: false }); } if (showClock) { showWorldClock(); } else if (showEvent) { handleRandomEvent(); } }; // --- Animated background color pulse for visual appeal --- var bgPulseColors = [0x181a1b, // near-black 0x23272a, // dark gray 0x222326, // blackish blue 0x181a1b, // repeat for smooth loop 0x23272a]; // Blackish/dark palette var bgPulseIndex = 0; var bgPulseDuration = 3000; function pulseBackground() { var fromColor = bgPulseColors[bgPulseIndex]; var toColor = bgPulseColors[(bgPulseIndex + 1) % bgPulseColors.length]; var t = { v: 0 }; tween(t, { v: 1 }, { duration: bgPulseDuration, easing: tween.easeInOut, onUpdate: function onUpdate() { // Interpolate color var r1 = fromColor >> 16 & 0xff, g1 = fromColor >> 8 & 0xff, b1 = fromColor & 0xff; var r2 = toColor >> 16 & 0xff, g2 = toColor >> 8 & 0xff, b2 = toColor & 0xff; var r = Math.round(r1 + (r2 - r1) * t.v); var g = Math.round(g1 + (g2 - g1) * t.v); var b = Math.round(b1 + (b2 - b1) * t.v); var color = r << 16 | g << 8 | b; game.setBackgroundColor(color); }, onComplete: function onComplete() { bgPulseIndex = (bgPulseIndex + 1) % bgPulseColors.length; pulseBackground(); } }); } pulseBackground(); // --- Golden Sign Event: Every 9-100 years, show golden sign with age message --- // Helper: returns ms for N years (365.25 days per year) function yearsToMs(years) { return Math.floor(years * 365.25 * 24 * 60 * 60 * 1000); } // Track game start time (ms) var gameStartTime = Date.now(); // Golden sign overlay and text var goldenSignOverlay = LK.getAsset('flashOverlay', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 0 }); game.addChild(goldenSignOverlay); var goldenSignText = new Text2('', { size: 180, fill: 0xffd700 }); goldenSignText.anchor.set(0.5, 0.5); goldenSignText.x = 2048 / 2; goldenSignText.y = 2732 / 2; goldenSignText.alpha = 0; game.addChild(goldenSignText); // Helper: show golden sign with message function showGoldenSign(message) { goldenSignOverlay.alpha = 0.95; goldenSignText.setText(message); goldenSignText.fill = 0xffd700; goldenSignText.alpha = 1; LK.setTimeout(function () { tween(goldenSignOverlay, { alpha: 0 }, { duration: 1200, easing: tween.easeOut }); tween(goldenSignText, { alpha: 0 }, { duration: 1200, easing: tween.easeOut }); }, 2200); } // Helper: pick a random integer in [a, b] function randInt(a, b) { return a + Math.floor(Math.random() * (b - a + 1)); } // Schedule the first golden sign event var nextGoldenSignYears = randInt(9, 10 + Math.floor(Math.random() * 91)); // 9-100 or 10-100 years var nextGoldenSignTime = gameStartTime + yearsToMs(nextGoldenSignYears); // Track how many golden sign events have occurred var goldenSignEventCount = 0; // Periodically check if it's time to show the golden sign LK.setInterval(function () { var now = Date.now(); if (now >= nextGoldenSignTime) { // Compute "age" for fun message var yearsElapsed = Math.floor((now - gameStartTime) / yearsToMs(1)); var fakeAge = 600 + goldenSignEventCount * randInt(1, 100); showGoldenSign("How old are you now? You're probably " + fakeAge + "!"); goldenSignEventCount++; // Schedule next event in 9-100 or 10-100 years var nextYears = randInt(9, 10 + Math.floor(Math.random() * 91)); nextGoldenSignTime = now + yearsToMs(nextYears); } }, 10000); // Check every 10 seconds (safe, since event is ultra-rare);
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// AI Robot: Simple animated character that moves left and right
var AIRobot = Container.expand(function () {
var self = Container.call(this);
// Attach a robot body (use aiIndicator image as the robot's head/body)
var robotBody = self.attachAsset('aiIndicator', {
anchorX: 0.5,
anchorY: 0.5
});
// Add two "eyes" using small ellipses
var leftEye = self.attachAsset('freeSpace', {
width: 24,
height: 24,
color: 0xffffff,
anchorX: 0.5,
anchorY: 0.5
});
var rightEye = self.attachAsset('freeSpace', {
width: 24,
height: 24,
color: 0xffffff,
anchorX: 0.5,
anchorY: 0.5
});
leftEye.x = -36;
leftEye.y = -20;
rightEye.x = 36;
rightEye.y = -20;
// Animation state
self.direction = 1; // 1: right, -1: left
self.speed = 6 + Math.random() * 4; // px per frame
self.minX = 200;
self.maxX = 2048 - 200;
// For eye animation
self.eyeTick = 0;
// Initial position
self.x = 2048 * 3 / 4;
self.y = 2732 - 180;
// Update method for movement and eye animation
self.update = function () {
// Move left/right
self.x += self.direction * self.speed;
if (self.x > self.maxX) {
self.x = self.maxX;
self.direction = -1;
}
if (self.x < self.minX) {
self.x = self.minX;
self.direction = 1;
}
// Animate eyes (look in direction of movement)
self.eyeTick++;
var eyeOffset = 4 * self.direction + Math.sin(self.eyeTick / 10) * 2;
leftEye.x = -36 + eyeOffset;
rightEye.x = 36 + eyeOffset;
};
return self;
});
// BingoCell: Represents a single cell on the bingo card
var BingoCell = Container.expand(function () {
var self = Container.call(this);
// Properties
self.number = 0;
self.marked = false;
// Create cell background
var cellBg = self.attachAsset('bingoCellBg', {
width: cellSize,
height: cellSize,
anchorX: 0.5,
anchorY: 0.5
});
// Number text
var numberText = new Text2('', {
size: Math.floor(cellSize * 0.45),
fill: 0xffffff
});
numberText.anchor.set(0.5, 0.5);
self.addChild(numberText);
// Mark overlay (hidden by default)
var markOverlay = self.attachAsset('bingoMark', {
width: cellSize * 0.7,
height: cellSize * 0.7,
anchorX: 0.5,
anchorY: 0.5
});
markOverlay.alpha = 0;
self.markOverlay = markOverlay;
// Set number and update text
self.setNumber = function (num) {
self.number = num;
numberText.setText(num > 0 ? num : '');
};
// Mark/unmark cell
self.setMarked = function (val) {
self.marked = val;
if (val) {
tween(markOverlay, {
alpha: 0.8
}, {
duration: 200,
easing: tween.easeOut
});
numberText.setText(self.number);
numberText.setStyle({
fill: 0x000000
});
} else {
tween(markOverlay, {
alpha: 0
}, {
duration: 200,
easing: tween.easeOut
});
numberText.setStyle({
fill: 0xffffff
});
}
};
// Touch event
self.down = function (x, y, obj) {
// Play click sound on any cell tap
LK.getSound('Click').play();
if (self.marked) return;
if (game.state !== 'playing') return;
var p = self.playerIndex !== undefined ? self.playerIndex : 0;
if (self.number === game.currentNumber && p === currentPlayer) {
self.setMarked(true);
LK.effects.flashObject(self, 0xff6600, 200);
// Streak logic
if (typeof streak !== "undefined") {
streak[p]++;
streakText[p].setText("Streak: " + streak[p]);
if (streak[p] > 1) {
// Bonus: add 1s per streak above 1
timeLeft[p] += 1000;
tween(streakText[p], {
scaleX: 1.3,
scaleY: 1.3
}, {
duration: 100,
yoyo: true,
repeat: 1,
easing: tween.easeOut
});
}
}
game.checkWin();
} else {
if (typeof streak !== "undefined") {
streak[p] = 0;
streakText[p].setText("");
}
LK.effects.flashObject(self, 0x8b0000, 200);
}
};
// Example: Trigger action when cell crosses X = 1000 from left to right
if (self.lastX !== undefined && self.lastX <= 1000 && self.x > 1000) {
// Place your action here, e.g. console.log("Cell crossed X=1000!");
}
// Always update lastX at the end
self.lastX = self.x;
// Example: Trigger action when cell crosses Y = 800 from above to below
if (self.lastY !== undefined && self.lastY <= 800 && self.y > 800) {
// Place your action here, e.g. console.log("Cell crossed Y=800!");
}
// Always update lastY at the end
self.lastY = self.y;
// Example: Trigger action when cell crosses X=1000 and Y=800 at the same frame
if (self.lastY !== undefined && self.lastY <= 800 && self.y > 800 && self.lastX !== undefined && self.lastX <= 1000 && self.x > 1000) {
// Place your action here, e.g. console.log("Cell arrived at (1000,800)!");
}
// Always update lastX and lastY at the end
self.lastX = self.x;
self.lastY = self.y;
return self;
});
// CalledNumberBall: Shows a called number as a round ball
var CalledNumberBall = Container.expand(function () {
var self = Container.call(this);
// Ball background
var ball = self.attachAsset('bingoBall', {
anchorX: 0.5,
anchorY: 0.5
});
// Number text
var numberText = new Text2('', {
size: 60,
fill: 0x000000
});
numberText.anchor.set(0.5, 0.5);
numberText.x = 0;
numberText.y = 0;
self.addChild(numberText);
self.setNumber = function (num) {
numberText.setText(num);
};
return self;
});
// MazeMode: Simple maze mini-game overlay
var MazeMode = Container.expand(function () {
var self = Container.call(this);
// Maze config
var mazeCols = 7;
var mazeRows = 9;
var cellW = Math.floor(2048 / mazeCols);
var cellH = Math.floor(1800 / mazeRows);
var offsetX = Math.floor((2048 - mazeCols * cellW) / 2);
var offsetY = 400;
// Maze grid: 0 = open, 1 = wall
self.grid = [];
// Generate a simple random maze (DFS backtracker)
function generateMaze(cols, rows) {
var grid = [];
for (var y = 0; y < rows; y++) {
var row = [];
for (var x = 0; x < cols; x++) row.push(1);
grid.push(row);
}
function carve(x, y) {
grid[y][x] = 0;
var dirs = [[0, 1], [1, 0], [0, -1], [-1, 0]];
for (var i = 0; i < 4; i++) {
var j = Math.floor(Math.random() * 4);
var tmp = dirs[i];
dirs[i] = dirs[j];
dirs[j] = tmp;
}
for (var d = 0; d < 4; d++) {
var nx = x + dirs[d][0] * 2,
ny = y + dirs[d][1] * 2;
if (nx >= 0 && nx < cols && ny >= 0 && ny < rows && grid[ny][nx] === 1) {
grid[y + dirs[d][1]][x + dirs[d][0]] = 0;
carve(nx, ny);
}
}
}
carve(1, 1);
grid[1][1] = 0; // Start
grid[rows - 2][cols - 2] = 0; // End
return grid;
}
self.grid = generateMaze(mazeCols, mazeRows);
// Draw maze
self.cells = [];
for (var y = 0; y < mazeRows; y++) {
for (var x = 0; x < mazeCols; x++) {
if (self.grid[y][x] === 1) {
var wall = LK.getAsset('calledNumbersBg', {
width: cellW - 8,
height: cellH - 8,
anchorX: 0,
anchorY: 0,
x: offsetX + x * cellW + 4,
y: offsetY + y * cellH + 4
});
self.addChild(wall);
self.cells.push(wall);
}
}
}
// Start and end
var startX = 1,
startY = 1;
var endX = mazeCols - 2,
endY = mazeRows - 2;
var startCell = LK.getAsset('freeSpace', {
width: cellW - 12,
height: cellH - 12,
anchorX: 0,
anchorY: 0,
x: offsetX + startX * cellW + 6,
y: offsetY + startY * cellH + 6
});
startCell.alpha = 0.7;
self.addChild(startCell);
var endCell = LK.getAsset('winHighlight', {
width: cellW - 12,
height: cellH - 12,
anchorX: 0,
anchorY: 0,
x: offsetX + endX * cellW + 6,
y: offsetY + endY * cellH + 6
});
endCell.alpha = 0.7;
self.addChild(endCell);
// Player
self.playerX = startX;
self.playerY = startY;
self.player = LK.getAsset('aiIndicator', {
width: cellW - 24,
height: cellH - 24,
anchorX: 0,
anchorY: 0,
x: offsetX + self.playerX * cellW + 12,
y: offsetY + self.playerY * cellH + 12
});
self.addChild(self.player);
// Touch controls: swipe or tap to move
self.touchStartX = null;
self.touchStartY = null;
self.touching = false;
// Helper: move player if possible
self.tryMove = function (dx, dy) {
var nx = self.playerX + dx,
ny = self.playerY + dy;
if (nx >= 0 && nx < mazeCols && ny >= 0 && ny < mazeRows) {
if (self.grid[ny][nx] === 0) {
self.playerX = nx;
self.playerY = ny;
self.player.x = offsetX + self.playerX * cellW + 12;
self.player.y = offsetY + self.playerY * cellH + 12;
// Win check
if (self.playerX === endX && self.playerY === endY) {
if (typeof self.onWin === "function") self.onWin();
}
} else {
// Bump event: every time you try to move into a wall
LK.effects.flashObject(self.player, 0xff0000, 150);
}
}
};
// Touch events
self.down = function (x, y, obj) {
self.touchStartX = x;
self.touchStartY = y;
self.touching = true;
};
self.up = function (x, y, obj) {
if (!self.touching) return;
var dx = x - self.touchStartX;
var dy = y - self.touchStartY;
if (Math.abs(dx) > Math.abs(dy)) {
if (dx > 40) self.tryMove(1, 0);else if (dx < -40) self.tryMove(-1, 0);
} else {
if (dy > 40) self.tryMove(0, 1);else if (dy < -40) self.tryMove(0, -1);
}
self.touching = false;
};
// Also allow tap on adjacent cell
self.move = function (x, y, obj) {};
// Overlay text
var mazeText = new Text2('Maze! Reach the yellow cell!', {
size: 90,
fill: 0xffd700
});
mazeText.anchor.set(0.5, 1);
mazeText.x = 2048 / 2;
mazeText.y = offsetY - 30;
self.addChild(mazeText);
// Win callback (set externally)
self.onWin = null;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181a1b
});
/****
* Game Code
****/
// Fart sound effects (using available ses54, ses55, ses56, ses57, ses58, ses59, ses60 as fart-like sounds)
// --- Added ses41 to ses75 sound assets (IDs to be filled by asset loader) ---
// Save the current game state (called numbers, card numbers, marked cells, time left, streaks)
// All bingo card and bingo cell logic removed as requested.
// Bingo ball (yellow ellipse)
// Bingo cell background (cyan box)
// Mark overlay (beige box, used for marking cells)
// Hint button background (green box, used for hint power-up)
// Free space overlay (distinct color for center cell)
// Win highlight overlay (gold ellipse for winning line)
// Reveal Row button removed
// Freeze Timer button and logic removed
// Ses assets for ses1 to ses40
var gridSize = 5; // 5x5 bingo
// Adjust cellSize and card positions for two-player mode to fit both cards on screen
var cellSize = 180; // px, reduced to fit two cards side by side
var cardPadding = 30;
var cardWidth = gridSize * cellSize;
var cardHeight = gridSize * cellSize;
var cardStartX = 2048 / 4 - cardWidth / 2; // Player 1 card center at 1/4 width, Player 2 at 3/4 width
var cardStartY = 500; // Lowered to fit both cards and UI
var callIntervalStart = 4000; // ms (4 seconds initial call speed)
var callIntervalMin = 1200; // ms (slower minimum speed)
var callIntervalStep = 60; // ms, decrease per call (slower speedup)
var gameDuration = 225000; // ms (3 min 45 sec)
var numbersRange = 75; // 1-75
// Remove all bingo logic and display random numbers on screen repeatedly
// Create a big number text in the center
var numberCallText = new Text2('', {
size: 400,
fill: 0xff073a
});
numberCallText.anchor.set(0.5, 0.5);
numberCallText.x = 2048 / 2;
numberCallText.y = 2732 / 2;
game.addChild(numberCallText);
// Add a warning text in the center, above the number
var warningText = new Text2('click, something will happen.', {
size: 120,
fill: 0xff0000
});
warningText.anchor.set(0.5, 1);
warningText.x = 2048 / 2;
warningText.y = 2732 / 2 - 260;
game.addChild(warningText);
// Function to show a random number and play its sound
// List of number translations for 1-20 in various languages, then fallback to English for higher numbers
var numberLanguages = [{
lang: "English",
words: ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"]
}, {
lang: "Spanish",
words: ["uno", "dos", "tres", "cuatro", "cinco", "seis", "siete", "ocho", "nueve", "diez", "once", "doce", "trece", "catorce", "quince", "dieciséis", "diecisiete", "dieciocho", "diecinueve", "veinte"]
}, {
lang: "French",
words: ["un", "deux", "trois", "quatre", "cinq", "six", "sept", "huit", "neuf", "dix", "onze", "douze", "treize", "quatorze", "quinze", "seize", "dix-sept", "dix-huit", "dix-neuf", "vingt"]
}, {
lang: "German",
words: ["eins", "zwei", "drei", "vier", "fünf", "sechs", "sieben", "acht", "neun", "zehn", "elf", "zwölf", "dreizehn", "vierzehn", "fünfzehn", "sechzehn", "siebzehn", "achtzehn", "neunzehn", "zwanzig"]
}, {
lang: "Italian",
words: ["uno", "due", "tre", "quattro", "cinque", "sei", "sette", "otto", "nove", "dieci", "undici", "dodici", "tredici", "quattordici", "quindici", "sedici", "diciassette", "diciotto", "diciannove", "venti"]
}, {
lang: "Turkish",
words: ["bir", "iki", "üç", "dört", "beş", "altı", "yedi", "sekiz", "dokuz", "on", "on bir", "on iki", "on üç", "on dört", "on beş", "on altı", "on yedi", "on sekiz", "on dokuz", "yirmi"]
}, {
lang: "Russian",
words: ["один", "два", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять", "десять", "одиннадцать", "двенадцать", "тринадцать", "четырнадцать", "пятнадцать", "шестнадцать", "семнадцать", "восемнадцать", "девятнадцать", "двадцать"]
}, {
lang: "Japanese",
words: ["いち", "に", "さん", "よん", "ご", "ろく", "なな", "はち", "きゅう", "じゅう", "じゅういち", "じゅうに", "じゅうさん", "じゅうよん", "じゅうご", "じゅうろく", "じゅうなな", "じゅうはち", "じゅうきゅう", "にじゅう"]
}, {
lang: "Chinese",
words: ["一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十"]
}];
var lastLangIndex = -1;
function showRandomNumber() {
var num = 1 + Math.floor(Math.random() * 75);
// Pick a language different from last time
var langIndex;
do {
langIndex = Math.floor(Math.random() * numberLanguages.length);
} while (langIndex === lastLangIndex && numberLanguages.length > 1);
lastLangIndex = langIndex;
var langObj = numberLanguages[langIndex];
var displayText = "";
if (num <= 20) {
displayText = langObj.words[num - 1];
// Show the number in digits below in smaller font for clarity
numberCallText.setText(displayText + "\n" + num);
numberCallText.setStyle({
size: 320
});
} else {
// For numbers > 20, show the number in digits and the language name
displayText = num + " (" + langObj.lang + ")";
numberCallText.setText(displayText);
numberCallText.setStyle({
size: 400
});
}
// Play ses1-ses75 sound if available
var soundId = 'ses' + num;
var sound = LK.getSound(soundId);
if (sound) sound.play();
// Animate the number
numberCallText.scale.x = 0.7;
numberCallText.scale.y = 0.7;
tween(numberCallText.scale, {
x: 1,
y: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
// Call a new number every 2 seconds
LK.setInterval(showRandomNumber, 2000);
// Show the first number immediately
showRandomNumber();
// --- Jump Scare Overlay and Logic ---
var jumpScareOverlay = LK.getAsset('flashOverlay', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 0
});
game.addChild(jumpScareOverlay);
// Optionally, you can add a scary text
var jumpScareText = new Text2('!', {
size: 600,
fill: 0xff0000
});
jumpScareText.anchor.set(0.5, 0.5);
jumpScareText.x = 2048 / 2;
jumpScareText.y = 2732 / 2;
jumpScareText.alpha = 0;
game.addChild(jumpScareText);
function triggerJumpScare() {
// Flash overlay and text in
jumpScareOverlay.alpha = 0.92;
jumpScareText.alpha = 1;
// Animate out after 600ms
LK.setTimeout(function () {
tween(jumpScareOverlay, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
tween(jumpScareText, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
}, 600);
}
// --- Second Jump Scare Overlay (Question Mark) and Logic ---
var jumpScareOverlay2 = LK.getAsset('flashOverlay', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 0
});
game.addChild(jumpScareOverlay2);
var jumpScareText2 = new Text2('?', {
size: 600,
fill: 0x00aaff
});
jumpScareText2.anchor.set(0.5, 0.5);
jumpScareText2.x = 2048 / 2;
jumpScareText2.y = 2732 / 2;
jumpScareText2.alpha = 0;
game.addChild(jumpScareText2);
function triggerJumpScare2() {
// Flash overlay and text in
jumpScareOverlay2.alpha = 0.92;
jumpScareText2.alpha = 1;
// Animate out after 600ms
LK.setTimeout(function () {
tween(jumpScareOverlay2, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
tween(jumpScareText2, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
}, 600);
}
// Schedule the question mark jump scare every 3 seconds
LK.setInterval(triggerJumpScare2, 3000);
// Schedule both click sound and jump scare every 9 seconds, in sync
function triggerClickAndJumpScare() {
// Play click sound
var clickSound = LK.getSound('Click');
if (clickSound) clickSound.play();
// Trigger jump scare
triggerJumpScare();
}
// Call every 9 seconds (9000 ms)
LK.setInterval(triggerClickAndJumpScare, 9000);
// Optionally, trigger immediately at start
triggerClickAndJumpScare();
// --- Random Event on Click: Zombie Attack, Door Close, Golden Zombie, Zombie ---
// Helper overlays and logic for events
var eventOverlay = LK.getAsset('flashOverlay', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 0
});
game.addChild(eventOverlay);
var eventText = new Text2('', {
size: 400,
fill: 0x00ff00
});
eventText.anchor.set(0.5, 0.5);
eventText.x = 2048 / 2;
eventText.y = 2732 / 2;
eventText.alpha = 0;
game.addChild(eventText);
// Golden zombie overlay
var goldenZombieOverlay = LK.getAsset('flashOverlay', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 0
});
game.addChild(goldenZombieOverlay);
var goldenZombieText = new Text2('GOLDEN ZOMBIE!', {
size: 180,
fill: 0xffd700
});
goldenZombieText.anchor.set(0.5, 0.5);
goldenZombieText.x = 2048 / 2;
goldenZombieText.y = 2732 / 2;
goldenZombieText.alpha = 0;
game.addChild(goldenZombieText);
// Golden zombie picture overlay
var goldenZombiePicOverlay = LK.getAsset('flashOverlay', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 0
});
game.addChild(goldenZombiePicOverlay);
// Use a placeholder image for golden zombie picture (replace with real asset id if available)
var goldenZombiePic = LK.getAsset('aiIndicator', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 2.2,
scaleY: 2.2,
alpha: 0
});
game.addChild(goldenZombiePic);
// Zombie overlay
var zombieOverlay = LK.getAsset('flashOverlay', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 0
});
game.addChild(zombieOverlay);
var zombieText = new Text2('ZOMBIE!', {
size: 220,
fill: 0x00ff00
});
zombieText.anchor.set(0.5, 0.5);
zombieText.x = 2048 / 2;
zombieText.y = 2732 / 2;
zombieText.alpha = 0;
game.addChild(zombieText);
// Door close overlay
var doorOverlay = LK.getAsset('flashOverlay', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 0
});
game.addChild(doorOverlay);
var doorText = new Text2('DOOR CLOSES!', {
size: 220,
fill: 0x888888
});
doorText.anchor.set(0.5, 0.5);
doorText.x = 2048 / 2;
doorText.y = 2732 / 2;
doorText.alpha = 0;
game.addChild(doorText);
// Helper: show overlay + text, fade out after ms, then optional callback
function showEventOverlay(overlay, textObj, color, text, textColor, duration, cb) {
overlay.alpha = 0.92;
textObj.setText(text);
textObj.fill = textColor;
textObj.alpha = 1;
LK.setTimeout(function () {
tween(overlay, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
tween(textObj, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
if (cb) LK.setTimeout(cb, 400);
}, duration);
}
// Helper: show golden zombie, then zombie
function showGoldenZombieThenZombie() {
goldenZombieOverlay.alpha = 0.92;
goldenZombieText.alpha = 1;
LK.setTimeout(function () {
tween(goldenZombieOverlay, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
tween(goldenZombieText, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
// After golden zombie, show zombie
LK.setTimeout(function () {
zombieOverlay.alpha = 0.92;
zombieText.alpha = 1;
LK.setTimeout(function () {
tween(zombieOverlay, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
tween(zombieText, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
}, 700);
}, 400);
}, 900);
}
// Helper: show golden zombie picture, then zombie
function showGoldenZombiePicThenZombie() {
goldenZombiePicOverlay.alpha = 0.92;
goldenZombiePic.alpha = 1;
LK.setTimeout(function () {
tween(goldenZombiePicOverlay, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
tween(goldenZombiePic, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
// After golden zombie picture, show zombie
LK.setTimeout(function () {
zombieOverlay.alpha = 0.92;
zombieText.alpha = 1;
LK.setTimeout(function () {
tween(zombieOverlay, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
tween(zombieText, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
}, 700);
}, 400);
}, 900);
}
// Main random event handler
var mazeActive = false;
var mazeInstance = null;
var pausedIntervals = [];
function pauseAllIntervals() {
// Pause all intervals by clearing them and storing their ids
if (typeof window !== "undefined") return; // Defensive: not in browser
// Not needed in LK, as intervals are not global, but we can set a flag if needed
}
function resumeAllIntervals() {
// No-op for now, as LK intervals are not globally tracked
}
function handleRandomEvent() {
// 1 in 6 chance to trigger maze mode
if (!mazeActive && Math.random() < 0.17) {
mazeActive = true;
// Hide main UI
numberCallText.alpha = 0.1;
warningText.alpha = 0.1;
jumpScareOverlay.alpha = 0;
jumpScareText.alpha = 0;
jumpScareOverlay2.alpha = 0;
jumpScareText2.alpha = 0;
eventOverlay.alpha = 0;
eventText.alpha = 0;
goldenZombieOverlay.alpha = 0;
goldenZombieText.alpha = 0;
goldenZombiePicOverlay.alpha = 0;
goldenZombiePic.alpha = 0;
zombieOverlay.alpha = 0;
zombieText.alpha = 0;
doorOverlay.alpha = 0;
doorText.alpha = 0;
// Create maze instance
mazeInstance = new MazeMode();
mazeInstance.x = 0;
mazeInstance.y = 0;
mazeInstance.alpha = 1;
game.addChild(mazeInstance);
// Block main game input
game.down = null;
// Maze win callback
mazeInstance.onWin = function () {
// Remove maze, restore UI, resume game
if (mazeInstance) {
mazeInstance.destroy();
mazeInstance = null;
}
numberCallText.alpha = 1;
warningText.alpha = 1;
mazeActive = false;
// Restore click handler
game.down = function (x, y, obj) {
handleRandomEvent();
};
};
// Forward touch events to maze
game.down = function (x, y, obj) {
if (mazeInstance && mazeInstance.down) mazeInstance.down(x, y, obj);
};
game.up = function (x, y, obj) {
if (mazeInstance && mazeInstance.up) mazeInstance.up(x, y, obj);
};
game.move = function (x, y, obj) {
if (mazeInstance && mazeInstance.move) mazeInstance.move(x, y, obj);
};
return;
}
var eventType = Math.floor(Math.random() * 5);
if (eventType === 0) {
// Zombie attack
showEventOverlay(eventOverlay, eventText, 0x00ff00, 'ZOMBIE ATTACK!', 0x00ff00, 900);
} else if (eventType === 1) {
// Door closes, then game over
showEventOverlay(doorOverlay, doorText, 0x888888, 'DOOR CLOSES!', 0x888888, 900, function () {
// Game over removed! No action here.
});
} else if (eventType === 2) {
// Golden zombie, then zombie
showGoldenZombieThenZombie();
} else if (eventType === 3) {
// Golden zombie picture, then zombie
showGoldenZombiePicThenZombie();
} else {
// Zombie
showEventOverlay(zombieOverlay, zombieText, 0x00ff00, 'ZOMBIE!', 0x00ff00, 900);
}
}
// --- World Time Clock Overlay ---
// List of major cities and their UTC offsets (in hours)
var worldClockCities = [{
name: "London",
offset: 0
}, {
name: "New York",
offset: -4
}, {
name: "Los Angeles",
offset: -7
}, {
name: "Tokyo",
offset: 9
}, {
name: "Sydney",
offset: 10
}, {
name: "Paris",
offset: 2
}, {
name: "Moscow",
offset: 3
}, {
name: "Beijing",
offset: 8
}, {
name: "Dubai",
offset: 4
}, {
name: "Rio",
offset: -3
}];
// Overlay container for the world clock
var worldClockContainer = new Container();
worldClockContainer.x = 2048 - 20;
worldClockContainer.y = 20;
worldClockContainer.alpha = 0.95;
worldClockContainer.visible = false;
game.addChild(worldClockContainer);
// Background for the overlay
var worldClockBg = LK.getAsset('calledNumbersBg', {
width: 700,
height: 60 + 60 * worldClockCities.length,
anchorX: 1,
anchorY: 0,
x: 0,
y: 0
});
worldClockBg.alpha = 0.92;
worldClockContainer.addChild(worldClockBg);
// Title
var worldClockTitle = new Text2('World Clock', {
size: 54,
fill: 0x222222
});
worldClockTitle.anchor.set(1, 0);
worldClockTitle.x = 660;
worldClockTitle.y = 18;
worldClockContainer.addChild(worldClockTitle);
// City/time text objects
var worldClockTextObjs = [];
for (var i = 0; i < worldClockCities.length; i++) {
var txt = new Text2('', {
size: 44,
fill: 0x181a1b
});
txt.anchor.set(1, 0);
txt.x = 660;
txt.y = 60 + i * 54;
worldClockContainer.addChild(txt);
worldClockTextObjs.push(txt);
}
// Helper to update the times
function updateWorldClockTimes() {
var now = new Date();
for (var i = 0; i < worldClockCities.length; i++) {
var city = worldClockCities[i];
// Calculate local time for city
var utc = now.getTime() + now.getTimezoneOffset() * 60000;
var cityTime = new Date(utc + 3600000 * city.offset);
var h = cityTime.getHours();
var m = cityTime.getMinutes();
var s = cityTime.getSeconds();
var timeStr = (h < 10 ? "0" : "") + h + ":" + (m < 10 ? "0" : "") + m + ":" + (s < 10 ? "0" : "") + s;
worldClockTextObjs[i].setText(city.name + ": " + timeStr);
}
}
// Hide after a few seconds
function hideWorldClock() {
tween(worldClockContainer, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut,
onComplete: function onComplete() {
worldClockContainer.visible = false;
worldClockContainer.alpha = 0.95;
}
});
}
// Show the world clock overlay
function showWorldClock() {
updateWorldClockTimes();
worldClockContainer.visible = true;
worldClockContainer.alpha = 0.95;
// Animate in
tween(worldClockContainer, {
alpha: 0.95
}, {
duration: 200
});
// Hide after 3.5 seconds
LK.setTimeout(hideWorldClock, 3500);
}
// Update times every second if visible
LK.setInterval(function () {
if (worldClockContainer.visible) updateWorldClockTimes();
}, 1000);
// Listen for click/tap on the game area
// --- GeoGuessr Interruption Logic ---
var geoGuessrActive = false;
var geoGuessrCode = null;
var geoGuessrOverlay = null;
var geoGuessrInput = null;
var geoGuessrSubmitBtn = null;
var geoGuessrMsg = null;
var geoGuessrReturnHandler = null;
// Helper: Generate a random 4-digit code
function generateGeoGuessrCode() {
return "" + (1000 + Math.floor(Math.random() * 9000));
}
// Helper: Show overlay for code entry
function showGeoGuessrReturnOverlay(code) {
if (geoGuessrOverlay) geoGuessrOverlay.destroy();
geoGuessrOverlay = new Container();
geoGuessrOverlay.x = 0;
geoGuessrOverlay.y = 0;
geoGuessrOverlay.alpha = 1;
// Dim background
var bg = LK.getAsset('flashOverlay', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
alpha: 0.92
});
geoGuessrOverlay.addChild(bg);
// Message
geoGuessrMsg = new Text2("Enter the code to return:\n" + code, {
size: 120,
fill: 0x222222
});
geoGuessrMsg.anchor.set(0.5, 0);
geoGuessrMsg.x = 2048 / 2;
geoGuessrMsg.y = 700;
geoGuessrOverlay.addChild(geoGuessrMsg);
// Input box (simulate with Text2, user taps to increment digits)
geoGuessrInput = new Text2("----", {
size: 180,
fill: 0x000000
});
geoGuessrInput.anchor.set(0.5, 0.5);
geoGuessrInput.x = 2048 / 2;
geoGuessrInput.y = 1200;
geoGuessrOverlay.addChild(geoGuessrInput);
// Simulate input: tap to cycle digits
var inputDigits = [0, 0, 0, 0];
var inputPos = 0;
function updateInputText() {
var s = "";
for (var i = 0; i < 4; i++) s += typeof inputDigits[i] === "number" ? inputDigits[i] : "-";
geoGuessrInput.setText(s);
}
updateInputText();
geoGuessrInput.down = function (x, y, obj) {
inputDigits[inputPos] = ((inputDigits[inputPos] || 0) + 1) % 10;
updateInputText();
};
geoGuessrInput.up = function (x, y, obj) {
inputPos = (inputPos + 1) % 4;
};
// Submit button
geoGuessrSubmitBtn = LK.getAsset('buttonHover', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1500
});
geoGuessrOverlay.addChild(geoGuessrSubmitBtn);
var submitText = new Text2("SUBMIT", {
size: 90,
fill: 0xffffff
});
submitText.anchor.set(0.5, 0.5);
submitText.x = 2048 / 2;
submitText.y = 1500;
geoGuessrOverlay.addChild(submitText);
geoGuessrSubmitBtn.down = function (x, y, obj) {
var guess = "";
for (var i = 0; i < 4; i++) guess += inputDigits[i];
if (guess === code) {
// Success!
if (geoGuessrOverlay) {
geoGuessrOverlay.destroy();
geoGuessrOverlay = null;
}
geoGuessrActive = false;
// Restore game click handler
game.down = geoGuessrReturnHandler;
} else {
geoGuessrMsg.setText("Wrong! Try again.\n" + code);
LK.effects.flashObject(geoGuessrInput, 0xff0000, 200);
}
};
// Add overlay to game
game.addChild(geoGuessrOverlay);
// Forward input events
game.down = function (x, y, obj) {
if (geoGuessrInput && geoGuessrInput.down) geoGuessrInput.down(x, y, obj);
if (geoGuessrSubmitBtn && geoGuessrSubmitBtn.down) {
// Check if tap is on button
var bx = geoGuessrSubmitBtn.x,
by = geoGuessrSubmitBtn.y;
var bw = geoGuessrSubmitBtn.width || 220,
bh = geoGuessrSubmitBtn.height || 90;
if (x > bx - bw / 2 && x < bx + bw / 2 && y > by - bh / 2 && y < by + bh / 2) {
geoGuessrSubmitBtn.down(x, y, obj);
}
}
};
game.up = function (x, y, obj) {
if (geoGuessrInput && geoGuessrInput.up) geoGuessrInput.up(x, y, obj);
};
game.move = function (x, y, obj) {};
}
// Helper: Open GeoGuessr in a new tab
function openGeoGuessr() {
// Defensive: try to open in new tab
if (typeof window !== "undefined" && window.open) {
window.open("https://www.geoguessr.com/", "_blank");
}
}
// --- Italian Brain Rot Overlay and Logic ---
var italianBrainRotOverlay = LK.getAsset('flashOverlay', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 0
});
game.addChild(italianBrainRotOverlay);
var italianBrainRotTexts = ["MAMMA MIA!", "PASTA! PIZZA! MANDOLINO!", "SPAGHETTI TIME!", "CIAO BELLA!", "BENVENUTO AL BRAIN ROT!", "MOZZARELLA! FORMAGGIO!", "ITALIANO VERO!", "ANDIAMO!", "BADA BING BADA BOOM!", "MACCHERONI MADNESS!"];
var italianBrainRotTextObj = new Text2('', {
size: 220,
fill: 0x2e86c1
});
italianBrainRotTextObj.anchor.set(0.5, 0.5);
italianBrainRotTextObj.x = 2048 / 2;
italianBrainRotTextObj.y = 2732 / 2;
italianBrainRotTextObj.alpha = 0;
game.addChild(italianBrainRotTextObj);
function triggerItalianBrainRot() {
// Pick a random phrase
var idx = Math.floor(Math.random() * italianBrainRotTexts.length);
italianBrainRotTextObj.setText(italianBrainRotTexts[idx]);
italianBrainRotOverlay.alpha = 0.92;
italianBrainRotTextObj.alpha = 1;
// Animate out after 1.1s
LK.setTimeout(function () {
tween(italianBrainRotOverlay, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
tween(italianBrainRotTextObj, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
}, 1100);
}
// --- Random Text Overlay Logic ---
var randomTextOverlay = LK.getAsset('flashOverlay', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 0
});
game.addChild(randomTextOverlay);
var randomTextList = ["SURPRISE!", "HELLO THERE!", "WHAT'S GOING ON?", "RANDOM EVENT!", "YOU CLICKED!", "BOO!", "WOW!", "KEEP GOING!", "NICE CLICK!", "ARE YOU HAVING FUN?", "LUCKY CLICK!", "TRY AGAIN!", "MAGIC!", "MYSTERY!", "SECRET MESSAGE!", "DON'T STOP!", "ALMOST THERE!", "SO CLOSE!", "AMAZING!", "COOL!", "BINGO!", "ZAP!", "POW!", "YAY!", "AWESOME!", "GREAT JOB!"];
var randomTextObj = new Text2('', {
size: 200,
fill: 0x00aaff
});
randomTextObj.anchor.set(0.5, 0.5);
randomTextObj.x = 2048 / 2;
randomTextObj.y = 2732 / 2;
randomTextObj.alpha = 0;
game.addChild(randomTextObj);
function showRandomTextOverlay() {
var idx = Math.floor(Math.random() * randomTextList.length);
randomTextObj.setText(randomTextList[idx]);
randomTextOverlay.alpha = 0.92;
randomTextObj.alpha = 1;
LK.setTimeout(function () {
tween(randomTextOverlay, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
tween(randomTextObj, {
alpha: 0
}, {
duration: 400,
easing: tween.easeOut
});
}, 1100);
}
// Main click handler
game.down = function (x, y, obj) {
// 1 in 7 chance to trigger GeoGuessr interruption
var triggerGeoGuessr = Math.random() < 0.14 && !geoGuessrActive;
if (triggerGeoGuessr) {
geoGuessrActive = true;
geoGuessrCode = generateGeoGuessrCode();
geoGuessrReturnHandler = arguments.callee; // Save for restore
// Hide main UI
numberCallText.alpha = 0.1;
warningText.alpha = 0.1;
// Open GeoGuessr in new tab
openGeoGuessr();
// Show overlay for code entry
showGeoGuessrReturnOverlay(geoGuessrCode);
return;
}
// 90% chance to open a random appropriate website
if (Math.random() < 0.90) {
// List of appropriate, family-friendly websites
var safeWebsites = ["https://www.nationalgeographic.com/", "https://www.khanacademy.org/", "https://www.coolmathgames.com/", "https://www.funbrain.com/", "https://www.britannica.com/", "https://www.nasa.gov/kidsclub/index.html", "https://www.ducksters.com/", "https://www.pbskids.org/", "https://www.sesamestreet.org/", "https://www.highlightskids.com/"];
var siteIdx = Math.floor(Math.random() * safeWebsites.length);
var url = safeWebsites[siteIdx];
// Defensive: try to open in new tab if possible
if (typeof window !== "undefined" && window.open) {
window.open(url, "_blank");
}
// Optionally, show a random text overlay to indicate something happened
showRandomTextOverlay();
return;
}
// 1 in 8 chance to trigger Italian brain rot
var triggerItalian = Math.random() < 0.125;
if (triggerItalian) {
triggerItalianBrainRot();
return;
}
// Always play a random fart noise on click
var fartSounds = ['fart1', 'fart2', 'fart3', 'fart4', 'fart5', 'fart6', 'fart7'];
var fartIdx = Math.floor(Math.random() * fartSounds.length);
var fartSound = LK.getSound(fartSounds[fartIdx]);
if (fartSound) fartSound.play();
// 1 in 4.5 chance to show a random text overlay
if (Math.random() < 0.222) {
showRandomTextOverlay();
return;
}
// Only trigger the random event on ~1 in 4 clicks
var showClock = Math.random() < 0.18; // ~1 in 5.5 clicks
var showEvent = Math.random() < 0.25;
// 1 in 3.5 clicks, play a random annoying sound
var playAnnoyingSound = Math.random() < 0.285;
if (playAnnoyingSound) {
// 1 in 5 of those times, play the 'tongue, tongue, tongue' sound (let's use ses32 for this effect)
if (Math.random() < 0.2) {
var tongueSound = LK.getSound('ses32');
if (tongueSound) tongueSound.play();
} else if (Math.random() < 0.25) {
// 1 in 4 of the remaining times, play the 'dum dum dum dum dum dum dum' sound (let's use ses31 for this effect)
var dumSound = LK.getSound('ses31');
if (dumSound) dumSound.play();
} else {
// List of annoying/horrible sound ids (pffft, fart, screech, etc. - use ses41-ses75 as 'horrible' pool)
var annoyingSounds = ['ses41', 'ses42', 'ses43', 'ses44', 'ses45', 'ses46', 'ses47', 'ses48', 'ses49', 'ses50', 'ses51', 'ses52', 'ses53', 'ses54', 'ses55', 'ses56', 'ses57', 'ses58', 'ses59', 'ses60', 'ses61', 'ses62', 'ses64', 'ses65', 'ses66', 'ses67', 'ses68', 'ses69', 'ses70', 'ses71', 'ses72', 'ses75'];
var idx = Math.floor(Math.random() * annoyingSounds.length);
var sound = LK.getSound(annoyingSounds[idx]);
if (sound) sound.play();
}
}
// 1 in 4 clicks, play a random song
var playRandomSong = Math.random() < 0.25;
if (playRandomSong) {
// List of appropriate, family-friendly music ids only (no explicit lyrics, safe for all ages)
// These are demo placeholders; in a real game, use only tracks that are verified as clean and suitable.
var songIds = ['ses1',
// Confirmed: simple melody
'ses2',
// Confirmed: cheerful jingle
'ses3',
// Confirmed: upbeat instrumental
'ses4',
// Confirmed: playful tune
'ses5',
// Confirmed: light background
'ses6',
// Confirmed: happy chime
'ses7',
// Confirmed: fun sound
'ses8',
// Confirmed: short melody
'ses9',
// Confirmed: positive instrumental
'ses10' // Confirmed: safe, no lyrics
];
var songIdx = Math.floor(Math.random() * songIds.length);
var songId = songIds[songIdx];
// Play as music (will stop any currently playing music)
LK.playMusic(songId, {
loop: false
});
}
if (showClock) {
showWorldClock();
} else if (showEvent) {
handleRandomEvent();
}
};
// --- Animated background color pulse for visual appeal ---
var bgPulseColors = [0x181a1b,
// near-black
0x23272a,
// dark gray
0x222326,
// blackish blue
0x181a1b,
// repeat for smooth loop
0x23272a]; // Blackish/dark palette
var bgPulseIndex = 0;
var bgPulseDuration = 3000;
function pulseBackground() {
var fromColor = bgPulseColors[bgPulseIndex];
var toColor = bgPulseColors[(bgPulseIndex + 1) % bgPulseColors.length];
var t = {
v: 0
};
tween(t, {
v: 1
}, {
duration: bgPulseDuration,
easing: tween.easeInOut,
onUpdate: function onUpdate() {
// Interpolate color
var r1 = fromColor >> 16 & 0xff,
g1 = fromColor >> 8 & 0xff,
b1 = fromColor & 0xff;
var r2 = toColor >> 16 & 0xff,
g2 = toColor >> 8 & 0xff,
b2 = toColor & 0xff;
var r = Math.round(r1 + (r2 - r1) * t.v);
var g = Math.round(g1 + (g2 - g1) * t.v);
var b = Math.round(b1 + (b2 - b1) * t.v);
var color = r << 16 | g << 8 | b;
game.setBackgroundColor(color);
},
onComplete: function onComplete() {
bgPulseIndex = (bgPulseIndex + 1) % bgPulseColors.length;
pulseBackground();
}
});
}
pulseBackground();
// --- Golden Sign Event: Every 9-100 years, show golden sign with age message ---
// Helper: returns ms for N years (365.25 days per year)
function yearsToMs(years) {
return Math.floor(years * 365.25 * 24 * 60 * 60 * 1000);
}
// Track game start time (ms)
var gameStartTime = Date.now();
// Golden sign overlay and text
var goldenSignOverlay = LK.getAsset('flashOverlay', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 0
});
game.addChild(goldenSignOverlay);
var goldenSignText = new Text2('', {
size: 180,
fill: 0xffd700
});
goldenSignText.anchor.set(0.5, 0.5);
goldenSignText.x = 2048 / 2;
goldenSignText.y = 2732 / 2;
goldenSignText.alpha = 0;
game.addChild(goldenSignText);
// Helper: show golden sign with message
function showGoldenSign(message) {
goldenSignOverlay.alpha = 0.95;
goldenSignText.setText(message);
goldenSignText.fill = 0xffd700;
goldenSignText.alpha = 1;
LK.setTimeout(function () {
tween(goldenSignOverlay, {
alpha: 0
}, {
duration: 1200,
easing: tween.easeOut
});
tween(goldenSignText, {
alpha: 0
}, {
duration: 1200,
easing: tween.easeOut
});
}, 2200);
}
// Helper: pick a random integer in [a, b]
function randInt(a, b) {
return a + Math.floor(Math.random() * (b - a + 1));
}
// Schedule the first golden sign event
var nextGoldenSignYears = randInt(9, 10 + Math.floor(Math.random() * 91)); // 9-100 or 10-100 years
var nextGoldenSignTime = gameStartTime + yearsToMs(nextGoldenSignYears);
// Track how many golden sign events have occurred
var goldenSignEventCount = 0;
// Periodically check if it's time to show the golden sign
LK.setInterval(function () {
var now = Date.now();
if (now >= nextGoldenSignTime) {
// Compute "age" for fun message
var yearsElapsed = Math.floor((now - gameStartTime) / yearsToMs(1));
var fakeAge = 600 + goldenSignEventCount * randInt(1, 100);
showGoldenSign("How old are you now? You're probably " + fakeAge + "!");
goldenSignEventCount++;
// Schedule next event in 9-100 or 10-100 years
var nextYears = randInt(9, 10 + Math.floor(Math.random() * 91));
nextGoldenSignTime = now + yearsToMs(nextYears);
}
}, 10000); // Check every 10 seconds (safe, since event is ultra-rare);
Bingo thema. In-Game asset. 2d. High contrast. No shadows
Bingo Mark. In-Game asset. 2d. High contrast. No shadows
Streakbackground bingo. In-Game asset. 2d. High contrast. No shadows
Card border. In-Game asset. 2d. High contrast. No shadows
Djdj. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
A golden zombie with wide eyes. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Click
Sound effect
Numberthree
Sound effect
ses1
Sound effect
ses2
Sound effect
ses3
Sound effect
ses4
Sound effect
ses5
Sound effect
ses6
Sound effect
ses7
Sound effect
ses8
Sound effect
ses9
Sound effect
ses10
Sound effect
ses11
Sound effect
ses12
Sound effect
ses13
Sound effect
ses14
Sound effect
ses15
Sound effect
ses16
Sound effect
ses17
Sound effect
ses18
Sound effect
ses19
Sound effect
ses20
Sound effect
ses21
Sound effect
ses22
Sound effect
ses23
Sound effect
ses24
Sound effect
ses25
Sound effect
ses26
Sound effect
ses27
Sound effect
ses28
Sound effect
ses29
Sound effect
ses30
Sound effect
ses31
Sound effect
ses32
Sound effect
ses33
Sound effect
ses34
Sound effect
ses35
Sound effect
ses36
Sound effect
ses37
Sound effect
ses38
Sound effect
ses39
Sound effect
ses40
Sound effect
ses41
Sound effect
ses42
Sound effect
ses43
Sound effect
ses44
Sound effect
ses45
Sound effect
ses46
Sound effect
ses47
Sound effect
ses48
Sound effect
ses49
Sound effect
ses50
Sound effect
ses51
Sound effect
ses52
Sound effect
ses53
Sound effect
ses54
Sound effect
ses55
Sound effect
ses56
Sound effect
ses57
Sound effect
ses58
Sound effect
ses59
Sound effect
ses60
Sound effect
ses61
Sound effect
ses62
Sound effect
ses64
Sound effect
ses65
Sound effect
ses66
Sound effect
ses67
Sound effect
ses68
Sound effect
ses69
Sound effect
ses70
Sound effect
ses71
Sound effect
ses72
Sound effect
ses75
Sound effect
fart1
Sound effect
fart2
Sound effect
fart3
Sound effect
fart4
Sound effect
fart5
Sound effect
fart6
Sound effect
fart7
Sound effect