/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var EscapeSequence = Container.expand(function () { var self = Container.call(this); // Running figure sprite var runningFigure = new Container(); // Body shadow var body = runningFigure.attachAsset('simonButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 1.2, alpha: 0.8 }); // Head var head = runningFigure.attachAsset('entityFace', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3, y: -60, alpha: 0.8 }); // Legs in running position var leftLeg = runningFigure.attachAsset('simonButton', { anchorX: 0.5, anchorY: 0, scaleX: 0.2, scaleY: 0.5, x: -20, y: 60, rotation: Math.PI / 6, alpha: 0.8 }); var rightLeg = runningFigure.attachAsset('simonButton', { anchorX: 0.5, anchorY: 0, scaleX: 0.2, scaleY: 0.5, x: 20, y: 60, rotation: -Math.PI / 6, alpha: 0.8 }); // Arms in running position var leftArm = runningFigure.attachAsset('simonButton', { anchorX: 0.5, anchorY: 0, scaleX: 0.2, scaleY: 0.4, x: -25, y: -20, rotation: -Math.PI / 4, alpha: 0.8 }); var rightArm = runningFigure.attachAsset('simonButton', { anchorX: 0.5, anchorY: 0, scaleX: 0.2, scaleY: 0.4, x: 25, y: -20, rotation: Math.PI / 4, alpha: 0.8 }); // Add the running figure to self self.addChild(runningFigure); // Dialogue box var dialogueBox = new Container(); dialogueBox.y = 600; var dialogueBackground = dialogueBox.attachAsset('simonButtonGreen', { anchorX: 0.5, anchorY: 0.5, scaleX: 4.5, scaleY: 1.5, alpha: 0.7 }); // Dialogue text var dialogueText = new Text2('', { size: 60, fill: 0xFFFFFF, font: "'Creepster', 'Chiller', 'Times New Roman'" }); dialogueText.anchor.set(0.5, 0.5); dialogueBox.addChild(dialogueText); self.addChild(dialogueBox); // Animation state variables self.animationFrame = 0; self.runningSpeed = 15; self.direction = -1; // -1 for running left, 1 for running right // Method to start the escape sequence self.startEscape = function () { self.alpha = 0; // Position initially on the right side self.x = 2048 + 200; self.direction = -1; // Run to the left initially runningFigure.scale.x = self.direction; // Play escape sound LK.getSound('levelUpSound').play(); // Fade in sequence tween(self, { alpha: 1 }, { duration: 1000, easing: tween.easeIn, onFinish: function onFinish() { self.playDialogueSequence(); self.animateRunning(); } }); }; // Simplified movement without animation self.animateRunning = function () { // Move the figure without animating limbs self.x += self.direction * self.runningSpeed; // Check if we need to turn around if (self.x < -200 || self.x > 2048 + 200) { self.direction *= -1; runningFigure.scale.x = self.direction; } // Continue movement LK.setTimeout(self.animateRunning, 50); }; // Play the dialogue sequence self.playDialogueSequence = function () { var dialogues = ["I have to get out of here!", "These shadows... they're watching me...", "I can feel the darkness trying to pull me back...", "That entity... it's toying with me.", "Is this really happening? Or am I still trapped?", "The patterns... I can still see them when I close my eyes...", "I think I'm finally free... but at what cost?", "Part of me will always be trapped in that place...", "I can hear the voices fading... finally...", "Never look back. Just keep running."]; var currentDialogue = 0; function showNextDialogue() { if (currentDialogue < dialogues.length) { dialogueText.setText(dialogues[currentDialogue]); currentDialogue++; // Schedule next dialogue LK.setTimeout(showNextDialogue, 3000); } else { // End of dialogue sequence self.finishEscape(); } } // Start the dialogue sequence showNextDialogue(); }; // Finish the escape sequence self.finishEscape = function () { // Speed up running at the end self.runningSpeed = 25; // Make sure we're running to the left (away) self.direction = -1; runningFigure.scale.x = self.direction; // Play victory sound LK.getSound('levelUpSound').play(); // Fade out dialogue tween(dialogueBox, { alpha: 0 }, { duration: 1000 }); // Run off screen then fade out LK.setTimeout(function () { tween(self, { alpha: 0 }, { duration: 1500, onFinish: function onFinish() { // Create restart button var restartButton = new Container(); var restartButtonBg = restartButton.attachAsset('simonButtonGreen', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 1, alpha: 0.7 }); var restartText = new Text2('PLAY AGAIN', { size: 80, fill: 0xFFFFFF, font: "'Creepster', 'Chiller', 'Times New Roman'" }); restartText.anchor.set(0.5, 0.5); restartButton.addChild(restartText); restartButton.x = 2048 / 2; restartButton.y = 2732 / 2 + 300; LK.gui.center.addChild(restartButton); // Add touch handler for restart button restartButton.down = function () { restartButton.destroy(); LK.showYouWin(); }; // Show you win screen with the restart button LK.showYouWin(); self.destroy(); } }); }, 3000); }; return self; }); var GlitchEntity = Container.expand(function () { var self = Container.call(this); // Face from the entity that will glitch around var face = self.attachAsset('entityFace', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5, alpha: 0.7 }); // Eyes that will move independently var leftEye = self.attachAsset('entityEye', { anchorX: 0.5, anchorY: 0.5, x: -65, y: -55, scaleX: 1.2, scaleY: 1.2, alpha: 0.9 }); var rightEye = self.attachAsset('entityEye', { anchorX: 0.5, anchorY: 0.5, x: 65, y: -55, scaleX: 1.2, scaleY: 1.2, alpha: 0.9 }); // Mouth that will distort var mouth = self.attachAsset('entityMouth', { anchorX: 0.5, anchorY: 0.5, y: 100, scaleX: 1.4, scaleY: 1.2, alpha: 0.9 }); // Dialogue box var dialogueBox = new Container(); dialogueBox.y = 600; var dialogueBackground = dialogueBox.attachAsset('simonButtonBlue', { anchorX: 0.5, anchorY: 0.5, scaleX: 4.5, scaleY: 1.5, alpha: 0.7 }); // Dialogue text var dialogueText = new Text2('', { size: 60, fill: 0xFFFFFF, font: "'Creepster', 'Chiller', 'Times New Roman'" }); dialogueText.anchor.set(0.5, 0.5); dialogueBox.addChild(dialogueText); self.addChild(dialogueBox); // Set initial state self.alpha = 0; // Glitch intervals self.eyeGlitchInterval = null; self.mouthGlitchInterval = null; self.faceGlitchInterval = null; self.randomSpritesInterval = null; self.sprites = []; // Start glitch sequence self.startGlitch = function () { self.alpha = 0; // Play creepy sound LK.getSound('creepyLaugh').play(); // Fade in tween(self, { alpha: 1 }, { duration: 1000, easing: tween.easeIn, onFinish: function onFinish() { self.startGlitchEffects(); self.showGlitchDialogue(); } }); }; // Generate random glitchy sprites self.createRandomSprite = function () { var sprite = new Container(); // Randomly select which element to use var elements = ['entityEye', 'entityMouth', 'entityFace', 'simonButton', 'simonButtonRed', 'simonButtonGreen', 'simonButtonBlue', 'simonButtonYellow']; var asset = elements[Math.floor(Math.random() * elements.length)]; var spriteGraphic = sprite.attachAsset(asset, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3 + Math.random() * 0.7, scaleY: 0.3 + Math.random() * 0.7, alpha: 0.1 + Math.random() * 0.4, rotation: Math.random() * Math.PI * 2 }); // Position randomly on screen sprite.x = Math.random() * 2048; sprite.y = Math.random() * 2732; // Add to game game.addChild(sprite); self.sprites.push(sprite); // Apply glitch movement self.glitchSpriteMovement(sprite); // Remove after random time LK.setTimeout(function () { sprite.destroy(); var index = self.sprites.indexOf(sprite); if (index !== -1) { self.sprites.splice(index, 1); } }, 1000 + Math.random() * 5000); }; // Apply random movement to sprites self.glitchSpriteMovement = function (sprite) { var originalX = sprite.x; var originalY = sprite.y; var randomX = originalX + (Math.random() - 0.5) * 300; var randomY = originalY + (Math.random() - 0.5) * 300; tween(sprite, { x: randomX, y: randomY, rotation: Math.random() * Math.PI * 2, alpha: 0.1 + Math.random() * 0.6, scaleX: 0.2 + Math.random() * 1.0, scaleY: 0.2 + Math.random() * 1.0 }, { duration: 100 + Math.random() * 500, onFinish: function onFinish() { if (sprite.parent) { self.glitchSpriteMovement(sprite); } } }); }; // Start all glitch effects self.startGlitchEffects = function () { // Start eyes moving randomly self.eyeGlitchInterval = LK.setInterval(function () { tween(leftEye, { x: -65 + (Math.random() - 0.5) * 150, y: -55 + (Math.random() - 0.5) * 150, rotation: Math.random() * Math.PI * 2, scaleX: 0.8 + Math.random() * 1.0, scaleY: 0.8 + Math.random() * 1.0 }, { duration: 50 + Math.random() * 100 }); tween(rightEye, { x: 65 + (Math.random() - 0.5) * 150, y: -55 + (Math.random() - 0.5) * 150, rotation: Math.random() * Math.PI * 2, scaleX: 0.8 + Math.random() * 1.0, scaleY: 0.8 + Math.random() * 1.0 }, { duration: 50 + Math.random() * 100 }); }, 150); // Mouth distortion self.mouthGlitchInterval = LK.setInterval(function () { tween(mouth, { x: (Math.random() - 0.5) * 100, y: 100 + (Math.random() - 0.5) * 50, scaleX: 0.5 + Math.random() * 2.0, scaleY: 0.5 + Math.random() * 1.0, rotation: (Math.random() - 0.5) * 0.5 }, { duration: 50 + Math.random() * 150 }); }, 200); // Face distortion self.faceGlitchInterval = LK.setInterval(function () { tween(face, { scaleX: 1.3 + (Math.random() - 0.5) * 0.5, scaleY: 1.3 + (Math.random() - 0.5) * 0.5, rotation: (Math.random() - 0.5) * 0.2 }, { duration: 100 + Math.random() * 200 }); // Screen shake var shakeIntensity = 5 + Math.random() * 15; var originalX = game.x; var originalY = game.y; var shakeCount = 0; var maxShakes = 5 + Math.floor(Math.random() * 5); var shakeInterval = LK.setInterval(function () { game.x = originalX + (Math.random() - 0.5) * shakeIntensity; game.y = originalY + (Math.random() - 0.5) * shakeIntensity; shakeCount++; if (shakeCount >= maxShakes) { LK.clearInterval(shakeInterval); game.x = originalX; game.y = originalY; } }, 30); }, 500); // Create random sprites that appear and disappear self.randomSpritesInterval = LK.setInterval(function () { // Limit total sprites to avoid performance issues if (self.sprites.length < 15) { self.createRandomSprite(); } }, 300); }; // Show creepy dialogue self.showGlitchDialogue = function () { var dialogue = "w-why d-d-diiiid y-y-you do that,? you will be t-t-tr-tr-trapped here f-for eternity... I c-can f-f-feel y-your fear... it t-t-tastes s-so sweet... Y-your s-soul is m-mine now... T-there is n-no esc-c-cape... T-the d-darkness will c-c-consume you... F-forever in th-this n-nightmare... Y-your m-memories w-will fade... L-lost in th-this v-void... A-alone... F-forgotten... B-broken... E-every p-p-piece of y-you w-will d-d-dissolve into th-the v-void... Y-your c-consciousness w-will r-remain... a-aware... s-suffering... b-but p-powerless... T-trapped in a m-moment of p-pure t-terror... N-no one w-will r-remember y-you... T-time w-will n-never p-pass h-here... I will k-keep y-you here... FOREVER..."; // Break dialogue into chunks with random delays var words = dialogue.split(' '); var currentText = ''; var wordIndex = 0; function showNextWord() { if (wordIndex < words.length) { currentText += words[wordIndex] + ' '; dialogueText.setText(currentText); wordIndex++; // Random glitchy delay between words - slower than before LK.setTimeout(showNextWord, 150 + Math.random() * 250); } else { // End of dialogue with final scream dialogueText.setText(currentText + " o-oh n-n-n-nOOOOOOOOOOOOO!!!"); // Wait a bit before ending the glitch LK.setTimeout(function () { self.showTrappedEnding(); }, 3000); } } showNextWord(); }; // Show trapped ending with white eyes around screen self.showTrappedEnding = function () { // First fade out the entity and dialogue tween(face, { alpha: 0 }, { duration: 800 }); tween(leftEye, { alpha: 0 }, { duration: 800 }); tween(rightEye, { alpha: 0 }, { duration: 800 }); tween(mouth, { alpha: 0 }, { duration: 800 }); tween(dialogueBox, { alpha: 0 }, { duration: 800, onFinish: function onFinish() { // Create white eyes around the edges var eyes = []; var eyeCount = 20; // Create "Trapped ending" text var trappedText = new Text2('Trapped ending', { size: 150, fill: 0xFFFFFF, font: "'Creepster', 'Chiller', 'Times New Roman'" }); trappedText.anchor.set(0.5, 0.5); trappedText.alpha = 0; game.addChild(trappedText); trappedText.x = 2048 / 2; trappedText.y = 2732 / 2; // Create eyes around the screen edges for (var i = 0; i < eyeCount; i++) { var eye = new Container(); var eyeGraphic = eye.attachAsset('entityEye', { anchorX: 0.5, anchorY: 0.5, tint: 0xFFFFFF // White eyes }); // Position around the edge of the screen var angle = i / eyeCount * Math.PI * 2; var radius = Math.min(2048, 2732) * 0.45; // Slightly inside the screen edge eye.x = 2048 / 2 + Math.cos(angle) * radius; eye.y = 2732 / 2 + Math.sin(angle) * radius; // Make eyes look toward center eye.rotation = angle + Math.PI; // Face toward center eye.scale.set(0.8 + Math.random() * 0.4); eye.alpha = 0; game.addChild(eye); eyes.push(eye); } // Fade in the eyes one by one function fadeInEyes(index) { if (index < eyes.length) { tween(eyes[index], { alpha: 0.7 + Math.random() * 0.3 }, { duration: 100 + Math.random() * 200, onFinish: function onFinish() { fadeInEyes(index + 1); } }); } else { // After all eyes appear, show the text tween(trappedText, { alpha: 1 }, { duration: 1500, onFinish: function onFinish() { // Let the trapped ending display for a while before ending LK.setTimeout(function () { self.endGlitch(eyes, trappedText); }, 5000); } }); } } // Start fading in eyes fadeInEyes(0); } }); }; // End glitch sequence self.endGlitch = function (eyes, trappedText) { // Play error sound LK.getSound('errorSound').play(); // Stop all glitch intervals LK.clearInterval(self.eyeGlitchInterval); LK.clearInterval(self.mouthGlitchInterval); LK.clearInterval(self.faceGlitchInterval); LK.clearInterval(self.randomSpritesInterval); // Remove all sprites self.sprites.forEach(function (sprite) { sprite.destroy(); }); self.sprites = []; // Reset game position game.x = 0; game.y = 0; // If we have eyes and trapped text from the ending, fade them out if (eyes && trappedText) { // Fade out eyes eyes.forEach(function (eye) { tween(eye, { alpha: 0 }, { duration: 1000 + Math.random() * 500 }); }); // Fade out trapped text tween(trappedText, { alpha: 0 }, { duration: 1500 }); } // Fade out main container tween(self, { alpha: 0 }, { duration: 1500, easing: tween.easeOut, onFinish: function onFinish() { // Create restart button var restartButton = new Container(); var restartButtonBg = restartButton.attachAsset('simonButtonBlue', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 1, alpha: 0.7 }); var restartText = new Text2('PLAY AGAIN', { size: 80, fill: 0xFFFFFF, font: "'Creepster', 'Chiller', 'Times New Roman'" }); restartText.anchor.set(0.5, 0.5); restartButton.addChild(restartText); restartButton.x = 2048 / 2; restartButton.y = 2732 / 2 + 300; LK.gui.center.addChild(restartButton); // Add touch handler for restart button restartButton.down = function () { restartButton.destroy(); LK.showGameOver(); }; // Clean up by destroying all elements if (eyes) { eyes.forEach(function (eye) { eye.destroy(); }); } if (trappedText) { trappedText.destroy(); } self.destroy(); } }); }; return self; }); var ShadowFigure = Container.expand(function () { var self = Container.call(this); // Dark shadow shape var shadowShape = self.attachAsset('simonButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 5, scaleY: 10, alpha: 0.8 }); // Face elements similar to entity but with different positions/scales var face = self.attachAsset('entityFace', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5, alpha: 0.7 }); // Eyes var leftEye = self.attachAsset('entityEye', { anchorX: 0.5, anchorY: 0.5, x: -65, y: -55, scaleX: 1.2, scaleY: 1.2, alpha: 0.9 }); var rightEye = self.attachAsset('entityEye', { anchorX: 0.5, anchorY: 0.5, x: 65, y: -55, scaleX: 1.2, scaleY: 1.2, alpha: 0.9 }); // Mouth var mouth = self.attachAsset('entityMouth', { anchorX: 0.5, anchorY: 0.5, y: 100, scaleX: 1.4, scaleY: 1.2, alpha: 0.9 }); // Dialogue box var dialogueBox = new Container(); dialogueBox.y = 600; var dialogueBackground = dialogueBox.attachAsset('simonButtonBlue', { anchorX: 0.5, anchorY: 0.5, scaleX: 4.5, scaleY: 1.5, alpha: 0.7 }); // Dialogue text var dialogueText = new Text2('', { size: 60, fill: 0xFFFFFF, font: "'Creepster', 'Chiller', 'Times New Roman'" }); dialogueText.anchor.set(0.5, 0.5); dialogueBox.addChild(dialogueText); // Car crash image var carCrashImage = new Container(); carCrashImage.y = -150; carCrashImage.visible = false; var crashBackground = carCrashImage.attachAsset('carCrashImage', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0, alpha: 0.7 }); // Skip button var skipButton = new Container(); var skipButtonBg = skipButton.attachAsset('simonButtonYellow', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 0.5, alpha: 0.7 }); var skipText = new Text2('SKIP', { size: 60, fill: 0xFFFFFF, font: "'Creepster', 'Chiller', 'Times New Roman'" }); skipText.anchor.set(0.5, 0.5); skipButton.addChild(skipText); skipButton.x = 800; skipButton.y = 900; // Add touch handler for skip button skipButton.down = function (x, y, obj) { self.endDialogue(); }; // Add everything to self self.addChild(dialogueBox); self.addChild(carCrashImage); self.addChild(skipButton); // Ensure car crash image is in front by setting its zIndex carCrashImage.zIndex = 100; // Starting state self.alpha = 0; // Method to start dialogue sequence self.startDialogue = function () { self.alpha = 0; // Play eerie ambience LK.getSound('creepyLaugh').play(); // Stop jack-in-the-box music if it's playing LK.stopMusic(); // Hide UI elements during dialogue levelText.visible = false; scoreText.visible = false; highScoreText.visible = false; instructionsText.visible = false; statusText.setText(""); // Fade in sequence tween(self, { alpha: 1 }, { duration: 2000, easing: tween.easeIn, onFinish: function onFinish() { self.playDialogueSequence(); } }); }; // Play the dialogue sequence self.playDialogueSequence = function () { var dialogues = ["Hello...", "Do you remember where you were before the incident?", "*shows blurry image of a person's perspective of driving a car*", "And now, you're here.", "I've been watching you for some time...", "Your thoughts, your fears, your regrets...", "They're all so... delicious.", "This place exists between reality and nightmare.", "A realm where I control everything.", "Your memories are fractured, aren't they?", "The crash wasn't your fault... or was it?", "The guilt you carry is what brought you to me.", "You must complete 35 levels of Simon Says to leave this place.", "With each level, a piece of your soul will return.", "Fail, and you'll remain here... forever.", "Others have tried before you. None have succeeded.", "Their echoes still linger in these walls.", "Can you hear them whispering?", "Follow the patterns. Don't make mistakes.", "Your sanity depends on it.", "Good luck.", "You'll need it.", "*shows devious smile before game starts*"]; var hellModeDialogues = ["Why would you do this to yourself?", "This isn't worth it...", "I didn't think you'd actually choose this path.", "I do want to see you suffer, though...", "Your mind will fracture in ways you cannot imagine.", "The patterns will blur, distort, and deceive you.", "Reality itself will bend against you.", "Time will stretch and contract at my whim.", "I've driven others to madness this way before.", "They clawed at their eyes trying to unsee what I showed them.", "They still scream in the void between thoughts...", "Can you feel them reaching for you even now?", "Their torment will become yours.", "Your soul will shatter into a thousand fragments.", "I will cherish collecting each broken piece...", "Your suffering will nourish me for centuries.", "The buttons themselves will become your enemies.", "Every touch will send tremors through your very being.", "I can feel your fear already... it's intoxicating.", "The others before you... they thought they were strong too.", "One by one, they surrendered to madness.", "Some begged for death before the end.", "Death would be a mercy I'm not willing to grant.", "Your fingers will tremble, your vision will blur.", "The nightmares will follow you even if you somehow escape.", "Your determination is... admirable, but futile.", "No one escapes the nightmare at this depth.", "Still, I'm eager to watch you try...", "Let your sanity slip away, piece by piece...", "G O O D L U C K . . .", "*shows horrific wide grin as face distorts unnaturally*"]; var currentDialogue = 0; var isHellModeDialogue = false; // Check if this is triggered from hell mode button if (gameState === STATE_INTRO && window.hellButton && window.hellButton.alpha < 1) { dialogues = hellModeDialogues; isHellModeDialogue = true; tween(mouth, { scaleX: 3.0, scaleY: 0.8 }, { duration: 800 }); } function showNextDialogue() { if (currentDialogue < dialogues.length) { var dialogue = dialogues[currentDialogue]; // Special cases if (dialogue.includes("*shows blurry image")) { // Show car crash image carCrashImage.visible = true; tween(carCrashImage, { alpha: 0.9 }, { duration: 500 }); dialogueText.setText(""); } else if (dialogue.includes("*shows devious smile") || dialogue.includes("*shows horrific wide grin")) { // Show evil smile, more extreme for hell mode var scaleX = isHellModeDialogue ? 3.5 : 2.5; var scaleY = isHellModeDialogue ? 0.7 : 1.0; tween(mouth, { scaleX: scaleX, scaleY: scaleY }, { duration: 800 }); dialogueText.setText(""); } else { // Hide car crash image if visible if (carCrashImage.visible) { tween(carCrashImage, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { carCrashImage.visible = false; } }); } // Normal dialogue dialogueText.setText(dialogue); } currentDialogue++; // Calculate delay - longer for showing images or evil smile var delay = 3500; // Increased from 2000 to make dialogue slower if (dialogue.includes("*")) { delay = 5000; // Increased from 3000 for special scenes } // Schedule next dialogue LK.setTimeout(showNextDialogue, delay); } else { // End of dialogue sequence self.endDialogue(); } } // Start the dialogue sequence showNextDialogue(); }; // End dialogue and transition to title screen self.endDialogue = function () { // Check whether we're in intro dialogue or hell mode dialogue var showTitleScreen = gameState === STATE_INTRO_DIALOGUE; var isHellMode = gameState === STATE_INTRO && window.hellButton && window.hellButton.alpha < 1; tween(self, { alpha: 0 }, { duration: 1500, easing: tween.easeOut, onFinish: function onFinish() { // Only show title screen if we're in the intro state and not coming from hell button if (showTitleScreen) { // Make sure all UI elements are hidden before showing title screen levelText.visible = false; scoreText.visible = false; highScoreText.visible = false; instructionsText.visible = false; // Create title screen var titleScreen = game.addChild(new TitleScreen()); titleScreen.x = 2048 / 2; titleScreen.y = 2732 / 2; gameState = STATE_INTRO; } else if (isHellMode) { // If coming from hell button click, start hell mode if (window.hellButton) { // Restore title screen visibility first var titleScreen = window.hellButton.parent; tween(titleScreen, { alpha: 1 }, { duration: 500, onFinish: function onFinish() { // Start hell mode titleScreen.startGame(true); // Reset hellButton reference window.hellButton = null; } }); } } statusText.setText(""); self.destroy(); } }); }; return self; }); var SimonButton = Container.expand(function (color, sound, id) { var self = Container.call(this); self.id = id; self.isActive = false; self.sound = sound; self.isHovering = false; self.shakeInterval = null; var buttonGraphics = self.attachAsset('simonButton', { anchorX: 0.5, anchorY: 0.5 }); var activeButtonAsset = 'simonButton' + color; var activeButtonGraphics = self.attachAsset(activeButtonAsset, { anchorX: 0.5, anchorY: 0.5, alpha: 0 }); self.activate = function () { if (self.isActive) { return; } self.isActive = true; // Apply glitch effects to button activation based on score var activationDuration = 300; var fadeDuration = 300; var glitchScale = 1; // Play sound immediately when button is activated LK.getSound(self.sound).play(); // Modify button behavior based on glitch intensity if (glitchIntensity > 0) { // Random duration variations activationDuration = Math.max(100, 300 - glitchIntensity * 20); fadeDuration = Math.max(100, 300 - glitchIntensity * 15); // Random scale effects if (glitchIntensity > 3 && Math.random() < 0.3) { glitchScale = 1 + Math.random() * 0.3 * glitchIntensity; // Apply temporary scale effect buttonGraphics.scale.set(glitchScale); LK.setTimeout(function () { buttonGraphics.scale.set(1); }, activationDuration); } } tween(activeButtonGraphics, { alpha: 1 }, { duration: activationDuration, onFinish: function onFinish() { tween(activeButtonGraphics, { alpha: 0 }, { duration: fadeDuration, onFinish: function onFinish() { self.isActive = false; } }); } }); }; self.down = function (x, y, obj) { if (gameState === STATE_PLAYER_TURN && !self.isActive && !waitingForInput) { self.activate(); playerSequence.push(self.id); checkPlayerInput(); } }; // Add move handler for hover effect in hell mode self.move = function (x, y, obj) { if (glitchIntensity >= 15 && !self.isHovering) { self.isHovering = true; // Create violent screen shake when hovering in hell mode var shakeIntensity = 15 + Math.random() * 15; var originalX = game.x; var originalY = game.y; // Clear any existing shake interval if (self.shakeInterval) { LK.clearInterval(self.shakeInterval); } // Create new shake interval self.shakeInterval = LK.setInterval(function () { game.x = originalX + (Math.random() - 0.5) * shakeIntensity; game.y = originalY + (Math.random() - 0.5) * shakeIntensity; }, 30); // Also add button pulsing effect tween(buttonGraphics, { scaleX: 1.1, scaleY: 1.1, alpha: 0.8 }, { duration: 200 }); } }; // Add out handler to stop shaking when not hovering self.out = function () { if (self.isHovering) { self.isHovering = false; // Stop the screen shake if (self.shakeInterval) { LK.clearInterval(self.shakeInterval); self.shakeInterval = null; // Reset game position game.x = 0; game.y = 0; } // Reset button appearance tween(buttonGraphics, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 200 }); } }; return self; }); var SinisterEntity = Container.expand(function () { var self = Container.call(this); // Face base var face = self.attachAsset('entityFace', { anchorX: 0.5, anchorY: 0.5 }); // Left eye var leftEye = self.attachAsset('entityEye', { anchorX: 0.5, anchorY: 0.5, x: -75, y: -50 }); // Right eye var rightEye = self.attachAsset('entityEye', { anchorX: 0.5, anchorY: 0.5, x: 75, y: -50 }); // Mouth var mouth = self.attachAsset('entityMouth', { anchorX: 0.5, anchorY: 0.5, y: 80 }); self.alpha = 0; self.appear = function (intensity) { self.alpha = 0; // Scale intensity from 0-10 to meaningful values var duration = Math.max(1000 - intensity * 80, 200); var scaleFactor = 1 + intensity * 0.1; tween(self, { alpha: 1 }, { duration: duration, easing: tween.easeIn, onFinish: function onFinish() { // Make eyes look at player tween(leftEye, { scaleX: 1.5, scaleY: 1.5 }, { duration: 300, easing: tween.easeOut }); tween(rightEye, { scaleX: 1.5, scaleY: 1.5 }, { duration: 300, easing: tween.easeOut }); // Make mouth grow wider tween(mouth, { scaleX: 1.8, scaleY: 0.8 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { if (intensity > 5) { LK.getSound('creepyLaugh').play(); } LK.setTimeout(function () { self.disappear(); }, 1000); } }); } }); }; self.disappear = function () { tween(leftEye, { scaleX: 1, scaleY: 1 }, { duration: 300 }); tween(rightEye, { scaleX: 1, scaleY: 1 }, { duration: 300 }); tween(mouth, { scaleX: 1, scaleY: 1 }, { duration: 300 }); tween(self, { alpha: 0 }, { duration: 500, easing: tween.easeOut }); }; self.jumpscare = function () { self.alpha = 0; self.scale.set(0.1); tween(self, { alpha: 1, scaleX: 3, scaleY: 3 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { LK.setTimeout(function () { tween(self, { alpha: 0 }, { duration: 400, easing: tween.easeIn }); }, 200); } }); }; return self; }); var TitleScreen = Container.expand(function () { var self = Container.call(this); // Play jack-in-the-box music for title screen LK.playMusic('jackInTheBoxMusic', { fade: { start: 0, end: 0.7, duration: 1500 } }); // Title text var titleText = new Text2('Sinister Simon', { size: 150, fill: 0xFF0000, font: "'Creepster', 'Chiller', 'Times New Roman'" }); titleText.anchor.set(0.5, 0.5); titleText.y = -400; self.addChild(titleText); // Subtitle text var subtitleText = new Text2('A game of memory and fear', { size: 70, fill: 0xFF0000, font: "'Creepster', 'Chiller', 'Times New Roman'" }); subtitleText.anchor.set(0.5, 0.5); subtitleText.y = -280; self.addChild(subtitleText); // Start button var startButton = new Container(); var startButtonBg = startButton.attachAsset('simonButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 1, alpha: 0.7 }); var startText = new Text2('START GAME', { size: 80, fill: 0xFFFFFF, font: "'Creepster', 'Chiller', 'Times New Roman'" }); startText.anchor.set(0.5, 0.5); startButton.addChild(startText); startButton.y = 100; self.addChild(startButton); // Hell mode button var hellButton = new Container(); var hellBg = hellButton.attachAsset('simonButtonRed', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 1, alpha: 0.7 }); var hellText = new Text2('HELL MODE', { size: 80, fill: 0xFFFFFF, font: "'Creepster', 'Chiller', 'Times New Roman'" }); hellText.anchor.set(0.5, 0.5); hellButton.addChild(hellText); hellButton.y = 500; self.addChild(hellButton); // Add touch handler for start button startButton.down = function (x, y, obj) { self.startGame(false); }; // Add touch handler for hell mode button hellButton.down = function (x, y, obj) { // Create shadow figure for hell mode warning var hellFigure = game.addChild(new ShadowFigure()); hellFigure.x = 2048 / 2; hellFigure.y = 2732 / 2; // Fade out title screen temporarily tween(self, { alpha: 0.2 }, { duration: 1000 }); // Store reference to hell button for the dialogue system window.hellButton = hellButton; // Prevent double-clicking hellButton.alpha = 0.5; // Trigger hell mode dialogue LK.setTimeout(function () { hellFigure.startDialogue(); // After dialogue, the shadow figure will automatically start hell mode gameState = STATE_INTRO; }, 500); }; // Add glitch button in the bottom right corner var glitchButton = new Container(); var glitchBg = glitchButton.attachAsset('simonButtonBlue', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.7, scaleY: 0.7, alpha: 0.3 }); var glitchText = new Text2('???', { size: 70, fill: 0xFFFFFF, font: "'Creepster', 'Chiller', 'Times New Roman'" }); glitchText.anchor.set(0.5, 0.5); glitchButton.addChild(glitchText); glitchButton.x = 900; glitchButton.y = 700; self.addChild(glitchButton); // Add touch handler for glitch button glitchButton.down = function (x, y, obj) { // Prevent double-clicking glitchButton.alpha = 0.2; // Stop the jack-in-the-box music LK.stopMusic(); // Fade out everything on screen tween(self, { alpha: 0 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { // Create glitch entity var glitchEntity = game.addChild(new GlitchEntity()); glitchEntity.x = 2048 / 2; glitchEntity.y = 2732 / 2; // Start glitch sequence glitchEntity.startGlitch(); } }); }; // Method to start the game self.startGame = function (hellMode) { // Stop the jack-in-the-box music LK.stopMusic(); tween(self, { alpha: 0 }, { duration: 1000, easing: tween.easeOut, onFinish: function onFinish() { startGame(hellMode); self.destroy(); } }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Constants var STATE_INTRO_DIALOGUE = 0; var STATE_INTRO = 1; var STATE_SIMON_TURN = 2; var STATE_PLAYER_TURN = 3; var STATE_GAME_OVER = 4; var COLOR_RED = 'Red'; var COLOR_GREEN = 'Green'; var COLOR_BLUE = 'Blue'; var COLOR_YELLOW = 'Yellow'; // Game variables var gameState = STATE_INTRO_DIALOGUE; var level = 1; var sequence = []; var playerSequence = []; var sequenceIndex = 0; var waitingForInput = false; var horrorIntensity = 0; var glitchIntensity = 0; // Track glitch effects based on score var highScore = storage.highScore || 0; // Overlay for horror effects var overlay = game.addChild(LK.getAsset('backgroundOverlay', { anchorX: 0, anchorY: 0, alpha: 0 })); // Create Simon buttons var buttonSize = 400; var spacing = 50; var totalWidth = buttonSize * 2 + spacing; var totalHeight = buttonSize * 2 + spacing; var startX = (2048 - totalWidth) / 2 + buttonSize / 2; var startY = (2732 - totalHeight) / 2 + buttonSize / 2; var buttons = []; var buttonRed = game.addChild(new SimonButton(COLOR_RED, 'buttonSound1', 0)); buttonRed.x = startX; buttonRed.y = startY; buttons.push(buttonRed); var buttonGreen = game.addChild(new SimonButton(COLOR_GREEN, 'buttonSound2', 1)); buttonGreen.x = startX + buttonSize + spacing; buttonGreen.y = startY; buttons.push(buttonGreen); var buttonBlue = game.addChild(new SimonButton(COLOR_BLUE, 'buttonSound3', 2)); buttonBlue.x = startX; buttonBlue.y = startY + buttonSize + spacing; buttons.push(buttonBlue); var buttonYellow = game.addChild(new SimonButton(COLOR_YELLOW, 'buttonSound4', 3)); buttonYellow.x = startX + buttonSize + spacing; buttonYellow.y = startY + buttonSize + spacing; buttons.push(buttonYellow); // Create the sinister entity var entity = game.addChild(new SinisterEntity()); entity.x = 2048 / 2; entity.y = 2732 / 2; // Level text var levelText = new Text2('Level: 1', { size: 80, fill: 0xFF0000, font: "'Creepster', 'Chiller', 'Times New Roman'" }); levelText.anchor.set(0.5, 0); LK.gui.top.addChild(levelText); levelText.y = 100; // Score text var scoreText = new Text2('Score: 0', { size: 80, fill: 0xFF0000, font: "'Creepster', 'Chiller', 'Times New Roman'" }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); scoreText.y = 200; // High score text var highScoreText = new Text2('High Score: ' + highScore, { size: 80, fill: 0xFF0000, font: "'Creepster', 'Chiller', 'Times New Roman'" }); highScoreText.anchor.set(0.5, 0); LK.gui.top.addChild(highScoreText); highScoreText.y = 300; // Instructions text var instructionsText = new Text2('Watch the pattern, then repeat it', { size: 60, fill: 0xFF0000, font: "'Creepster', 'Chiller', 'Times New Roman'" }); instructionsText.anchor.set(0.5, 0); LK.gui.bottom.addChild(instructionsText); instructionsText.y = -150; // Status text var statusText = new Text2('Get ready...', { size: 85, fill: 0xFF0000, font: "'Creepster', 'Chiller', 'Times New Roman'" }); statusText.anchor.set(0.5, 0); LK.gui.center.addChild(statusText); statusText.y = -400; // Game functions function startGame(hellMode) { LK.playMusic('horrorAmbience', { fade: { start: 0, end: 0.4, duration: 1000 } }); gameState = STATE_SIMON_TURN; level = 1; sequence = []; horrorIntensity = 0; // Initialize glitch intensity based on mode glitchIntensity = hellMode ? 15 : 0; // Apply hell mode visual effects if enabled if (hellMode) { // Add dark overlay tween(overlay, { alpha: 0.3 // Persistent dark overlay }, { duration: 500 }); // Turn text bloody red var textElements = [levelText, scoreText, highScoreText, instructionsText, statusText]; textElements.forEach(function (text) { tween(text, { tint: 0xff0000 }, { duration: 500 }); }); } // Show UI elements levelText.visible = true; scoreText.visible = true; highScoreText.visible = true; instructionsText.visible = true; // Show game elements buttons.forEach(function (button) { button.visible = true; }); entity.visible = true; updateLevel(); LK.setScore(0); updateScore(); generateSequence(); // Add more steps to sequence for hell mode if (hellMode) { for (var i = 0; i < 3; i++) { sequence.push(Math.floor(Math.random() * 4)); } statusText.setText("WELCOME TO HELL MODE"); } // Start the first round LK.setTimeout(function () { playSequence(); }, 1500); } function updateLevel() { levelText.setText('Level: ' + level); } function updateScore() { scoreText.setText('Score: ' + LK.getScore()); if (LK.getScore() > highScore) { highScore = LK.getScore(); storage.highScore = highScore; highScoreText.setText('High Score: ' + highScore); } // Update glitch intensity based on current score glitchIntensity = Math.min(LK.getScore() / 10, 10); } function generateSequence() { // Add a new step to the sequence sequence.push(Math.floor(Math.random() * 4)); playerSequence = []; sequenceIndex = 0; } function playSequence() { statusText.setText("Watch carefully..."); // Flash the entity briefly before showing the sequence // Intensity increases with level horrorIntensity = Math.min(level - 1, 10); entity.appear(horrorIntensity); // Start showing sequence after entity appears sequenceIndex = 0; waitingForInput = true; LK.setTimeout(function () { playNextInSequence(); }, 2000); } function playNextInSequence() { if (sequenceIndex < sequence.length) { buttons[sequence[sequenceIndex]].activate(); // Sequence timing gets faster as level increases var delay = Math.max(1000 - level * 50, 400); // Apply glitch effects to sequence timing if (glitchIntensity > 2) { // Add random timing variations var randomOffset = (Math.random() - 0.5) * 200 * (glitchIntensity / 10); delay = Math.max(200, delay + randomOffset); // Much more chaotic in hell mode if (glitchIntensity >= 15) { // Extremely unpredictable timing in hell mode - more random in hell mode delay = Math.max(150, Math.random() * 2000); // Completely random delay between 150ms and 2000ms // Random button flashes during sequence if (Math.random() < 0.3) { // Increased probability // Flash multiple wrong buttons to confuse player var distractionCount = Math.floor(Math.random() * 3) + 1; // More distractions for (var i = 0; i < distractionCount; i++) { var wrongButtonIndex = Math.floor(Math.random() * 4); var distractionDelay = Math.random() * delay * 0.8; LK.setTimeout(function (wrongIdx) { return function () { buttons[wrongIdx].activate(); }; }(wrongButtonIndex), distractionDelay); } } // Occasionally briefly rotate the game container if (Math.random() < 0.25) { // Increased probability var originalRotation = game.rotation; var glitchRotation = (Math.random() - 0.5) * 0.2; // More extreme rotation tween(game, { rotation: glitchRotation }, { duration: 100, onFinish: function onFinish() { tween(game, { rotation: originalRotation }, { duration: 100 }); } }); } } // Occasionally show wrong button at higher glitch levels else if (glitchIntensity > 6 && Math.random() < 0.15 && sequenceIndex > 0) { // Activate a random wrong button very briefly var wrongButtonIndex; do { wrongButtonIndex = Math.floor(Math.random() * 4); } while (wrongButtonIndex === sequence[sequenceIndex]); // Show wrong button briefly LK.setTimeout(function () { buttons[wrongButtonIndex].activate(); }, delay / 3); } } LK.setTimeout(function () { sequenceIndex++; playNextInSequence(); }, delay); } else { // Done showing sequence, player's turn LK.setTimeout(function () { waitingForInput = false; gameState = STATE_PLAYER_TURN; statusText.setText("Your turn!"); playerSequence = []; sequenceIndex = 0; }, 500); } } function checkPlayerInput() { var currentIndex = playerSequence.length - 1; if (playerSequence[currentIndex] !== sequence[currentIndex]) { // Wrong input gameOver(); return; } // If the player has completed the current sequence if (playerSequence.length === sequence.length) { // Level completed waitingForInput = true; LK.setScore(LK.getScore() + sequence.length); updateScore(); level++; updateLevel(); // Check if player has reached score 35 if (LK.getScore() >= 35) { var applyButtonGlitch = function applyButtonGlitch(button) { var originalX = button.x; var originalY = button.y; tween(button, { x: originalX + (Math.random() - 0.5) * 30, y: originalY + (Math.random() - 0.5) * 20, alpha: 0.7 + Math.random() * 0.3 }, { duration: 100, onFinish: function onFinish() { tween(button, { x: originalX, y: originalY, alpha: 1 }, { duration: 100 }); } }); }; // Apply periodic glitches // Create continue option container var continueOption = new Container(); continueOption.x = 2048 / 2; continueOption.y = 2732 / 2; // Create background var optionBg = continueOption.attachAsset('backgroundOverlay', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8, alpha: 0.8 }); // Hide all text elements levelText.visible = false; scoreText.visible = false; highScoreText.visible = false; instructionsText.visible = false; // Apply glitch effects to the background tween(optionBg, { alpha: 0.6, scaleX: 5.2, scaleY: 4.2 }, { duration: 300, yoyo: true, repeat: 3 }); // Create escape button var escapeButton = new Container(); var escapeBg = escapeButton.attachAsset('simonButtonGreen', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.5, scaleY: 0.8, alpha: 0.7 }); var escapeText = new Text2("ESCAPE", { size: 70, fill: 0xFFFFFF, font: "'Creepster', 'Chiller', 'Times New Roman'" }); escapeText.anchor.set(0.5, 0.5); escapeButton.addChild(escapeText); escapeButton.y = -50; // Adjusted position continueOption.addChild(escapeButton); // Create continue button var continueButton = new Container(); var continueBg = continueButton.attachAsset('simonButtonRed', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.5, scaleY: 0.8, alpha: 0.7 }); var continueText = new Text2("CONTINUE", { size: 70, fill: 0xFFFFFF, font: "'Creepster', 'Chiller', 'Times New Roman'" }); continueText.anchor.set(0.5, 0.5); continueButton.addChild(continueText); continueButton.y = 80; // Adjusted position continueOption.addChild(continueButton); // Apply glitch effects to buttons var glitchInterval = LK.setInterval(function () { applyButtonGlitch(escapeButton); applyButtonGlitch(continueButton); }, 1000); // Add event handlers escapeButton.down = function () { LK.clearInterval(glitchInterval); continueOption.destroy(); statusText.setText("You have escaped..."); // Create escape sequence with running figure var escapeSequence = game.addChild(new EscapeSequence()); escapeSequence.x = 2048 / 2; escapeSequence.y = 2732 / 2 - 100; // Start the escape sequence escapeSequence.startEscape(); // Hide game elements buttons.forEach(function (button) { tween(button, { alpha: 0 }, { duration: 500 }); }); // Fade overlay to create escape atmosphere tween(overlay, { alpha: 0.4 }, { duration: 800 }); }; continueButton.down = function () { LK.clearInterval(glitchInterval); continueOption.destroy(); // Make text elements visible again levelText.visible = true; scoreText.visible = true; highScoreText.visible = true; instructionsText.visible = true; statusText.setText("The nightmare continues..."); LK.setTimeout(function () { gameState = STATE_SIMON_TURN; generateSequence(); playSequence(); }, 1500); }; // Add to game game.addChild(continueOption); // Disable game state to prevent interactions with Simon buttons waitingForInput = true; gameState = STATE_SIMON_TURN; return; } gameState = STATE_SIMON_TURN; // Horror effect between levels tween(overlay, { alpha: 0.7 }, { duration: 500, onFinish: function onFinish() { LK.getSound('levelUpSound').play(); LK.setTimeout(function () { tween(overlay, { alpha: 0 }, { duration: 500 }); }, 500); } }); statusText.setText("Level " + level + "!"); // Start next level after a delay LK.setTimeout(function () { generateSequence(); playSequence(); }, 2000); } } function gameOver() { gameState = STATE_GAME_OVER; // Jumpscare effect entity.jumpscare(); LK.getSound('errorSound').play(); // Flash screen red LK.effects.flashScreen(0xff0000, 800); statusText.setText("Game Over!"); LK.setTimeout(function () { // Create restart button var restartButton = new Container(); var restartButtonBg = restartButton.attachAsset('simonButtonRed', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 1, alpha: 0.7 }); var restartText = new Text2('PLAY AGAIN', { size: 80, fill: 0xFFFFFF, font: "'Creepster', 'Chiller', 'Times New Roman'" }); restartText.anchor.set(0.5, 0.5); restartButton.addChild(restartText); restartButton.x = 2048 / 2; restartButton.y = 2732 / 2 + 300; LK.gui.center.addChild(restartButton); // Add touch handler for restart button restartButton.down = function () { restartButton.destroy(); LK.showGameOver(); }; LK.showGameOver(); }, 1500); } // Create shadow figure for intro var shadowFigure = game.addChild(new ShadowFigure()); shadowFigure.x = 2048 / 2; shadowFigure.y = 2732 / 2; // Hide game elements initially buttons.forEach(function (button) { button.visible = false; }); entity.visible = false; // Start intro dialogue when loaded LK.setTimeout(function () { shadowFigure.startDialogue(); }, 1000); // Game update function game.update = function () { // Apply glitch effects based on score if (gameState !== STATE_GAME_OVER && glitchIntensity > 0) { // Apply UI glitches when score increases if (LK.ticks % 60 === 0 && Math.random() < 0.1 * glitchIntensity) { // Random text color changes var randomColor = Math.floor(Math.random() * 0xFFFFFF); var targetText = Math.random() < 0.5 ? levelText : scoreText; tween(targetText, { tint: randomColor }, { duration: 300, onFinish: function onFinish() { tween(targetText, { tint: 0xFF0000 }, { duration: 200 }); } }); } // Random button position jitter at higher scores if (glitchIntensity > 3 && Math.random() < 0.02 * glitchIntensity) { var randomButton = buttons[Math.floor(Math.random() * buttons.length)]; var originalX = randomButton.x; var originalY = randomButton.y; var offsetX = (Math.random() - 0.5) * 20 * glitchIntensity; var offsetY = (Math.random() - 0.5) * 20 * glitchIntensity; tween(randomButton, { x: originalX + offsetX, y: originalY + offsetY }, { duration: 100, onFinish: function onFinish() { tween(randomButton, { x: originalX, y: originalY }, { duration: 100 }); } }); } // Screen distortion at higher scores if (glitchIntensity > 5 && Math.random() < 0.01 * glitchIntensity) { // Glitch overlay effect tween(overlay, { alpha: 0.2 + 0.05 * glitchIntensity }, { duration: 50, onFinish: function onFinish() { tween(overlay, { alpha: glitchIntensity >= 15 ? 0.3 : 0 }, { duration: 100 }); } }); } // Extreme glitches at very high scores if (glitchIntensity > 7 && Math.random() < 0.005 * glitchIntensity) { // Temporarily rotate the entire game container var originalRotation = game.rotation; var glitchRotation = (Math.random() - 0.5) * 0.05 * glitchIntensity; tween(game, { rotation: glitchRotation }, { duration: 100, onFinish: function onFinish() { tween(game, { rotation: originalRotation }, { duration: 150 }); } }); } // Hell mode specific glitches (glitchIntensity >= 15) if (glitchIntensity >= 15) { // Entity flickers more often in hell mode if (Math.random() < 0.02 && entity.alpha < 0.1) { entity.alpha = 0.4; LK.setTimeout(function () { entity.alpha = 0; }, 50); } // Occasionally make buttons flicker with wrong colors if (Math.random() < 0.01) { var randomButtonIndex = Math.floor(Math.random() * buttons.length); var wrongButtonAsset; do { var wrongColor = [COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_YELLOW][Math.floor(Math.random() * 4)]; wrongButtonAsset = 'simonButton' + wrongColor; } while (buttons[randomButtonIndex].id === wrongColor); // Briefly show wrong color on button var originalAlpha = buttons[randomButtonIndex].alpha; buttons[randomButtonIndex].alpha = 0.7; LK.setTimeout(function () { buttons[randomButtonIndex].alpha = originalAlpha; }, 50 + Math.random() * 100); } // Occasionally distort status text in hell mode if (LK.ticks % 120 === 0 && Math.random() < 0.3) { var originalSize = statusText.style.size; var originalY = statusText.y; // Distort text statusText.style.size = originalSize * (0.8 + Math.random() * 0.4); statusText.y = originalY + (Math.random() - 0.5) * 50; // Reset after brief period LK.setTimeout(function () { statusText.style.size = originalSize; statusText.y = originalY; }, 200); } // Random screen shake in hell mode if (Math.random() < 0.005) { var shakeIntensity = 5 + Math.random() * 10; var originalX = game.x; var originalY = game.y; var shakeInterval = LK.setInterval(function () { game.x = originalX + (Math.random() - 0.5) * shakeIntensity; game.y = originalY + (Math.random() - 0.5) * shakeIntensity; }, 50); LK.setTimeout(function () { LK.clearInterval(shakeInterval); game.x = originalX; game.y = originalY; }, 300); } } } // Add subtle horror effects as the game progresses if (gameState !== STATE_GAME_OVER && level > 3) { // Random subtle screen flicker if (Math.random() < 0.005 * horrorIntensity) { tween(overlay, { alpha: 0.2 }, { duration: 100, onFinish: function onFinish() { tween(overlay, { alpha: 0 }, { duration: 100 }); } }); } // Random entity flicker at higher levels if (level > 5 && Math.random() < 0.002 * horrorIntensity && entity.alpha < 0.1) { tween(entity, { alpha: 0.3 }, { duration: 50, onFinish: function onFinish() { tween(entity, { alpha: 0 }, { duration: 50 }); } }); } } }; // Event handlers game.down = function (x, y, obj) { // No need for intro handling, title screen has its own button };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var EscapeSequence = Container.expand(function () {
var self = Container.call(this);
// Running figure sprite
var runningFigure = new Container();
// Body shadow
var body = runningFigure.attachAsset('simonButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 1.2,
alpha: 0.8
});
// Head
var head = runningFigure.attachAsset('entityFace', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3,
y: -60,
alpha: 0.8
});
// Legs in running position
var leftLeg = runningFigure.attachAsset('simonButton', {
anchorX: 0.5,
anchorY: 0,
scaleX: 0.2,
scaleY: 0.5,
x: -20,
y: 60,
rotation: Math.PI / 6,
alpha: 0.8
});
var rightLeg = runningFigure.attachAsset('simonButton', {
anchorX: 0.5,
anchorY: 0,
scaleX: 0.2,
scaleY: 0.5,
x: 20,
y: 60,
rotation: -Math.PI / 6,
alpha: 0.8
});
// Arms in running position
var leftArm = runningFigure.attachAsset('simonButton', {
anchorX: 0.5,
anchorY: 0,
scaleX: 0.2,
scaleY: 0.4,
x: -25,
y: -20,
rotation: -Math.PI / 4,
alpha: 0.8
});
var rightArm = runningFigure.attachAsset('simonButton', {
anchorX: 0.5,
anchorY: 0,
scaleX: 0.2,
scaleY: 0.4,
x: 25,
y: -20,
rotation: Math.PI / 4,
alpha: 0.8
});
// Add the running figure to self
self.addChild(runningFigure);
// Dialogue box
var dialogueBox = new Container();
dialogueBox.y = 600;
var dialogueBackground = dialogueBox.attachAsset('simonButtonGreen', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4.5,
scaleY: 1.5,
alpha: 0.7
});
// Dialogue text
var dialogueText = new Text2('', {
size: 60,
fill: 0xFFFFFF,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
dialogueText.anchor.set(0.5, 0.5);
dialogueBox.addChild(dialogueText);
self.addChild(dialogueBox);
// Animation state variables
self.animationFrame = 0;
self.runningSpeed = 15;
self.direction = -1; // -1 for running left, 1 for running right
// Method to start the escape sequence
self.startEscape = function () {
self.alpha = 0;
// Position initially on the right side
self.x = 2048 + 200;
self.direction = -1; // Run to the left initially
runningFigure.scale.x = self.direction;
// Play escape sound
LK.getSound('levelUpSound').play();
// Fade in sequence
tween(self, {
alpha: 1
}, {
duration: 1000,
easing: tween.easeIn,
onFinish: function onFinish() {
self.playDialogueSequence();
self.animateRunning();
}
});
};
// Simplified movement without animation
self.animateRunning = function () {
// Move the figure without animating limbs
self.x += self.direction * self.runningSpeed;
// Check if we need to turn around
if (self.x < -200 || self.x > 2048 + 200) {
self.direction *= -1;
runningFigure.scale.x = self.direction;
}
// Continue movement
LK.setTimeout(self.animateRunning, 50);
};
// Play the dialogue sequence
self.playDialogueSequence = function () {
var dialogues = ["I have to get out of here!", "These shadows... they're watching me...", "I can feel the darkness trying to pull me back...", "That entity... it's toying with me.", "Is this really happening? Or am I still trapped?", "The patterns... I can still see them when I close my eyes...", "I think I'm finally free... but at what cost?", "Part of me will always be trapped in that place...", "I can hear the voices fading... finally...", "Never look back. Just keep running."];
var currentDialogue = 0;
function showNextDialogue() {
if (currentDialogue < dialogues.length) {
dialogueText.setText(dialogues[currentDialogue]);
currentDialogue++;
// Schedule next dialogue
LK.setTimeout(showNextDialogue, 3000);
} else {
// End of dialogue sequence
self.finishEscape();
}
}
// Start the dialogue sequence
showNextDialogue();
};
// Finish the escape sequence
self.finishEscape = function () {
// Speed up running at the end
self.runningSpeed = 25;
// Make sure we're running to the left (away)
self.direction = -1;
runningFigure.scale.x = self.direction;
// Play victory sound
LK.getSound('levelUpSound').play();
// Fade out dialogue
tween(dialogueBox, {
alpha: 0
}, {
duration: 1000
});
// Run off screen then fade out
LK.setTimeout(function () {
tween(self, {
alpha: 0
}, {
duration: 1500,
onFinish: function onFinish() {
// Create restart button
var restartButton = new Container();
var restartButtonBg = restartButton.attachAsset('simonButtonGreen', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 1,
alpha: 0.7
});
var restartText = new Text2('PLAY AGAIN', {
size: 80,
fill: 0xFFFFFF,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
restartText.anchor.set(0.5, 0.5);
restartButton.addChild(restartText);
restartButton.x = 2048 / 2;
restartButton.y = 2732 / 2 + 300;
LK.gui.center.addChild(restartButton);
// Add touch handler for restart button
restartButton.down = function () {
restartButton.destroy();
LK.showYouWin();
};
// Show you win screen with the restart button
LK.showYouWin();
self.destroy();
}
});
}, 3000);
};
return self;
});
var GlitchEntity = Container.expand(function () {
var self = Container.call(this);
// Face from the entity that will glitch around
var face = self.attachAsset('entityFace', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.7
});
// Eyes that will move independently
var leftEye = self.attachAsset('entityEye', {
anchorX: 0.5,
anchorY: 0.5,
x: -65,
y: -55,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.9
});
var rightEye = self.attachAsset('entityEye', {
anchorX: 0.5,
anchorY: 0.5,
x: 65,
y: -55,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.9
});
// Mouth that will distort
var mouth = self.attachAsset('entityMouth', {
anchorX: 0.5,
anchorY: 0.5,
y: 100,
scaleX: 1.4,
scaleY: 1.2,
alpha: 0.9
});
// Dialogue box
var dialogueBox = new Container();
dialogueBox.y = 600;
var dialogueBackground = dialogueBox.attachAsset('simonButtonBlue', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4.5,
scaleY: 1.5,
alpha: 0.7
});
// Dialogue text
var dialogueText = new Text2('', {
size: 60,
fill: 0xFFFFFF,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
dialogueText.anchor.set(0.5, 0.5);
dialogueBox.addChild(dialogueText);
self.addChild(dialogueBox);
// Set initial state
self.alpha = 0;
// Glitch intervals
self.eyeGlitchInterval = null;
self.mouthGlitchInterval = null;
self.faceGlitchInterval = null;
self.randomSpritesInterval = null;
self.sprites = [];
// Start glitch sequence
self.startGlitch = function () {
self.alpha = 0;
// Play creepy sound
LK.getSound('creepyLaugh').play();
// Fade in
tween(self, {
alpha: 1
}, {
duration: 1000,
easing: tween.easeIn,
onFinish: function onFinish() {
self.startGlitchEffects();
self.showGlitchDialogue();
}
});
};
// Generate random glitchy sprites
self.createRandomSprite = function () {
var sprite = new Container();
// Randomly select which element to use
var elements = ['entityEye', 'entityMouth', 'entityFace', 'simonButton', 'simonButtonRed', 'simonButtonGreen', 'simonButtonBlue', 'simonButtonYellow'];
var asset = elements[Math.floor(Math.random() * elements.length)];
var spriteGraphic = sprite.attachAsset(asset, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3 + Math.random() * 0.7,
scaleY: 0.3 + Math.random() * 0.7,
alpha: 0.1 + Math.random() * 0.4,
rotation: Math.random() * Math.PI * 2
});
// Position randomly on screen
sprite.x = Math.random() * 2048;
sprite.y = Math.random() * 2732;
// Add to game
game.addChild(sprite);
self.sprites.push(sprite);
// Apply glitch movement
self.glitchSpriteMovement(sprite);
// Remove after random time
LK.setTimeout(function () {
sprite.destroy();
var index = self.sprites.indexOf(sprite);
if (index !== -1) {
self.sprites.splice(index, 1);
}
}, 1000 + Math.random() * 5000);
};
// Apply random movement to sprites
self.glitchSpriteMovement = function (sprite) {
var originalX = sprite.x;
var originalY = sprite.y;
var randomX = originalX + (Math.random() - 0.5) * 300;
var randomY = originalY + (Math.random() - 0.5) * 300;
tween(sprite, {
x: randomX,
y: randomY,
rotation: Math.random() * Math.PI * 2,
alpha: 0.1 + Math.random() * 0.6,
scaleX: 0.2 + Math.random() * 1.0,
scaleY: 0.2 + Math.random() * 1.0
}, {
duration: 100 + Math.random() * 500,
onFinish: function onFinish() {
if (sprite.parent) {
self.glitchSpriteMovement(sprite);
}
}
});
};
// Start all glitch effects
self.startGlitchEffects = function () {
// Start eyes moving randomly
self.eyeGlitchInterval = LK.setInterval(function () {
tween(leftEye, {
x: -65 + (Math.random() - 0.5) * 150,
y: -55 + (Math.random() - 0.5) * 150,
rotation: Math.random() * Math.PI * 2,
scaleX: 0.8 + Math.random() * 1.0,
scaleY: 0.8 + Math.random() * 1.0
}, {
duration: 50 + Math.random() * 100
});
tween(rightEye, {
x: 65 + (Math.random() - 0.5) * 150,
y: -55 + (Math.random() - 0.5) * 150,
rotation: Math.random() * Math.PI * 2,
scaleX: 0.8 + Math.random() * 1.0,
scaleY: 0.8 + Math.random() * 1.0
}, {
duration: 50 + Math.random() * 100
});
}, 150);
// Mouth distortion
self.mouthGlitchInterval = LK.setInterval(function () {
tween(mouth, {
x: (Math.random() - 0.5) * 100,
y: 100 + (Math.random() - 0.5) * 50,
scaleX: 0.5 + Math.random() * 2.0,
scaleY: 0.5 + Math.random() * 1.0,
rotation: (Math.random() - 0.5) * 0.5
}, {
duration: 50 + Math.random() * 150
});
}, 200);
// Face distortion
self.faceGlitchInterval = LK.setInterval(function () {
tween(face, {
scaleX: 1.3 + (Math.random() - 0.5) * 0.5,
scaleY: 1.3 + (Math.random() - 0.5) * 0.5,
rotation: (Math.random() - 0.5) * 0.2
}, {
duration: 100 + Math.random() * 200
});
// Screen shake
var shakeIntensity = 5 + Math.random() * 15;
var originalX = game.x;
var originalY = game.y;
var shakeCount = 0;
var maxShakes = 5 + Math.floor(Math.random() * 5);
var shakeInterval = LK.setInterval(function () {
game.x = originalX + (Math.random() - 0.5) * shakeIntensity;
game.y = originalY + (Math.random() - 0.5) * shakeIntensity;
shakeCount++;
if (shakeCount >= maxShakes) {
LK.clearInterval(shakeInterval);
game.x = originalX;
game.y = originalY;
}
}, 30);
}, 500);
// Create random sprites that appear and disappear
self.randomSpritesInterval = LK.setInterval(function () {
// Limit total sprites to avoid performance issues
if (self.sprites.length < 15) {
self.createRandomSprite();
}
}, 300);
};
// Show creepy dialogue
self.showGlitchDialogue = function () {
var dialogue = "w-why d-d-diiiid y-y-you do that,? you will be t-t-tr-tr-trapped here f-for eternity... I c-can f-f-feel y-your fear... it t-t-tastes s-so sweet... Y-your s-soul is m-mine now... T-there is n-no esc-c-cape... T-the d-darkness will c-c-consume you... F-forever in th-this n-nightmare... Y-your m-memories w-will fade... L-lost in th-this v-void... A-alone... F-forgotten... B-broken... E-every p-p-piece of y-you w-will d-d-dissolve into th-the v-void... Y-your c-consciousness w-will r-remain... a-aware... s-suffering... b-but p-powerless... T-trapped in a m-moment of p-pure t-terror... N-no one w-will r-remember y-you... T-time w-will n-never p-pass h-here... I will k-keep y-you here... FOREVER...";
// Break dialogue into chunks with random delays
var words = dialogue.split(' ');
var currentText = '';
var wordIndex = 0;
function showNextWord() {
if (wordIndex < words.length) {
currentText += words[wordIndex] + ' ';
dialogueText.setText(currentText);
wordIndex++;
// Random glitchy delay between words - slower than before
LK.setTimeout(showNextWord, 150 + Math.random() * 250);
} else {
// End of dialogue with final scream
dialogueText.setText(currentText + " o-oh n-n-n-nOOOOOOOOOOOOO!!!");
// Wait a bit before ending the glitch
LK.setTimeout(function () {
self.showTrappedEnding();
}, 3000);
}
}
showNextWord();
};
// Show trapped ending with white eyes around screen
self.showTrappedEnding = function () {
// First fade out the entity and dialogue
tween(face, {
alpha: 0
}, {
duration: 800
});
tween(leftEye, {
alpha: 0
}, {
duration: 800
});
tween(rightEye, {
alpha: 0
}, {
duration: 800
});
tween(mouth, {
alpha: 0
}, {
duration: 800
});
tween(dialogueBox, {
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
// Create white eyes around the edges
var eyes = [];
var eyeCount = 20;
// Create "Trapped ending" text
var trappedText = new Text2('Trapped ending', {
size: 150,
fill: 0xFFFFFF,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
trappedText.anchor.set(0.5, 0.5);
trappedText.alpha = 0;
game.addChild(trappedText);
trappedText.x = 2048 / 2;
trappedText.y = 2732 / 2;
// Create eyes around the screen edges
for (var i = 0; i < eyeCount; i++) {
var eye = new Container();
var eyeGraphic = eye.attachAsset('entityEye', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFFFFFF // White eyes
});
// Position around the edge of the screen
var angle = i / eyeCount * Math.PI * 2;
var radius = Math.min(2048, 2732) * 0.45; // Slightly inside the screen edge
eye.x = 2048 / 2 + Math.cos(angle) * radius;
eye.y = 2732 / 2 + Math.sin(angle) * radius;
// Make eyes look toward center
eye.rotation = angle + Math.PI; // Face toward center
eye.scale.set(0.8 + Math.random() * 0.4);
eye.alpha = 0;
game.addChild(eye);
eyes.push(eye);
}
// Fade in the eyes one by one
function fadeInEyes(index) {
if (index < eyes.length) {
tween(eyes[index], {
alpha: 0.7 + Math.random() * 0.3
}, {
duration: 100 + Math.random() * 200,
onFinish: function onFinish() {
fadeInEyes(index + 1);
}
});
} else {
// After all eyes appear, show the text
tween(trappedText, {
alpha: 1
}, {
duration: 1500,
onFinish: function onFinish() {
// Let the trapped ending display for a while before ending
LK.setTimeout(function () {
self.endGlitch(eyes, trappedText);
}, 5000);
}
});
}
}
// Start fading in eyes
fadeInEyes(0);
}
});
};
// End glitch sequence
self.endGlitch = function (eyes, trappedText) {
// Play error sound
LK.getSound('errorSound').play();
// Stop all glitch intervals
LK.clearInterval(self.eyeGlitchInterval);
LK.clearInterval(self.mouthGlitchInterval);
LK.clearInterval(self.faceGlitchInterval);
LK.clearInterval(self.randomSpritesInterval);
// Remove all sprites
self.sprites.forEach(function (sprite) {
sprite.destroy();
});
self.sprites = [];
// Reset game position
game.x = 0;
game.y = 0;
// If we have eyes and trapped text from the ending, fade them out
if (eyes && trappedText) {
// Fade out eyes
eyes.forEach(function (eye) {
tween(eye, {
alpha: 0
}, {
duration: 1000 + Math.random() * 500
});
});
// Fade out trapped text
tween(trappedText, {
alpha: 0
}, {
duration: 1500
});
}
// Fade out main container
tween(self, {
alpha: 0
}, {
duration: 1500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Create restart button
var restartButton = new Container();
var restartButtonBg = restartButton.attachAsset('simonButtonBlue', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 1,
alpha: 0.7
});
var restartText = new Text2('PLAY AGAIN', {
size: 80,
fill: 0xFFFFFF,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
restartText.anchor.set(0.5, 0.5);
restartButton.addChild(restartText);
restartButton.x = 2048 / 2;
restartButton.y = 2732 / 2 + 300;
LK.gui.center.addChild(restartButton);
// Add touch handler for restart button
restartButton.down = function () {
restartButton.destroy();
LK.showGameOver();
};
// Clean up by destroying all elements
if (eyes) {
eyes.forEach(function (eye) {
eye.destroy();
});
}
if (trappedText) {
trappedText.destroy();
}
self.destroy();
}
});
};
return self;
});
var ShadowFigure = Container.expand(function () {
var self = Container.call(this);
// Dark shadow shape
var shadowShape = self.attachAsset('simonButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 5,
scaleY: 10,
alpha: 0.8
});
// Face elements similar to entity but with different positions/scales
var face = self.attachAsset('entityFace', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5,
alpha: 0.7
});
// Eyes
var leftEye = self.attachAsset('entityEye', {
anchorX: 0.5,
anchorY: 0.5,
x: -65,
y: -55,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.9
});
var rightEye = self.attachAsset('entityEye', {
anchorX: 0.5,
anchorY: 0.5,
x: 65,
y: -55,
scaleX: 1.2,
scaleY: 1.2,
alpha: 0.9
});
// Mouth
var mouth = self.attachAsset('entityMouth', {
anchorX: 0.5,
anchorY: 0.5,
y: 100,
scaleX: 1.4,
scaleY: 1.2,
alpha: 0.9
});
// Dialogue box
var dialogueBox = new Container();
dialogueBox.y = 600;
var dialogueBackground = dialogueBox.attachAsset('simonButtonBlue', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4.5,
scaleY: 1.5,
alpha: 0.7
});
// Dialogue text
var dialogueText = new Text2('', {
size: 60,
fill: 0xFFFFFF,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
dialogueText.anchor.set(0.5, 0.5);
dialogueBox.addChild(dialogueText);
// Car crash image
var carCrashImage = new Container();
carCrashImage.y = -150;
carCrashImage.visible = false;
var crashBackground = carCrashImage.attachAsset('carCrashImage', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0,
alpha: 0.7
});
// Skip button
var skipButton = new Container();
var skipButtonBg = skipButton.attachAsset('simonButtonYellow', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 0.5,
alpha: 0.7
});
var skipText = new Text2('SKIP', {
size: 60,
fill: 0xFFFFFF,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
skipText.anchor.set(0.5, 0.5);
skipButton.addChild(skipText);
skipButton.x = 800;
skipButton.y = 900;
// Add touch handler for skip button
skipButton.down = function (x, y, obj) {
self.endDialogue();
};
// Add everything to self
self.addChild(dialogueBox);
self.addChild(carCrashImage);
self.addChild(skipButton);
// Ensure car crash image is in front by setting its zIndex
carCrashImage.zIndex = 100;
// Starting state
self.alpha = 0;
// Method to start dialogue sequence
self.startDialogue = function () {
self.alpha = 0;
// Play eerie ambience
LK.getSound('creepyLaugh').play();
// Stop jack-in-the-box music if it's playing
LK.stopMusic();
// Hide UI elements during dialogue
levelText.visible = false;
scoreText.visible = false;
highScoreText.visible = false;
instructionsText.visible = false;
statusText.setText("");
// Fade in sequence
tween(self, {
alpha: 1
}, {
duration: 2000,
easing: tween.easeIn,
onFinish: function onFinish() {
self.playDialogueSequence();
}
});
};
// Play the dialogue sequence
self.playDialogueSequence = function () {
var dialogues = ["Hello...", "Do you remember where you were before the incident?", "*shows blurry image of a person's perspective of driving a car*", "And now, you're here.", "I've been watching you for some time...", "Your thoughts, your fears, your regrets...", "They're all so... delicious.", "This place exists between reality and nightmare.", "A realm where I control everything.", "Your memories are fractured, aren't they?", "The crash wasn't your fault... or was it?", "The guilt you carry is what brought you to me.", "You must complete 35 levels of Simon Says to leave this place.", "With each level, a piece of your soul will return.", "Fail, and you'll remain here... forever.", "Others have tried before you. None have succeeded.", "Their echoes still linger in these walls.", "Can you hear them whispering?", "Follow the patterns. Don't make mistakes.", "Your sanity depends on it.", "Good luck.", "You'll need it.", "*shows devious smile before game starts*"];
var hellModeDialogues = ["Why would you do this to yourself?", "This isn't worth it...", "I didn't think you'd actually choose this path.", "I do want to see you suffer, though...", "Your mind will fracture in ways you cannot imagine.", "The patterns will blur, distort, and deceive you.", "Reality itself will bend against you.", "Time will stretch and contract at my whim.", "I've driven others to madness this way before.", "They clawed at their eyes trying to unsee what I showed them.", "They still scream in the void between thoughts...", "Can you feel them reaching for you even now?", "Their torment will become yours.", "Your soul will shatter into a thousand fragments.", "I will cherish collecting each broken piece...", "Your suffering will nourish me for centuries.", "The buttons themselves will become your enemies.", "Every touch will send tremors through your very being.", "I can feel your fear already... it's intoxicating.", "The others before you... they thought they were strong too.", "One by one, they surrendered to madness.", "Some begged for death before the end.", "Death would be a mercy I'm not willing to grant.", "Your fingers will tremble, your vision will blur.", "The nightmares will follow you even if you somehow escape.", "Your determination is... admirable, but futile.", "No one escapes the nightmare at this depth.", "Still, I'm eager to watch you try...", "Let your sanity slip away, piece by piece...", "G O O D L U C K . . .", "*shows horrific wide grin as face distorts unnaturally*"];
var currentDialogue = 0;
var isHellModeDialogue = false;
// Check if this is triggered from hell mode button
if (gameState === STATE_INTRO && window.hellButton && window.hellButton.alpha < 1) {
dialogues = hellModeDialogues;
isHellModeDialogue = true;
tween(mouth, {
scaleX: 3.0,
scaleY: 0.8
}, {
duration: 800
});
}
function showNextDialogue() {
if (currentDialogue < dialogues.length) {
var dialogue = dialogues[currentDialogue];
// Special cases
if (dialogue.includes("*shows blurry image")) {
// Show car crash image
carCrashImage.visible = true;
tween(carCrashImage, {
alpha: 0.9
}, {
duration: 500
});
dialogueText.setText("");
} else if (dialogue.includes("*shows devious smile") || dialogue.includes("*shows horrific wide grin")) {
// Show evil smile, more extreme for hell mode
var scaleX = isHellModeDialogue ? 3.5 : 2.5;
var scaleY = isHellModeDialogue ? 0.7 : 1.0;
tween(mouth, {
scaleX: scaleX,
scaleY: scaleY
}, {
duration: 800
});
dialogueText.setText("");
} else {
// Hide car crash image if visible
if (carCrashImage.visible) {
tween(carCrashImage, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
carCrashImage.visible = false;
}
});
}
// Normal dialogue
dialogueText.setText(dialogue);
}
currentDialogue++;
// Calculate delay - longer for showing images or evil smile
var delay = 3500; // Increased from 2000 to make dialogue slower
if (dialogue.includes("*")) {
delay = 5000; // Increased from 3000 for special scenes
}
// Schedule next dialogue
LK.setTimeout(showNextDialogue, delay);
} else {
// End of dialogue sequence
self.endDialogue();
}
}
// Start the dialogue sequence
showNextDialogue();
};
// End dialogue and transition to title screen
self.endDialogue = function () {
// Check whether we're in intro dialogue or hell mode dialogue
var showTitleScreen = gameState === STATE_INTRO_DIALOGUE;
var isHellMode = gameState === STATE_INTRO && window.hellButton && window.hellButton.alpha < 1;
tween(self, {
alpha: 0
}, {
duration: 1500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Only show title screen if we're in the intro state and not coming from hell button
if (showTitleScreen) {
// Make sure all UI elements are hidden before showing title screen
levelText.visible = false;
scoreText.visible = false;
highScoreText.visible = false;
instructionsText.visible = false;
// Create title screen
var titleScreen = game.addChild(new TitleScreen());
titleScreen.x = 2048 / 2;
titleScreen.y = 2732 / 2;
gameState = STATE_INTRO;
} else if (isHellMode) {
// If coming from hell button click, start hell mode
if (window.hellButton) {
// Restore title screen visibility first
var titleScreen = window.hellButton.parent;
tween(titleScreen, {
alpha: 1
}, {
duration: 500,
onFinish: function onFinish() {
// Start hell mode
titleScreen.startGame(true);
// Reset hellButton reference
window.hellButton = null;
}
});
}
}
statusText.setText("");
self.destroy();
}
});
};
return self;
});
var SimonButton = Container.expand(function (color, sound, id) {
var self = Container.call(this);
self.id = id;
self.isActive = false;
self.sound = sound;
self.isHovering = false;
self.shakeInterval = null;
var buttonGraphics = self.attachAsset('simonButton', {
anchorX: 0.5,
anchorY: 0.5
});
var activeButtonAsset = 'simonButton' + color;
var activeButtonGraphics = self.attachAsset(activeButtonAsset, {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0
});
self.activate = function () {
if (self.isActive) {
return;
}
self.isActive = true;
// Apply glitch effects to button activation based on score
var activationDuration = 300;
var fadeDuration = 300;
var glitchScale = 1;
// Play sound immediately when button is activated
LK.getSound(self.sound).play();
// Modify button behavior based on glitch intensity
if (glitchIntensity > 0) {
// Random duration variations
activationDuration = Math.max(100, 300 - glitchIntensity * 20);
fadeDuration = Math.max(100, 300 - glitchIntensity * 15);
// Random scale effects
if (glitchIntensity > 3 && Math.random() < 0.3) {
glitchScale = 1 + Math.random() * 0.3 * glitchIntensity;
// Apply temporary scale effect
buttonGraphics.scale.set(glitchScale);
LK.setTimeout(function () {
buttonGraphics.scale.set(1);
}, activationDuration);
}
}
tween(activeButtonGraphics, {
alpha: 1
}, {
duration: activationDuration,
onFinish: function onFinish() {
tween(activeButtonGraphics, {
alpha: 0
}, {
duration: fadeDuration,
onFinish: function onFinish() {
self.isActive = false;
}
});
}
});
};
self.down = function (x, y, obj) {
if (gameState === STATE_PLAYER_TURN && !self.isActive && !waitingForInput) {
self.activate();
playerSequence.push(self.id);
checkPlayerInput();
}
};
// Add move handler for hover effect in hell mode
self.move = function (x, y, obj) {
if (glitchIntensity >= 15 && !self.isHovering) {
self.isHovering = true;
// Create violent screen shake when hovering in hell mode
var shakeIntensity = 15 + Math.random() * 15;
var originalX = game.x;
var originalY = game.y;
// Clear any existing shake interval
if (self.shakeInterval) {
LK.clearInterval(self.shakeInterval);
}
// Create new shake interval
self.shakeInterval = LK.setInterval(function () {
game.x = originalX + (Math.random() - 0.5) * shakeIntensity;
game.y = originalY + (Math.random() - 0.5) * shakeIntensity;
}, 30);
// Also add button pulsing effect
tween(buttonGraphics, {
scaleX: 1.1,
scaleY: 1.1,
alpha: 0.8
}, {
duration: 200
});
}
};
// Add out handler to stop shaking when not hovering
self.out = function () {
if (self.isHovering) {
self.isHovering = false;
// Stop the screen shake
if (self.shakeInterval) {
LK.clearInterval(self.shakeInterval);
self.shakeInterval = null;
// Reset game position
game.x = 0;
game.y = 0;
}
// Reset button appearance
tween(buttonGraphics, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 200
});
}
};
return self;
});
var SinisterEntity = Container.expand(function () {
var self = Container.call(this);
// Face base
var face = self.attachAsset('entityFace', {
anchorX: 0.5,
anchorY: 0.5
});
// Left eye
var leftEye = self.attachAsset('entityEye', {
anchorX: 0.5,
anchorY: 0.5,
x: -75,
y: -50
});
// Right eye
var rightEye = self.attachAsset('entityEye', {
anchorX: 0.5,
anchorY: 0.5,
x: 75,
y: -50
});
// Mouth
var mouth = self.attachAsset('entityMouth', {
anchorX: 0.5,
anchorY: 0.5,
y: 80
});
self.alpha = 0;
self.appear = function (intensity) {
self.alpha = 0;
// Scale intensity from 0-10 to meaningful values
var duration = Math.max(1000 - intensity * 80, 200);
var scaleFactor = 1 + intensity * 0.1;
tween(self, {
alpha: 1
}, {
duration: duration,
easing: tween.easeIn,
onFinish: function onFinish() {
// Make eyes look at player
tween(leftEye, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
easing: tween.easeOut
});
tween(rightEye, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
easing: tween.easeOut
});
// Make mouth grow wider
tween(mouth, {
scaleX: 1.8,
scaleY: 0.8
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
if (intensity > 5) {
LK.getSound('creepyLaugh').play();
}
LK.setTimeout(function () {
self.disappear();
}, 1000);
}
});
}
});
};
self.disappear = function () {
tween(leftEye, {
scaleX: 1,
scaleY: 1
}, {
duration: 300
});
tween(rightEye, {
scaleX: 1,
scaleY: 1
}, {
duration: 300
});
tween(mouth, {
scaleX: 1,
scaleY: 1
}, {
duration: 300
});
tween(self, {
alpha: 0
}, {
duration: 500,
easing: tween.easeOut
});
};
self.jumpscare = function () {
self.alpha = 0;
self.scale.set(0.1);
tween(self, {
alpha: 1,
scaleX: 3,
scaleY: 3
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
LK.setTimeout(function () {
tween(self, {
alpha: 0
}, {
duration: 400,
easing: tween.easeIn
});
}, 200);
}
});
};
return self;
});
var TitleScreen = Container.expand(function () {
var self = Container.call(this);
// Play jack-in-the-box music for title screen
LK.playMusic('jackInTheBoxMusic', {
fade: {
start: 0,
end: 0.7,
duration: 1500
}
});
// Title text
var titleText = new Text2('Sinister Simon', {
size: 150,
fill: 0xFF0000,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -400;
self.addChild(titleText);
// Subtitle text
var subtitleText = new Text2('A game of memory and fear', {
size: 70,
fill: 0xFF0000,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.y = -280;
self.addChild(subtitleText);
// Start button
var startButton = new Container();
var startButtonBg = startButton.attachAsset('simonButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 1,
alpha: 0.7
});
var startText = new Text2('START GAME', {
size: 80,
fill: 0xFFFFFF,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
startText.anchor.set(0.5, 0.5);
startButton.addChild(startText);
startButton.y = 100;
self.addChild(startButton);
// Hell mode button
var hellButton = new Container();
var hellBg = hellButton.attachAsset('simonButtonRed', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 1,
alpha: 0.7
});
var hellText = new Text2('HELL MODE', {
size: 80,
fill: 0xFFFFFF,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
hellText.anchor.set(0.5, 0.5);
hellButton.addChild(hellText);
hellButton.y = 500;
self.addChild(hellButton);
// Add touch handler for start button
startButton.down = function (x, y, obj) {
self.startGame(false);
};
// Add touch handler for hell mode button
hellButton.down = function (x, y, obj) {
// Create shadow figure for hell mode warning
var hellFigure = game.addChild(new ShadowFigure());
hellFigure.x = 2048 / 2;
hellFigure.y = 2732 / 2;
// Fade out title screen temporarily
tween(self, {
alpha: 0.2
}, {
duration: 1000
});
// Store reference to hell button for the dialogue system
window.hellButton = hellButton;
// Prevent double-clicking
hellButton.alpha = 0.5;
// Trigger hell mode dialogue
LK.setTimeout(function () {
hellFigure.startDialogue();
// After dialogue, the shadow figure will automatically start hell mode
gameState = STATE_INTRO;
}, 500);
};
// Add glitch button in the bottom right corner
var glitchButton = new Container();
var glitchBg = glitchButton.attachAsset('simonButtonBlue', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.7,
scaleY: 0.7,
alpha: 0.3
});
var glitchText = new Text2('???', {
size: 70,
fill: 0xFFFFFF,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
glitchText.anchor.set(0.5, 0.5);
glitchButton.addChild(glitchText);
glitchButton.x = 900;
glitchButton.y = 700;
self.addChild(glitchButton);
// Add touch handler for glitch button
glitchButton.down = function (x, y, obj) {
// Prevent double-clicking
glitchButton.alpha = 0.2;
// Stop the jack-in-the-box music
LK.stopMusic();
// Fade out everything on screen
tween(self, {
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
// Create glitch entity
var glitchEntity = game.addChild(new GlitchEntity());
glitchEntity.x = 2048 / 2;
glitchEntity.y = 2732 / 2;
// Start glitch sequence
glitchEntity.startGlitch();
}
});
};
// Method to start the game
self.startGame = function (hellMode) {
// Stop the jack-in-the-box music
LK.stopMusic();
tween(self, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
startGame(hellMode);
self.destroy();
}
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Constants
var STATE_INTRO_DIALOGUE = 0;
var STATE_INTRO = 1;
var STATE_SIMON_TURN = 2;
var STATE_PLAYER_TURN = 3;
var STATE_GAME_OVER = 4;
var COLOR_RED = 'Red';
var COLOR_GREEN = 'Green';
var COLOR_BLUE = 'Blue';
var COLOR_YELLOW = 'Yellow';
// Game variables
var gameState = STATE_INTRO_DIALOGUE;
var level = 1;
var sequence = [];
var playerSequence = [];
var sequenceIndex = 0;
var waitingForInput = false;
var horrorIntensity = 0;
var glitchIntensity = 0; // Track glitch effects based on score
var highScore = storage.highScore || 0;
// Overlay for horror effects
var overlay = game.addChild(LK.getAsset('backgroundOverlay', {
anchorX: 0,
anchorY: 0,
alpha: 0
}));
// Create Simon buttons
var buttonSize = 400;
var spacing = 50;
var totalWidth = buttonSize * 2 + spacing;
var totalHeight = buttonSize * 2 + spacing;
var startX = (2048 - totalWidth) / 2 + buttonSize / 2;
var startY = (2732 - totalHeight) / 2 + buttonSize / 2;
var buttons = [];
var buttonRed = game.addChild(new SimonButton(COLOR_RED, 'buttonSound1', 0));
buttonRed.x = startX;
buttonRed.y = startY;
buttons.push(buttonRed);
var buttonGreen = game.addChild(new SimonButton(COLOR_GREEN, 'buttonSound2', 1));
buttonGreen.x = startX + buttonSize + spacing;
buttonGreen.y = startY;
buttons.push(buttonGreen);
var buttonBlue = game.addChild(new SimonButton(COLOR_BLUE, 'buttonSound3', 2));
buttonBlue.x = startX;
buttonBlue.y = startY + buttonSize + spacing;
buttons.push(buttonBlue);
var buttonYellow = game.addChild(new SimonButton(COLOR_YELLOW, 'buttonSound4', 3));
buttonYellow.x = startX + buttonSize + spacing;
buttonYellow.y = startY + buttonSize + spacing;
buttons.push(buttonYellow);
// Create the sinister entity
var entity = game.addChild(new SinisterEntity());
entity.x = 2048 / 2;
entity.y = 2732 / 2;
// Level text
var levelText = new Text2('Level: 1', {
size: 80,
fill: 0xFF0000,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
levelText.anchor.set(0.5, 0);
LK.gui.top.addChild(levelText);
levelText.y = 100;
// Score text
var scoreText = new Text2('Score: 0', {
size: 80,
fill: 0xFF0000,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
scoreText.y = 200;
// High score text
var highScoreText = new Text2('High Score: ' + highScore, {
size: 80,
fill: 0xFF0000,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
highScoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(highScoreText);
highScoreText.y = 300;
// Instructions text
var instructionsText = new Text2('Watch the pattern, then repeat it', {
size: 60,
fill: 0xFF0000,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
instructionsText.anchor.set(0.5, 0);
LK.gui.bottom.addChild(instructionsText);
instructionsText.y = -150;
// Status text
var statusText = new Text2('Get ready...', {
size: 85,
fill: 0xFF0000,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
statusText.anchor.set(0.5, 0);
LK.gui.center.addChild(statusText);
statusText.y = -400;
// Game functions
function startGame(hellMode) {
LK.playMusic('horrorAmbience', {
fade: {
start: 0,
end: 0.4,
duration: 1000
}
});
gameState = STATE_SIMON_TURN;
level = 1;
sequence = [];
horrorIntensity = 0;
// Initialize glitch intensity based on mode
glitchIntensity = hellMode ? 15 : 0;
// Apply hell mode visual effects if enabled
if (hellMode) {
// Add dark overlay
tween(overlay, {
alpha: 0.3 // Persistent dark overlay
}, {
duration: 500
});
// Turn text bloody red
var textElements = [levelText, scoreText, highScoreText, instructionsText, statusText];
textElements.forEach(function (text) {
tween(text, {
tint: 0xff0000
}, {
duration: 500
});
});
}
// Show UI elements
levelText.visible = true;
scoreText.visible = true;
highScoreText.visible = true;
instructionsText.visible = true;
// Show game elements
buttons.forEach(function (button) {
button.visible = true;
});
entity.visible = true;
updateLevel();
LK.setScore(0);
updateScore();
generateSequence();
// Add more steps to sequence for hell mode
if (hellMode) {
for (var i = 0; i < 3; i++) {
sequence.push(Math.floor(Math.random() * 4));
}
statusText.setText("WELCOME TO HELL MODE");
}
// Start the first round
LK.setTimeout(function () {
playSequence();
}, 1500);
}
function updateLevel() {
levelText.setText('Level: ' + level);
}
function updateScore() {
scoreText.setText('Score: ' + LK.getScore());
if (LK.getScore() > highScore) {
highScore = LK.getScore();
storage.highScore = highScore;
highScoreText.setText('High Score: ' + highScore);
}
// Update glitch intensity based on current score
glitchIntensity = Math.min(LK.getScore() / 10, 10);
}
function generateSequence() {
// Add a new step to the sequence
sequence.push(Math.floor(Math.random() * 4));
playerSequence = [];
sequenceIndex = 0;
}
function playSequence() {
statusText.setText("Watch carefully...");
// Flash the entity briefly before showing the sequence
// Intensity increases with level
horrorIntensity = Math.min(level - 1, 10);
entity.appear(horrorIntensity);
// Start showing sequence after entity appears
sequenceIndex = 0;
waitingForInput = true;
LK.setTimeout(function () {
playNextInSequence();
}, 2000);
}
function playNextInSequence() {
if (sequenceIndex < sequence.length) {
buttons[sequence[sequenceIndex]].activate();
// Sequence timing gets faster as level increases
var delay = Math.max(1000 - level * 50, 400);
// Apply glitch effects to sequence timing
if (glitchIntensity > 2) {
// Add random timing variations
var randomOffset = (Math.random() - 0.5) * 200 * (glitchIntensity / 10);
delay = Math.max(200, delay + randomOffset);
// Much more chaotic in hell mode
if (glitchIntensity >= 15) {
// Extremely unpredictable timing in hell mode - more random in hell mode
delay = Math.max(150, Math.random() * 2000); // Completely random delay between 150ms and 2000ms
// Random button flashes during sequence
if (Math.random() < 0.3) {
// Increased probability
// Flash multiple wrong buttons to confuse player
var distractionCount = Math.floor(Math.random() * 3) + 1; // More distractions
for (var i = 0; i < distractionCount; i++) {
var wrongButtonIndex = Math.floor(Math.random() * 4);
var distractionDelay = Math.random() * delay * 0.8;
LK.setTimeout(function (wrongIdx) {
return function () {
buttons[wrongIdx].activate();
};
}(wrongButtonIndex), distractionDelay);
}
}
// Occasionally briefly rotate the game container
if (Math.random() < 0.25) {
// Increased probability
var originalRotation = game.rotation;
var glitchRotation = (Math.random() - 0.5) * 0.2; // More extreme rotation
tween(game, {
rotation: glitchRotation
}, {
duration: 100,
onFinish: function onFinish() {
tween(game, {
rotation: originalRotation
}, {
duration: 100
});
}
});
}
}
// Occasionally show wrong button at higher glitch levels
else if (glitchIntensity > 6 && Math.random() < 0.15 && sequenceIndex > 0) {
// Activate a random wrong button very briefly
var wrongButtonIndex;
do {
wrongButtonIndex = Math.floor(Math.random() * 4);
} while (wrongButtonIndex === sequence[sequenceIndex]);
// Show wrong button briefly
LK.setTimeout(function () {
buttons[wrongButtonIndex].activate();
}, delay / 3);
}
}
LK.setTimeout(function () {
sequenceIndex++;
playNextInSequence();
}, delay);
} else {
// Done showing sequence, player's turn
LK.setTimeout(function () {
waitingForInput = false;
gameState = STATE_PLAYER_TURN;
statusText.setText("Your turn!");
playerSequence = [];
sequenceIndex = 0;
}, 500);
}
}
function checkPlayerInput() {
var currentIndex = playerSequence.length - 1;
if (playerSequence[currentIndex] !== sequence[currentIndex]) {
// Wrong input
gameOver();
return;
}
// If the player has completed the current sequence
if (playerSequence.length === sequence.length) {
// Level completed
waitingForInput = true;
LK.setScore(LK.getScore() + sequence.length);
updateScore();
level++;
updateLevel();
// Check if player has reached score 35
if (LK.getScore() >= 35) {
var applyButtonGlitch = function applyButtonGlitch(button) {
var originalX = button.x;
var originalY = button.y;
tween(button, {
x: originalX + (Math.random() - 0.5) * 30,
y: originalY + (Math.random() - 0.5) * 20,
alpha: 0.7 + Math.random() * 0.3
}, {
duration: 100,
onFinish: function onFinish() {
tween(button, {
x: originalX,
y: originalY,
alpha: 1
}, {
duration: 100
});
}
});
}; // Apply periodic glitches
// Create continue option container
var continueOption = new Container();
continueOption.x = 2048 / 2;
continueOption.y = 2732 / 2;
// Create background
var optionBg = continueOption.attachAsset('backgroundOverlay', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8,
alpha: 0.8
});
// Hide all text elements
levelText.visible = false;
scoreText.visible = false;
highScoreText.visible = false;
instructionsText.visible = false;
// Apply glitch effects to the background
tween(optionBg, {
alpha: 0.6,
scaleX: 5.2,
scaleY: 4.2
}, {
duration: 300,
yoyo: true,
repeat: 3
});
// Create escape button
var escapeButton = new Container();
var escapeBg = escapeButton.attachAsset('simonButtonGreen', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 0.8,
alpha: 0.7
});
var escapeText = new Text2("ESCAPE", {
size: 70,
fill: 0xFFFFFF,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
escapeText.anchor.set(0.5, 0.5);
escapeButton.addChild(escapeText);
escapeButton.y = -50; // Adjusted position
continueOption.addChild(escapeButton);
// Create continue button
var continueButton = new Container();
var continueBg = continueButton.attachAsset('simonButtonRed', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 0.8,
alpha: 0.7
});
var continueText = new Text2("CONTINUE", {
size: 70,
fill: 0xFFFFFF,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
continueText.anchor.set(0.5, 0.5);
continueButton.addChild(continueText);
continueButton.y = 80; // Adjusted position
continueOption.addChild(continueButton);
// Apply glitch effects to buttons
var glitchInterval = LK.setInterval(function () {
applyButtonGlitch(escapeButton);
applyButtonGlitch(continueButton);
}, 1000);
// Add event handlers
escapeButton.down = function () {
LK.clearInterval(glitchInterval);
continueOption.destroy();
statusText.setText("You have escaped...");
// Create escape sequence with running figure
var escapeSequence = game.addChild(new EscapeSequence());
escapeSequence.x = 2048 / 2;
escapeSequence.y = 2732 / 2 - 100;
// Start the escape sequence
escapeSequence.startEscape();
// Hide game elements
buttons.forEach(function (button) {
tween(button, {
alpha: 0
}, {
duration: 500
});
});
// Fade overlay to create escape atmosphere
tween(overlay, {
alpha: 0.4
}, {
duration: 800
});
};
continueButton.down = function () {
LK.clearInterval(glitchInterval);
continueOption.destroy();
// Make text elements visible again
levelText.visible = true;
scoreText.visible = true;
highScoreText.visible = true;
instructionsText.visible = true;
statusText.setText("The nightmare continues...");
LK.setTimeout(function () {
gameState = STATE_SIMON_TURN;
generateSequence();
playSequence();
}, 1500);
};
// Add to game
game.addChild(continueOption);
// Disable game state to prevent interactions with Simon buttons
waitingForInput = true;
gameState = STATE_SIMON_TURN;
return;
}
gameState = STATE_SIMON_TURN;
// Horror effect between levels
tween(overlay, {
alpha: 0.7
}, {
duration: 500,
onFinish: function onFinish() {
LK.getSound('levelUpSound').play();
LK.setTimeout(function () {
tween(overlay, {
alpha: 0
}, {
duration: 500
});
}, 500);
}
});
statusText.setText("Level " + level + "!");
// Start next level after a delay
LK.setTimeout(function () {
generateSequence();
playSequence();
}, 2000);
}
}
function gameOver() {
gameState = STATE_GAME_OVER;
// Jumpscare effect
entity.jumpscare();
LK.getSound('errorSound').play();
// Flash screen red
LK.effects.flashScreen(0xff0000, 800);
statusText.setText("Game Over!");
LK.setTimeout(function () {
// Create restart button
var restartButton = new Container();
var restartButtonBg = restartButton.attachAsset('simonButtonRed', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 1,
alpha: 0.7
});
var restartText = new Text2('PLAY AGAIN', {
size: 80,
fill: 0xFFFFFF,
font: "'Creepster', 'Chiller', 'Times New Roman'"
});
restartText.anchor.set(0.5, 0.5);
restartButton.addChild(restartText);
restartButton.x = 2048 / 2;
restartButton.y = 2732 / 2 + 300;
LK.gui.center.addChild(restartButton);
// Add touch handler for restart button
restartButton.down = function () {
restartButton.destroy();
LK.showGameOver();
};
LK.showGameOver();
}, 1500);
}
// Create shadow figure for intro
var shadowFigure = game.addChild(new ShadowFigure());
shadowFigure.x = 2048 / 2;
shadowFigure.y = 2732 / 2;
// Hide game elements initially
buttons.forEach(function (button) {
button.visible = false;
});
entity.visible = false;
// Start intro dialogue when loaded
LK.setTimeout(function () {
shadowFigure.startDialogue();
}, 1000);
// Game update function
game.update = function () {
// Apply glitch effects based on score
if (gameState !== STATE_GAME_OVER && glitchIntensity > 0) {
// Apply UI glitches when score increases
if (LK.ticks % 60 === 0 && Math.random() < 0.1 * glitchIntensity) {
// Random text color changes
var randomColor = Math.floor(Math.random() * 0xFFFFFF);
var targetText = Math.random() < 0.5 ? levelText : scoreText;
tween(targetText, {
tint: randomColor
}, {
duration: 300,
onFinish: function onFinish() {
tween(targetText, {
tint: 0xFF0000
}, {
duration: 200
});
}
});
}
// Random button position jitter at higher scores
if (glitchIntensity > 3 && Math.random() < 0.02 * glitchIntensity) {
var randomButton = buttons[Math.floor(Math.random() * buttons.length)];
var originalX = randomButton.x;
var originalY = randomButton.y;
var offsetX = (Math.random() - 0.5) * 20 * glitchIntensity;
var offsetY = (Math.random() - 0.5) * 20 * glitchIntensity;
tween(randomButton, {
x: originalX + offsetX,
y: originalY + offsetY
}, {
duration: 100,
onFinish: function onFinish() {
tween(randomButton, {
x: originalX,
y: originalY
}, {
duration: 100
});
}
});
}
// Screen distortion at higher scores
if (glitchIntensity > 5 && Math.random() < 0.01 * glitchIntensity) {
// Glitch overlay effect
tween(overlay, {
alpha: 0.2 + 0.05 * glitchIntensity
}, {
duration: 50,
onFinish: function onFinish() {
tween(overlay, {
alpha: glitchIntensity >= 15 ? 0.3 : 0
}, {
duration: 100
});
}
});
}
// Extreme glitches at very high scores
if (glitchIntensity > 7 && Math.random() < 0.005 * glitchIntensity) {
// Temporarily rotate the entire game container
var originalRotation = game.rotation;
var glitchRotation = (Math.random() - 0.5) * 0.05 * glitchIntensity;
tween(game, {
rotation: glitchRotation
}, {
duration: 100,
onFinish: function onFinish() {
tween(game, {
rotation: originalRotation
}, {
duration: 150
});
}
});
}
// Hell mode specific glitches (glitchIntensity >= 15)
if (glitchIntensity >= 15) {
// Entity flickers more often in hell mode
if (Math.random() < 0.02 && entity.alpha < 0.1) {
entity.alpha = 0.4;
LK.setTimeout(function () {
entity.alpha = 0;
}, 50);
}
// Occasionally make buttons flicker with wrong colors
if (Math.random() < 0.01) {
var randomButtonIndex = Math.floor(Math.random() * buttons.length);
var wrongButtonAsset;
do {
var wrongColor = [COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_YELLOW][Math.floor(Math.random() * 4)];
wrongButtonAsset = 'simonButton' + wrongColor;
} while (buttons[randomButtonIndex].id === wrongColor);
// Briefly show wrong color on button
var originalAlpha = buttons[randomButtonIndex].alpha;
buttons[randomButtonIndex].alpha = 0.7;
LK.setTimeout(function () {
buttons[randomButtonIndex].alpha = originalAlpha;
}, 50 + Math.random() * 100);
}
// Occasionally distort status text in hell mode
if (LK.ticks % 120 === 0 && Math.random() < 0.3) {
var originalSize = statusText.style.size;
var originalY = statusText.y;
// Distort text
statusText.style.size = originalSize * (0.8 + Math.random() * 0.4);
statusText.y = originalY + (Math.random() - 0.5) * 50;
// Reset after brief period
LK.setTimeout(function () {
statusText.style.size = originalSize;
statusText.y = originalY;
}, 200);
}
// Random screen shake in hell mode
if (Math.random() < 0.005) {
var shakeIntensity = 5 + Math.random() * 10;
var originalX = game.x;
var originalY = game.y;
var shakeInterval = LK.setInterval(function () {
game.x = originalX + (Math.random() - 0.5) * shakeIntensity;
game.y = originalY + (Math.random() - 0.5) * shakeIntensity;
}, 50);
LK.setTimeout(function () {
LK.clearInterval(shakeInterval);
game.x = originalX;
game.y = originalY;
}, 300);
}
}
}
// Add subtle horror effects as the game progresses
if (gameState !== STATE_GAME_OVER && level > 3) {
// Random subtle screen flicker
if (Math.random() < 0.005 * horrorIntensity) {
tween(overlay, {
alpha: 0.2
}, {
duration: 100,
onFinish: function onFinish() {
tween(overlay, {
alpha: 0
}, {
duration: 100
});
}
});
}
// Random entity flicker at higher levels
if (level > 5 && Math.random() < 0.002 * horrorIntensity && entity.alpha < 0.1) {
tween(entity, {
alpha: 0.3
}, {
duration: 50,
onFinish: function onFinish() {
tween(entity, {
alpha: 0
}, {
duration: 50
});
}
});
}
}
};
// Event handlers
game.down = function (x, y, obj) {
// No need for intro handling, title screen has its own button
};
creepy realistic eye. In-Game asset. 2d. High contrast. No shadows
realistic face with no eyes or mouth. In-Game asset. 2d. High contrast. No shadows
realistic mouth. In-Game asset. 2d. High contrast. No shadows
blurry realistic image of a car crash with backround. In-Game asset. 2d. High contrast. No shadows
number 0. In-Game asset. 2d. High contrast. No shadows
the number 1. In-Game asset. 2d. High contrast. No shadows