/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var CodeBackground = Container.expand(function () { var self = Container.call(this); var lines = []; var lineSpacing = 40; // Initialize with random code lines self.initialize = function () { for (var i = 0; i < 150; i++) { // Increase from 100 to 150 lines var line = new CodeLine(Math.random() * 1000 + 100, i * lineSpacing); line.x = Math.random() * (2048 - line.width); self.addChild(line); lines.push(line); } }; // Move lines upward self.update = function () { for (var i = 0; i < lines.length; i++) { lines[i].y -= 1; // If line moved off screen, reset to bottom if (lines[i].y < -20) { lines[i].y = 2732 + Math.random() * 100; lines[i].x = Math.random() * (2048 - lines[i].width); } } }; return self; }); // Code for creating scrolling code in the background var CodeLine = Container.expand(function (length, yPos) { var self = Container.call(this); // Random line properties with brighter colors var colors = [0x00ff00, // Bright green 0x00ffff, // Cyan 0xff00ff, // Magenta 0xffff00, // Yellow 0xff3300 // Orange-red ]; var randomColor = colors[Math.floor(Math.random() * colors.length)]; // Create line var line = self.attachAsset('timer', { anchorX: 0, anchorY: 0.5, width: length || Math.random() * 500 + 100, height: 15, // Increased from 10 to 15 for better visibility tint: randomColor }); self.y = yPos || 0; return self; }); var Player = Container.expand(function () { var self = Container.call(this); // Create player visual var playerGraphic = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5, width: 500, height: 632 }); // Create status text self.statusText = new Text2("I'm fine!", { size: 60, fill: 0x89ffd4, align: 'center', stroke: 0x000000, strokeThickness: 5, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive", wordWrap: true, wordWrapWidth: 400 }); self.statusText.anchor.set(0.5, 0); self.statusText.y = 350; // Position the text below the player self.addChild(self.statusText); // Update appearance based on stress level self.updateAppearance = function (stress) { // Visual changes based on stress if (stress < 30) { // Calm - normal color playerGraphic.tint = 0xFFFFFF; // Create a completely new Text2 object with the desired style var newText = new Text2("I'm fine!", { size: 60, fill: 0x89ffd4, align: 'center', stroke: 0x000000, strokeThickness: 5, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive", wordWrap: true, wordWrapWidth: 400 }); newText.anchor.set(0.5, 0); newText.y = 350; // Remove old text and add new one self.removeChild(self.statusText); self.statusText = newText; self.addChild(self.statusText); // Reset animations tween.stop(self); tween(self, { rotation: 0, scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.easeOut }); } else if (stress < 60) { // Getting stressed - slight tint playerGraphic.tint = 0x9b59b6; // Purple tint // Create a completely new Text2 object with the desired style var newText = new Text2("I'm FINE!", { size: 60, fill: 0x660000, align: 'center', stroke: 0xFFFFFF, strokeThickness: 5, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive", wordWrap: true, wordWrapWidth: 400 }); newText.anchor.set(0.5, 0); newText.y = 350; // Remove old text and add new one self.removeChild(self.statusText); self.statusText = newText; self.addChild(self.statusText); // Add slight animation tween.stop(self); tween(self, { scaleX: 1.02, scaleY: 0.98 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { tween(self, { scaleX: 0.98, scaleY: 1.02 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { if (stressLevel >= 30 && stressLevel < 60) { tween(self, { scaleX: 1.02, scaleY: 0.98 }, { duration: 1000, easing: tween.easeInOut, onFinish: function onFinish() { if (stressLevel >= 30 && stressLevel < 60) { tween(self, { scaleX: 0.98, scaleY: 1.02 }, { duration: 1000, easing: tween.easeInOut }); } } }); } } }); } }); } else if (stress < 90) { // Very stressed - red tint playerGraphic.tint = 0xe74c3c; // Red // Create a completely new Text2 object with the desired style var newText = new Text2("I'M FINE!!", { size: 60, fill: 0xFF0000, align: 'center', stroke: 0x000000, strokeThickness: 5, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive", wordWrap: true, wordWrapWidth: 400 }); newText.anchor.set(0.5, 0); newText.y = 350; // Remove old text and add new one self.removeChild(self.statusText); self.statusText = newText; self.addChild(self.statusText); // Add wobble tween.stop(self); tween(self, { rotation: 0.05, scaleX: 1.05, scaleY: 0.95 }, { duration: 300, easing: tween.easeInOut, onFinish: function onFinish() { tween(self, { rotation: -0.05, scaleX: 0.95, scaleY: 1.05 }, { duration: 300, easing: tween.easeInOut, onFinish: function onFinish() { if (stressLevel >= 60 && stressLevel < 90) { tween(self, { rotation: 0.05, scaleX: 1.05, scaleY: 0.95 }, { duration: 300, easing: tween.easeInOut, onFinish: function onFinish() { if (stressLevel >= 60 && stressLevel < 90) { tween(self, { rotation: -0.05, scaleX: 0.95, scaleY: 1.05 }, { duration: 300, easing: tween.easeInOut }); } } }); } } }); } }); } else { // Maximum stress - bright red playerGraphic.tint = 0xff0000; // Create a completely new Text2 object with the desired style var newText = new Text2("T_T ...!!!", { size: 60, fill: 0xFF0000, align: 'center', stroke: 0x000000, strokeThickness: 3, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive", wordWrap: true, wordWrapWidth: 400 }); newText.anchor.set(0.5, 0); newText.y = 350; // Remove old text and add new one self.removeChild(self.statusText); self.statusText = newText; self.addChild(self.statusText); // Dramatic animation tween.stop(self); tween(self, { rotation: 0.1, scaleX: 1.1, scaleY: 0.9 }, { duration: 200, easing: tween.easeInOut, onFinish: function onFinish() { tween(self, { rotation: -0.1, scaleX: 0.9, scaleY: 1.1 }, { duration: 200, easing: tween.easeInOut, onFinish: function onFinish() { if (stressLevel >= 90) { tween(self, { rotation: 0.1, scaleX: 1.1, scaleY: 0.9 }, { duration: 200, easing: tween.easeInOut, onFinish: function onFinish() { if (stressLevel >= 90) { tween(self, { rotation: -0.1, scaleX: 0.9, scaleY: 1.1 }, { duration: 200, easing: tween.easeInOut }); } } }); } } }); } }); } }; return self; }); var Problem = Container.expand(function () { var self = Container.call(this); // Sticky note colors - authentic sticky note colors only var stickyColors = [0xFFFF99, // Light yellow 0xFFB6C1, // Light pink 0x90EE90, // Light green 0xADD8E6, // Light blue 0xFFCC99 // Light orange ]; // Choose random sticky note color var colorIndex = Math.floor(Math.random() * stickyColors.length); var stickyColor = stickyColors[colorIndex]; // Problem types with text and stress impact var problemTypes = [{ text: "WiFi Down!", stress: 8 }, { text: "Coffee Spill!", stress: 6 }, { text: "Deadline Changed!", stress: 10 }, { text: "Surprise Meeting!", stress: 12 }, { text: "Traffic Jam!", stress: 7 }, { text: "Phone Died!", stress: 9 }, { text: "Email Overload!", stress: 8 }, { text: "Printer Error!", stress: 7 }, { text: "Noisy Neighbors!", stress: 6 }, { text: "Low Battery!", stress: 5 }]; // Choose random problem type var typeIndex = Math.floor(Math.random() * problemTypes.length); var type = problemTypes[typeIndex]; // Problem properties self.active = true; self.stressValue = type.stress; self.maxTime = Math.random() * 3 + 1; // Random time between 1-4 seconds self.timeRemaining = self.maxTime; self.points = Math.ceil(10 / self.maxTime); // Shorter times = more points // NEW: Add initial stress when problem appears var initialStress = Math.ceil(self.stressValue * 0.3); // 30% of the full stress value stressLevel += initialStress; updateStressBar(); // Create problem background (sticky note) var problemGraphic = self.attachAsset('problem', { anchorX: 0.5, anchorY: 0.5, tint: stickyColor }); // Create problem text var problemText = new Text2(type.text, { size: 36, fill: 0x000000, // Black text for readability align: 'center', wordWrap: true, wordWrapWidth: 180, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" // Handwritten-style font }); problemText.anchor.set(0.5, 0.5); problemText.y = -20; // Move text up to make room for timer self.addChild(problemText); // Create timer bar self.timerBar = self.attachAsset('timer', { anchorX: 0, anchorY: 0.5, x: -90, // Center the timer bar y: 40, // Position below the text width: 180, // Full width for new timer height: 20, tint: 0x00ff00 }); // Add timer text self.timerText = new Text2(self.timeRemaining.toFixed(1), { size: 30, fill: 0x000000, // Black text for consistency align: 'center', font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); self.timerText.anchor.set(0.5, 0.5); self.timerText.x = 0; self.timerText.y = 70; self.addChild(self.timerText); // Add a slight rotation to make it look more like a sticky note self.rotation = (Math.random() - 0.5) * 0.2; // Random slight tilt // Handle tap/click self.down = function (x, y, obj) { if (!self.active) { return; } self.active = false; LK.getSound('tap').play(); // Visual feedback for successful tap - peeling off animation tween(self, { alpha: 0, scaleX: 0.2, scaleY: 0.2, rotation: self.rotation + Math.PI / 4 // Rotate like peeling off }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { self.destroy(); } }); // Award points based on time remaining var pointsAwarded = Math.ceil(self.points * (self.timeRemaining / self.maxTime)); score += pointsAwarded; scoreText.setText("SCORE: " + score); // NEW: Reduce stress when problem is solved var stressReduction = Math.ceil(self.stressValue * 0.5); // 50% of the full stress value stressLevel = Math.max(0, stressLevel - stressReduction); updateStressBar(); // Show points popup - Now yellow with "SCORE" text var pointsPopup = new Text2("+" + pointsAwarded + " SCORE", { size: 50, fill: 0xFFFF00, stroke: 0x000000, strokeThickness: 4 }); pointsPopup.anchor.set(0.5, 0.5); pointsPopup.x = self.x; pointsPopup.y = self.y; game.addChild(pointsPopup); // NEW: Show stress reduction popup - Keep green for stress reduction var stressReductionPopup = new Text2("-" + stressReduction + " STRESS!", { size: 40, fill: 0x00cc00, // Green for stress reduction stroke: 0x000000, strokeThickness: 3, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); stressReductionPopup.anchor.set(0.5, 0.5); stressReductionPopup.x = self.x; stressReductionPopup.y = self.y + 50; game.addChild(stressReductionPopup); // Animate stress reduction popup tween(stressReductionPopup, { y: stressReductionPopup.y - 50, alpha: 0 }, { duration: 3500, easing: tween.easeOut, onFinish: function onFinish() { stressReductionPopup.destroy(); } }); // Animate points popup tween(pointsPopup, { y: pointsPopup.y - 100, alpha: 0 }, { duration: 3500, easing: tween.easeOut, onFinish: function onFinish() { pointsPopup.destroy(); } }); }; // Update timer - THIS IS THE CRITICAL PART THAT WASN'T WORKING self.update = function (delta) { if (!self.active) { return; } // CRITICAL FIX: Ensure delta is a valid number var safeTimeDelta = isNaN(delta) ? 0.016 : delta; // Default to 60fps if delta is invalid // CRITICAL FIX: Ensure timeRemaining is a valid number if (isNaN(self.timeRemaining)) { self.timeRemaining = self.maxTime; // Reset to max time if invalid } // CRITICAL FIX: Ensure maxTime is valid if (isNaN(self.maxTime) || self.maxTime <= 0) { self.maxTime = 3.0; // Default to 3 seconds if invalid } // Decrease timer with safety checks self.timeRemaining = Math.max(0, self.timeRemaining - safeTimeDelta); // Calculate timer percentage with safety checks var timerPercent = self.timeRemaining && self.maxTime ? self.timeRemaining / self.maxTime : 0; timerPercent = Math.max(0, Math.min(1, timerPercent)); // Clamp between 0-1 // Update timer bar width var timerWidth = Math.max(0, Math.floor(180 * timerPercent)); self.timerBar.width = timerWidth; // Change timer color as time runs out if (timerPercent > 0.6) { self.timerBar.tint = 0x00ff00; // Green } else if (timerPercent > 0.3) { self.timerBar.tint = 0xffff00; // Yellow } else { self.timerBar.tint = 0xff0000; // Red } // CRITICAL FIX: Update timer text with safety check var timerText = self.timeRemaining >= 0 ? self.timeRemaining.toFixed(1) : "0.0"; self.timerText.setText(timerText); // Check if timer expired if (self.timeRemaining <= 0) { self.active = false; // Visual feedback for expired timer LK.getSound('stress').play(); // Add the remaining 70% of stress when timer expires (since 30% was added when the problem appeared) var finalStress = Math.ceil(self.stressValue * 0.7); stressLevel += finalStress; updateStressBar(); // Flash screen red LK.effects.flashScreen(0xff0000, 200, 0.3); // Crumpling animation for sticky note tween(self, { alpha: 0, scaleX: 0.1, scaleY: 0.1, rotation: Math.random() * Math.PI - Math.PI / 2 // Random rotation like crumpling }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { self.destroy(); } }); // Show stress increase popup var stressPopup = new Text2("+" + self.stressValue + " STRESS!", { size: 40, fill: 0xff0000, stroke: 0x000000, strokeThickness: 4, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); stressPopup.anchor.set(0.5, 0.5); stressPopup.x = self.x; stressPopup.y = self.y; game.addChild(stressPopup); // Animate stress popup tween(stressPopup, { y: stressPopup.y - 100, alpha: 0 }, { duration: 800, easing: tween.easeOut, onFinish: function onFinish() { stressPopup.destroy(); } }); } }; // No code needed here - removing completely // NEW: Show stress increase popup when problem appears var appearanceStressPopup = new Text2("+" + initialStress + " STRESS!", { size: 30, fill: 0xff6600, // Orange for initial stress stroke: 0x000000, strokeThickness: 3, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); appearanceStressPopup.anchor.set(0.5, 0.5); appearanceStressPopup.x = self.x; appearanceStressPopup.y = self.y - 40; game.addChild(appearanceStressPopup); // Animate initial stress popup tween(appearanceStressPopup, { y: appearanceStressPopup.y - 50, alpha: 0 }, { duration: 1500, easing: tween.easeOut, onFinish: function onFinish() { appearanceStressPopup.destroy(); } }); // Spawn animation - "sticking" effect self.scale.set(1.2); tween(self, { scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.backOut }); return self; }); var StressBar = Container.expand(function () { var self = Container.call(this); self.interactive = true; var dragOffsetX = 0; var dragOffsetY = 0; // Create stress bar elements var background = self.attachAsset('progressBar', { anchorX: 0.5, anchorY: 0.5, width: 1000, height: 80 }); var fill = self.attachAsset('progressFill', { anchorX: 0, anchorY: 0.5, x: -background.width / 2, y: 0, width: 0 // Start with 0 width }); // Add stress label var label = new Text2("STRESS LEVEL", { size: 40, fill: 0xFFFFFF, fontWeight: 'bold', stroke: 0x000000, strokeThickness: 4, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); label.anchor.set(0.5, 0.5); label.x = 0; label.y = 0; self.addChild(label); // Add drag functionality self.down = function (x, y, obj) { // No-op: stress bar should not be draggable return false; }; self.up = function (x, y, obj) { // Clear drag state dragOffsetX = 0; dragOffsetY = 0; }; self.move = function (x, y, obj) { // No-op: stress bar should not be draggable return false; }; // Update fill based on stress level self.updateFill = function (stressLevel) { var maxWidth = background.width; var newWidth = stressLevel / 100 * maxWidth; // Tween the fill bar tween(fill, { width: newWidth }, { duration: 300, easing: tween.easeOut }); // Change fill color based on stress level if (stressLevel < 30) { fill.tint = 0x00ff00; // Green } else if (stressLevel < 60) { fill.tint = 0xffff00; // Yellow } else if (stressLevel < 90) { fill.tint = 0xff9900; // Orange } else { fill.tint = 0xff0000; // Red } // Text color update is now handled in Player.updateAppearance with complete text replacement }; return self; }); // Create a special problem just for the tutorial that has no timer or functionality var TutorialProblem = Container.expand(function () { var self = Container.call(this); // Use yellow sticky note color for consistency var stickyColor = 0xFFFF99; // Create problem background (sticky note) var problemGraphic = self.attachAsset('problem', { anchorX: 0.5, anchorY: 0.5, tint: stickyColor }); // Add slight rotation for natural look self.rotation = 0.05; // Create problem text var problemText = new Text2("Deadline Changed!", { size: 36, fill: 0x000000, // Black text for readability align: 'center', wordWrap: true, wordWrapWidth: 180, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" // Handwritten-style font }); problemText.anchor.set(0.5, 0.5); problemText.y = -20; // Move text up to make room for timer self.addChild(problemText); // Create static timer bar var timerBar = self.attachAsset('timer', { anchorX: 0, anchorY: 0.5, x: -90, // Center the timer bar y: 40, // Position below the text width: 120, // Show as partially depleted height: 20, tint: 0xffff00 // Yellow to show it's in progress }); // Add static timer text var timerText = new Text2("2.5", { size: 30, fill: 0x000000, // Black text for consistency align: 'center', font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); timerText.anchor.set(0.5, 0.5); timerText.x = 0; timerText.y = 70; self.addChild(timerText); return self; }); /**** * Initialize Game ****/ // Create a tutorial-only example problem and add it to tutorial container var game = new LK.Game({ backgroundColor: 0x192a56 // Dark blue background }); /**** * Game Code ****/ // Game state variables var score = 0; var stressLevel = 0; var gameLevel = 1; var problems = []; var lastProblemTime = 0; var problemSpawnInterval = 1800; // ms between problem spawns var maxProblemsOnScreen = 4; // Maximum problems on screen at once var gameRunning = true; var gameStarted = false; var tutorialActive = false; // Flag to track when tutorial is active var lastUpdate = Date.now(); // Set up code background - keep it faint but visible in the background var codeBackground = new CodeBackground(); codeBackground.initialize(); codeBackground.alpha = 0.15; // Increase alpha to make it more visible while still subtle game.addChild(codeBackground); // Set up regular background - slightly transparent to show code through var background = LK.getAsset('background', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2, alpha: 0.85 // More transparent to let code background show through better }); game.addChild(background); // Set up player var player = new Player(); player.x = 350; // Move to left side player.y = 2732 - 500; player.alpha = 0; // Initially hidden until game starts game.addChild(player); // Set up score text var scoreText = new Text2("SCORE: 0", { size: 70, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 5 }); scoreText.anchor.set(0.5, 0); scoreText.x = 2048 / 2; scoreText.y = 20; LK.gui.top.addChild(scoreText); // Set up level text var levelText = new Text2("DAY: 1", { size: 50, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 3, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); levelText.anchor.set(0.5, 0); levelText.x = 2048 / 2 - 400 + 200 - 75 - 50 - 20 + 10; levelText.y = 30; levelText.alpha = 0; // Hide initially until game starts LK.gui.addChild(levelText); // Game title var titleText = new Text2("I'M FINE!", { size: 100, fill: 0xff4d4d, fontWeight: 'bold', stroke: 0xFFFFFF, strokeThickness: 10, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2 - 300; // Move 300 pixels to the left titleText.y = 500; LK.gui.addChild(titleText); // Game subtitle var subtitleText = new Text2("(a game about pretending everything is OK)", { size: 60, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 3, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 2048 / 2 - 300; // Move 300 pixels to the left subtitleText.y = 635; // Moved 35 pixels down from 600 LK.gui.addChild(subtitleText); // Create start button var startButton = new Container(); startButton.interactive = true; var startBg = LK.getAsset('problem', { anchorX: 0.5, anchorY: 0.5, width: 500, height: 120, tint: 0x444444, alpha: 0, radius: 30 // Rounded corners }); startButton.addChild(startBg); // No triangle needed var startText = new Text2("PLAY", { size: 85, fill: 0xff4d4d, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive", fontWeight: 'bold', stroke: 0xFFFFFF, strokeThickness: 5, underline: true }); startText.anchor.set(0.5, 0.5); startText.x = 0; // Center text after triangle removal startText.y = 0; startButton.addChild(startText); startButton.x = 2048 / 2 - 300; // Move 300 pixels to the left startButton.y = 2732 / 2 - 450 + 145 + 70 + 350 - 45; // Move 305 pixels down from previous position (45px up from previous position) LK.gui.addChild(startButton); // Create and position stress bar var stressBar = new StressBar(); stressBar.x = player.x + player.statusText.width / 2 + 733; // Position next to the status text with 703px more to the right stressBar.y = player.y + 420; // Move down 70px from original position stressBar.alpha = gameStarted ? 1 : 0; // Show if game started, otherwise hide game.addChild(stressBar); // Add to game instead of gui to ensure visibility // Refresh button removed // Update stress bar function updateStressBar() { // Clamp stress level between 0-100 stressLevel = Math.min(100, Math.max(0, stressLevel)); // Update stress bar fill stressBar.updateFill(stressLevel); // Update player appearance player.updateAppearance(stressLevel); // Check for game over if (stressLevel >= 100 && gameRunning) { gameOver(); } } // Spawn a new problem function spawnProblem() { // Don't spawn if tutorial is active, game not running, or not started if (tutorialActive || !gameRunning || !gameStarted) { // Clear any existing problems if tutorial is visible for (var i = problems.length - 1; i >= 0; i--) { if (problems[i].parent) { problems[i].destroy(); } } problems = []; return; } // Don't spawn if we already have max problems if (problems.length >= maxProblemsOnScreen) { return; } // Create new problem var problem = new Problem(); // Position randomly, but keep away from edges problem.x = Math.random() * (2048 - 400) + 200; problem.y = Math.random() * (2732 - 800) + 400; // Make sure it doesn't overlap with player var distToPlayer = Math.sqrt(Math.pow(problem.x - player.x, 2) + Math.pow(problem.y - player.y, 2)); if (distToPlayer < 500) { // Too close to player, adjust position var angle = Math.random() * Math.PI * 2; problem.x = player.x + Math.cos(angle) * 600; problem.y = player.y + Math.sin(angle) * 600; // Keep within screen bounds problem.x = Math.max(200, Math.min(problem.x, 2048 - 200)); problem.y = Math.max(400, Math.min(problem.y, 2732 - 400)); } game.addChild(problem); problems.push(problem); } // Start game function function startGame() { // Set gameStarted to true but not running yet (tutorial will show first) gameStarted = true; gameRunning = false; tutorialActive = true; // Set tutorial flag // Hide start screen elements tween(titleText, { y: -200, alpha: 0 }, { duration: 500, easing: tween.easeIn }); tween(subtitleText, { y: -200, alpha: 0 }, { duration: 500, easing: tween.easeIn }); tween(startButton, { y: 2732 + 200, alpha: 0 }, { duration: 500, easing: tween.easeIn, onFinish: function onFinish() { // Clean up any problems that might exist for (var i = problems.length - 1; i >= 0; i--) { if (problems[i] && problems[i].parent) { problems[i].destroy(); } } problems = []; // Reset the timer lastProblemTime = Date.now(); // Show tutorial first - the game will start when tutorial is closed showTutorial(); // Instructions button removed // Ensure code background continues during gameplay codeBackground.alpha = 0.05; // Music will be played when the START! button is pressed } }); } // Show tutorial function showTutorial() { var tutorialContainer = new Container(); // Set tutorial active flag to prevent problems from spawning tutorialActive = true; gameRunning = false; // Hide player and other game elements player.alpha = 0; stressBar.alpha = 0; levelText.alpha = 0; // Darken background var tutorialBg = LK.getAsset('problem', { width: 2048, height: 2732, tint: 0x000000, alpha: 0.7 }); tutorialContainer.addChild(tutorialBg); // Title var tutorialTitle = new Text2("HOW TO PLAY", { size: 100, fill: 0xFFFFFF, fontWeight: 'bold', stroke: 0x000000, // Added stroke for consistency and visibility strokeThickness: 4, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); tutorialTitle.anchor.set(0.5, 0.5); tutorialTitle.x = 2048 / 2 - 300; tutorialTitle.y = 100; tutorialContainer.addChild(tutorialTitle); // FIXED: Consistent formatting for tutorial instructions with new stress mechanics var instructions = new Text2("• PROBLEMS appear randomly and cause STRESS\n\n" + "• TAP problems before their timer runs out to REDUCE stress and EARN points\n\n" + "• If timers expire, you get MORE stress\n\n" + "• Clear ALL problems on screen to recover stress faster\n\n" + "• Don't let your stress reach 100%\n\n" + "• Just keep calm and whisper \"I'M FINE!\"", { size: 40, fill: 0xFFFFFF, align: 'left', lineHeight: 45, stroke: 0x000000, strokeThickness: 3, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); instructions.anchor.set(0, 0); instructions.x = 2048 / 2 - 1000; instructions.y = 220; // Position right below the title instructions.width = 1400; // Ensure text fits within screen width tutorialContainer.addChild(instructions); // Create a tutorial-only example problem and add it to tutorial container var exampleProblem = new TutorialProblem(); exampleProblem.x = 2048 / 2 - 300; exampleProblem.y = 1500; // Adjusted position tutorialContainer.addChild(exampleProblem); // Continue button with improved styling var continueButton = new Container(); continueButton.interactive = true; var continueText = new Text2("START!", { size: 70, fill: 0xff0000, fontWeight: 'bold', stroke: 0xFFFFFF, strokeThickness: 3, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); continueText.anchor.set(0.5, 0.5); continueText.x = 0; continueText.y = 0; continueButton.addChild(continueText); continueButton.x = 2048 / 2 - 300; continueButton.y = 1800; tutorialContainer.addChild(continueButton); // Add to GUI LK.gui.addChild(tutorialContainer); // Make the continue button interactive to close tutorial continueButton.down = function () { tutorialContainer.destroy(); // Clean up any remaining problems for (var i = problems.length - 1; i >= 0; i--) { if (problems[i] && problems[i].parent) { problems[i].destroy(); } } problems = []; // Reset the timer lastProblemTime = Date.now(); // Clear tutorial flag and start the game tutorialActive = false; gameRunning = true; // Start background music when game starts LK.playMusic('bgmusic'); // Don't stop code background animation, just keep it at low opacity during gameplay codeBackground.alpha = 0.15; // Keep subtle matrix effect in background // Show player and elements with animation tween(player, { alpha: 1 }, { duration: 800, easing: tween.elasticOut }); // Show stress bar tween(stressBar, { alpha: 1 }, { duration: 500 }); // Show level text tween(levelText, { alpha: 1 }, { duration: 800, easing: tween.elasticOut }); // Refresh button removed }; // Make the tutorial container interactive tutorialContainer.interactive = true; tutorialContainer.down = function (x, y, obj) { // Only trigger if clicked on the container background, not on buttons or text if (obj === tutorialContainer || obj === tutorialBg) { continueButton.down(); } }; } // Instructions popup function showInstructions() { var popup = new Container(); // Darken background var bg = LK.getAsset('problem', { anchorX: 0.5, anchorY: 0.5, width: 2048, height: 2732, tint: 0x000000, alpha: 0.7 }); popup.addChild(bg); // Panel background var panel = LK.getAsset('problem', { anchorX: 0.5, anchorY: 0.5, width: 1600, height: 1800, tint: 0xFFFFFF, alpha: 0.9 }); panel.x = 2048 / 2; panel.y = 2732 / 2; popup.addChild(panel); // Instructions with new stress mechanics var tutorialTitle = new Text2("HOW TO PLAY", { size: 100, fill: 0xFFFFFF, fontWeight: 'bold', stroke: 0x000000, // Added stroke for consistency and visibility strokeThickness: 4, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); tutorialTitle.anchor.set(0.5, 0.5); tutorialTitle.x = 2048 / 2 - 300; tutorialTitle.y = 100; tutorialContainer.addChild(tutorialTitle); // FIXED: Consistent formatting for tutorial instructions with new stress mechanics var instructions = new Text2("• PROBLEMS appear randomly and cause STRESS\n\n" + "• TAP problems before their timer runs out to REDUCE stress and EARN points\n\n" + "• If timers expire, you get MORE stress\n\n" + "• Clear ALL problems on screen to recover stress faster\n\n" + "• Don't let your stress reach 100%\n\n" + "• Just keep calm and whisper \"I'M FINE!\"", { size: 40, fill: 0xFFFFFF, align: 'left', lineHeight: 45, stroke: 0x000000, strokeThickness: 3, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); instructions.anchor.set(0, 0); instructions.x = 2048 / 2 - 300; instructions.y = 220; // Position right below the title instructions.width = 1400; // Ensure text fits within screen width tutorialContainer.addChild(instructions); // Create a tutorial-only example problem and add it to tutorial container var exampleProblem = new TutorialProblem(); exampleProblem.x = 2048 / 2 - 300; exampleProblem.y = 1500; // Adjusted position tutorialContainer.addChild(exampleProblem); // Continue button with improved styling var continueButton = new Container(); continueButton.interactive = true; var continueText = new Text2("START!", { size: 70, fill: 0xff0000, fontWeight: 'bold', stroke: 0xFFFFFF, strokeThickness: 3, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); continueText.anchor.set(0.5, 0.5); continueText.x = 0; continueText.y = 0; continueButton.addChild(continueText); continueButton.x = 2048 / 2 - 300; continueButton.y = 1800; tutorialContainer.addChild(continueButton); // Pause game while instructions are open var wasPaused = !gameRunning; gameRunning = false; tutorialActive = true; // Set tutorial active to prevent problems closeButton.down = function () { popup.destroy(); // Clean up any problems that might have been created for (var i = problems.length - 1; i >= 0; i--) { if (problems[i] && problems[i].parent) { problems[i].destroy(); } } problems = []; tutorialActive = false; // Clear tutorial active flag if (!wasPaused) { gameRunning = true; } }; LK.gui.addChild(popup); } // Check if level should increase function checkLevelProgress() { var newLevel = Math.floor(score / 10) + 1; if (newLevel > gameLevel) { gameLevel = newLevel; levelText.setText("DAY: " + gameLevel); // Make game harder as level increases problemSpawnInterval = Math.max(500, 1800 - gameLevel * 100); maxProblemsOnScreen = Math.min(8, 4 + Math.floor(gameLevel / 2)); // Visual and audio feedback LK.effects.flashScreen(0x00ff00, 500, 0.3); LK.getSound('levelup').play(); // Show level up text var levelUpText = new Text2("Let's Gooo!", { size: 100, fill: 0x00ff00, stroke: 0x000000, strokeThickness: 6, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); levelUpText.anchor.set(0.5, 0.5); levelUpText.x = 2048 / 2 - 300; levelUpText.y = 1000; LK.gui.addChild(levelUpText); // Animate and remove tween(levelUpText, { scaleX: 2, scaleY: 2, alpha: 0 }, { duration: 3500, easing: tween.easeOut, onFinish: function onFinish() { levelUpText.destroy(); } }); } } // Game over function function gameOver() { gameRunning = false; // Stop the background music when game over LK.stopMusic(); // Visual effects LK.effects.flashScreen(0xff0000, 1000); // Game over container var gameOverContainer = new Container(); // Darken background var darkOverlay = LK.getAsset('problem', { anchorX: 0.5, anchorY: 0.5, width: 2048, height: 2732, tint: 0x000000, alpha: 0.8 }); darkOverlay.x = 2048 / 2; darkOverlay.y = 2732 / 2; gameOverContainer.addChild(darkOverlay); // Game over text - properly centered with larger font var gameOverText = new Text2("YOU'RE NOT FINE!", { size: 60, fill: 0xff0000, fontWeight: 'bold', stroke: 0xFFFFFF, strokeThickness: 8, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); gameOverText.anchor.set(0.5, 0.5); // Center anchor gameOverText.x = 2048 / 2 - 300; // Center horizontally gameOverText.y = 200; // Position from top with more space gameOverContainer.addChild(gameOverText); // Meme text - position BELOW main text var memeText = new Text2("(But we've all been there...)", { size: 35, fill: 0xFFFFFF, fontStyle: 'italic', align: 'center', stroke: 0x000000, strokeThickness: 2, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); memeText.anchor.set(0.5, 0.5); memeText.x = 2048 / 2 - 300; // Center horizontally memeText.y = gameOverText.y + 250; // Position below game over text with more space gameOverContainer.addChild(memeText); // Final score text var finalScoreText = new Text2("FINAL SCORE: " + score, { size: 50, fill: 0xffff00, stroke: 0x000000, strokeThickness: 5, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" // Add font }); finalScoreText.anchor.set(0.5, 0.5); finalScoreText.x = 2048 / 2 - 300; // Center horizontally finalScoreText.y = 850; // Position from top gameOverContainer.addChild(finalScoreText); // Level reached - updated positioning and font var levelReachedText = new Text2("DAYS WITHOUT BURNOUT: " + gameLevel, { size: 35, fill: 0xFFFFFF, stroke: 0x000000, strokeThickness: 3, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" // Add font }); levelReachedText.anchor.set(0.5, 0.5); levelReachedText.x = 2048 / 2 - 300; // Center horizontally levelReachedText.y = 1300; // Position below score with more space gameOverContainer.addChild(levelReachedText); // Restart button - FIXED: Made it more visible and properly centered var restartButton = new Container(); restartButton.interactive = true; // No background button var restartText = new Text2("PLAY AGAIN", { size: 35, fill: 0xff0000, fontWeight: 'bold', font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); restartText.anchor.set(0.5, 0.5); restartText.x = 0; restartText.y = 0; restartButton.addChild(restartText); restartButton.x = 2048 / 2 - 300; // Center horizontally restartButton.y = 1600; // Position below level text with more space gameOverContainer.addChild(restartButton); // Add fun meme quote at the bottom with improved formatting var memeQuote = new Text2(getRandomMemeQuote(), { size: 55, fill: 0xFFFFFF, fontStyle: 'italic', align: 'center', wordWrap: true, wordWrapWidth: 1400, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" // Add font }); memeQuote.anchor.set(0.5, 0.5); memeQuote.x = 2048 / 2 - 300; // Center horizontally memeQuote.y = 1800; // Position from top with more space gameOverContainer.addChild(memeQuote); // Animate in with improved timing gameOverText.alpha = 0; gameOverText.y -= 100; memeText.alpha = 0; finalScoreText.alpha = 0; levelReachedText.alpha = 0; restartButton.alpha = 0; memeQuote.alpha = 0; tween(gameOverText, { alpha: 1, y: gameOverText.y + 100 }, { duration: 500, easing: tween.elasticOut }); tween(memeText, { alpha: 1 }, { duration: 500, delay: 200 // Reduced delay for better flow }); tween(finalScoreText, { alpha: 1 }, { duration: 500, delay: 400 // Reduced delay }); tween(levelReachedText, { alpha: 1 }, { duration: 500, delay: 600 // Reduced delay }); tween(restartButton, { alpha: 1 }, { duration: 500, delay: 800 // Reduced delay }); tween(memeQuote, { alpha: 1 }, { duration: 500, delay: 1000 // Reduced delay }); // Handle restart restartButton.down = function () { restartGame(); gameOverContainer.destroy(); }; LK.gui.addChild(gameOverContainer); } // Restart game function restartGame() { // Reset game variables score = 0; stressLevel = 0; gameLevel = 1; problemSpawnInterval = 1800; maxProblemsOnScreen = 4; lastProblemTime = 0; gameRunning = true; // Start game immediately tutorialActive = false; // Skip tutorial // Clear any existing problems for (var i = 0; i < problems.length; i++) { if (problems[i] && problems[i].parent) { problems[i].destroy(); } } problems = []; // Reset UI scoreText.setText("SCORE: 0"); levelText.setText("DAY: 1"); updateStressBar(); // Reset player player.updateAppearance(0); player.alpha = 1; // Show player immediately // Make game elements visible immediately stressBar.alpha = 1; levelText.alpha = 1; // Keep code background visible but subtle during restart codeBackground.alpha = 0.15; // Restart music - ensure music plays when game restarts LK.playMusic('bgmusic'); // Set last problem time to now lastProblemTime = Date.now(); } // Get random meme quote for game over screen function getRandomMemeQuote() { var quotes = ["This is fine. Everything is fine.", "When someone asks how you're doing and you say 'fine' for the 47th time today.", "Me pretending my life isn't falling apart.", "Monday: I'm fine. Tuesday: I'M FINE! Friday: EVERYTHING IS FINE!!!", "When the deadline is tomorrow and you haven't started yet: I'M FINE!", "Adult life is saying 'I'm fine' when people ask how you are until you actually are.", "No one: \nMe: I'M FINE!!! EVERYTHING IS FINE!!!", "When your coffee spills, WiFi drops, and deadline changes all at once: I'M TOTALLY FINE!"]; return quotes[Math.floor(Math.random() * quotes.length)]; } // Screen shake effect function shakeScreen(intensity) { if (!gameRunning) { return; } tween(game, { x: Math.random() * intensity - intensity / 2 }, { duration: 50, easing: tween.linear, onFinish: function onFinish() { tween(game, { x: Math.random() * intensity - intensity / 2 }, { duration: 50, easing: tween.linear, onFinish: function onFinish() { tween(game, { x: 0 }, { duration: 50, easing: tween.linear }); } }); } }); } // Clean up problems array function cleanupProblems() { for (var i = problems.length - 1; i >= 0; i--) { if (!problems[i].parent) { problems.splice(i, 1); } } } // Instructions button removed // Handle start button startButton.down = function () { startGame(); }; // Main game update function game.update = function () { // Calculate delta time for consistent updates var now = Date.now(); var delta = (now - lastUpdate) / 1000; // Convert to seconds lastUpdate = now; // Always update code background animation in all game states if (codeBackground && codeBackground.update) { console.log("Updating code background"); // Debug output codeBackground.update(); } if (!gameRunning || !gameStarted || tutorialActive) { // Check if there are any problems to remove (during tutorial) for (var i = problems.length - 1; i >= 0; i--) { if (problems[i].parent) { problems[i].destroy(); } } problems = []; return; } // Check if it's time to spawn a new problem if (now - lastProblemTime > problemSpawnInterval) { spawnProblem(); lastProblemTime = now; } // Update all problems for (var i = 0; i < problems.length; i++) { if (problems[i] && problems[i].update) { problems[i].update(delta); } } // Clean up problems array cleanupProblems(); // Gradually increase stress based on number of active problems if (problems.length > 0) { // Each active problem adds 0.8 stress per second, multiplied by delta time for consistent timing var stressIncrease = problems.length * 0.8 * delta; stressLevel = Math.min(100, stressLevel + stressIncrease); updateStressBar(); // Visual feedback for stress increase (show occasionally) if (Math.random() < 0.02) { var stressPopup = new Text2("+" + stressIncrease.toFixed(1) + " STRESS", { size: 30, fill: 0xFF6600, stroke: 0x000000, strokeThickness: 2, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); stressPopup.anchor.set(0.5, 0.5); stressPopup.x = player.x + (Math.random() * 200 - 100); stressPopup.y = player.y - 50 - Math.random() * 50; game.addChild(stressPopup); // Animate stress popup tween(stressPopup, { y: stressPopup.y - 50, alpha: 0 }, { duration: 3000, easing: tween.easeOut, onFinish: function onFinish() { stressPopup.destroy(); } }); } } // Check level progress checkLevelProgress(); // NEW: Reduce stress faster when there are no problems if (problems.length === 0 && stressLevel > 0) { // Reduce stress at a higher rate when no problems are present stressLevel = Math.max(0, stressLevel - 1.0 * delta); updateStressBar(); // Visual feedback for stress reduction when no problems if (Math.random() < 0.05) { // Occasional visual feedback var relaxPopup = new Text2("-1 STRESS", { size: 30, fill: 0x00cc00, stroke: 0x000000, strokeThickness: 2, font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" }); relaxPopup.anchor.set(0.5, 0.5); relaxPopup.x = player.x; relaxPopup.y = player.y + 100; game.addChild(relaxPopup); // Animate relaxation popup tween(relaxPopup, { y: relaxPopup.y + 50, alpha: 0 }, { duration: 3000, easing: tween.easeOut, onFinish: function onFinish() { relaxPopup.destroy(); } }); } } // Randomly reduce stress (small recovery chance) if (Math.random() < 0.001 * delta * 60 && stressLevel > 0) { stressLevel = Math.max(0, stressLevel - 0.2); updateStressBar(); } // Add screen shake when stress is high if (stressLevel >= 70 && Math.random() < 0.05) { var intensity = (stressLevel - 70) / 30 * 20; shakeScreen(intensity); } }; // Music will be played when the START! button is pressed instead
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var CodeBackground = Container.expand(function () {
var self = Container.call(this);
var lines = [];
var lineSpacing = 40;
// Initialize with random code lines
self.initialize = function () {
for (var i = 0; i < 150; i++) {
// Increase from 100 to 150 lines
var line = new CodeLine(Math.random() * 1000 + 100, i * lineSpacing);
line.x = Math.random() * (2048 - line.width);
self.addChild(line);
lines.push(line);
}
};
// Move lines upward
self.update = function () {
for (var i = 0; i < lines.length; i++) {
lines[i].y -= 1;
// If line moved off screen, reset to bottom
if (lines[i].y < -20) {
lines[i].y = 2732 + Math.random() * 100;
lines[i].x = Math.random() * (2048 - lines[i].width);
}
}
};
return self;
});
// Code for creating scrolling code in the background
var CodeLine = Container.expand(function (length, yPos) {
var self = Container.call(this);
// Random line properties with brighter colors
var colors = [0x00ff00,
// Bright green
0x00ffff,
// Cyan
0xff00ff,
// Magenta
0xffff00,
// Yellow
0xff3300 // Orange-red
];
var randomColor = colors[Math.floor(Math.random() * colors.length)];
// Create line
var line = self.attachAsset('timer', {
anchorX: 0,
anchorY: 0.5,
width: length || Math.random() * 500 + 100,
height: 15,
// Increased from 10 to 15 for better visibility
tint: randomColor
});
self.y = yPos || 0;
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
// Create player visual
var playerGraphic = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5,
width: 500,
height: 632
});
// Create status text
self.statusText = new Text2("I'm fine!", {
size: 60,
fill: 0x89ffd4,
align: 'center',
stroke: 0x000000,
strokeThickness: 5,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive",
wordWrap: true,
wordWrapWidth: 400
});
self.statusText.anchor.set(0.5, 0);
self.statusText.y = 350; // Position the text below the player
self.addChild(self.statusText);
// Update appearance based on stress level
self.updateAppearance = function (stress) {
// Visual changes based on stress
if (stress < 30) {
// Calm - normal color
playerGraphic.tint = 0xFFFFFF;
// Create a completely new Text2 object with the desired style
var newText = new Text2("I'm fine!", {
size: 60,
fill: 0x89ffd4,
align: 'center',
stroke: 0x000000,
strokeThickness: 5,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive",
wordWrap: true,
wordWrapWidth: 400
});
newText.anchor.set(0.5, 0);
newText.y = 350;
// Remove old text and add new one
self.removeChild(self.statusText);
self.statusText = newText;
self.addChild(self.statusText);
// Reset animations
tween.stop(self);
tween(self, {
rotation: 0,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeOut
});
} else if (stress < 60) {
// Getting stressed - slight tint
playerGraphic.tint = 0x9b59b6; // Purple tint
// Create a completely new Text2 object with the desired style
var newText = new Text2("I'm FINE!", {
size: 60,
fill: 0x660000,
align: 'center',
stroke: 0xFFFFFF,
strokeThickness: 5,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive",
wordWrap: true,
wordWrapWidth: 400
});
newText.anchor.set(0.5, 0);
newText.y = 350;
// Remove old text and add new one
self.removeChild(self.statusText);
self.statusText = newText;
self.addChild(self.statusText);
// Add slight animation
tween.stop(self);
tween(self, {
scaleX: 1.02,
scaleY: 0.98
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 0.98,
scaleY: 1.02
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (stressLevel >= 30 && stressLevel < 60) {
tween(self, {
scaleX: 1.02,
scaleY: 0.98
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (stressLevel >= 30 && stressLevel < 60) {
tween(self, {
scaleX: 0.98,
scaleY: 1.02
}, {
duration: 1000,
easing: tween.easeInOut
});
}
}
});
}
}
});
}
});
} else if (stress < 90) {
// Very stressed - red tint
playerGraphic.tint = 0xe74c3c; // Red
// Create a completely new Text2 object with the desired style
var newText = new Text2("I'M FINE!!", {
size: 60,
fill: 0xFF0000,
align: 'center',
stroke: 0x000000,
strokeThickness: 5,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive",
wordWrap: true,
wordWrapWidth: 400
});
newText.anchor.set(0.5, 0);
newText.y = 350;
// Remove old text and add new one
self.removeChild(self.statusText);
self.statusText = newText;
self.addChild(self.statusText);
// Add wobble
tween.stop(self);
tween(self, {
rotation: 0.05,
scaleX: 1.05,
scaleY: 0.95
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self, {
rotation: -0.05,
scaleX: 0.95,
scaleY: 1.05
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (stressLevel >= 60 && stressLevel < 90) {
tween(self, {
rotation: 0.05,
scaleX: 1.05,
scaleY: 0.95
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (stressLevel >= 60 && stressLevel < 90) {
tween(self, {
rotation: -0.05,
scaleX: 0.95,
scaleY: 1.05
}, {
duration: 300,
easing: tween.easeInOut
});
}
}
});
}
}
});
}
});
} else {
// Maximum stress - bright red
playerGraphic.tint = 0xff0000;
// Create a completely new Text2 object with the desired style
var newText = new Text2("T_T ...!!!", {
size: 60,
fill: 0xFF0000,
align: 'center',
stroke: 0x000000,
strokeThickness: 3,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive",
wordWrap: true,
wordWrapWidth: 400
});
newText.anchor.set(0.5, 0);
newText.y = 350;
// Remove old text and add new one
self.removeChild(self.statusText);
self.statusText = newText;
self.addChild(self.statusText);
// Dramatic animation
tween.stop(self);
tween(self, {
rotation: 0.1,
scaleX: 1.1,
scaleY: 0.9
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self, {
rotation: -0.1,
scaleX: 0.9,
scaleY: 1.1
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (stressLevel >= 90) {
tween(self, {
rotation: 0.1,
scaleX: 1.1,
scaleY: 0.9
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (stressLevel >= 90) {
tween(self, {
rotation: -0.1,
scaleX: 0.9,
scaleY: 1.1
}, {
duration: 200,
easing: tween.easeInOut
});
}
}
});
}
}
});
}
});
}
};
return self;
});
var Problem = Container.expand(function () {
var self = Container.call(this);
// Sticky note colors - authentic sticky note colors only
var stickyColors = [0xFFFF99,
// Light yellow
0xFFB6C1,
// Light pink
0x90EE90,
// Light green
0xADD8E6,
// Light blue
0xFFCC99 // Light orange
];
// Choose random sticky note color
var colorIndex = Math.floor(Math.random() * stickyColors.length);
var stickyColor = stickyColors[colorIndex];
// Problem types with text and stress impact
var problemTypes = [{
text: "WiFi Down!",
stress: 8
}, {
text: "Coffee Spill!",
stress: 6
}, {
text: "Deadline Changed!",
stress: 10
}, {
text: "Surprise Meeting!",
stress: 12
}, {
text: "Traffic Jam!",
stress: 7
}, {
text: "Phone Died!",
stress: 9
}, {
text: "Email Overload!",
stress: 8
}, {
text: "Printer Error!",
stress: 7
}, {
text: "Noisy Neighbors!",
stress: 6
}, {
text: "Low Battery!",
stress: 5
}];
// Choose random problem type
var typeIndex = Math.floor(Math.random() * problemTypes.length);
var type = problemTypes[typeIndex];
// Problem properties
self.active = true;
self.stressValue = type.stress;
self.maxTime = Math.random() * 3 + 1; // Random time between 1-4 seconds
self.timeRemaining = self.maxTime;
self.points = Math.ceil(10 / self.maxTime); // Shorter times = more points
// NEW: Add initial stress when problem appears
var initialStress = Math.ceil(self.stressValue * 0.3); // 30% of the full stress value
stressLevel += initialStress;
updateStressBar();
// Create problem background (sticky note)
var problemGraphic = self.attachAsset('problem', {
anchorX: 0.5,
anchorY: 0.5,
tint: stickyColor
});
// Create problem text
var problemText = new Text2(type.text, {
size: 36,
fill: 0x000000,
// Black text for readability
align: 'center',
wordWrap: true,
wordWrapWidth: 180,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" // Handwritten-style font
});
problemText.anchor.set(0.5, 0.5);
problemText.y = -20; // Move text up to make room for timer
self.addChild(problemText);
// Create timer bar
self.timerBar = self.attachAsset('timer', {
anchorX: 0,
anchorY: 0.5,
x: -90,
// Center the timer bar
y: 40,
// Position below the text
width: 180,
// Full width for new timer
height: 20,
tint: 0x00ff00
});
// Add timer text
self.timerText = new Text2(self.timeRemaining.toFixed(1), {
size: 30,
fill: 0x000000,
// Black text for consistency
align: 'center',
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
self.timerText.anchor.set(0.5, 0.5);
self.timerText.x = 0;
self.timerText.y = 70;
self.addChild(self.timerText);
// Add a slight rotation to make it look more like a sticky note
self.rotation = (Math.random() - 0.5) * 0.2; // Random slight tilt
// Handle tap/click
self.down = function (x, y, obj) {
if (!self.active) {
return;
}
self.active = false;
LK.getSound('tap').play();
// Visual feedback for successful tap - peeling off animation
tween(self, {
alpha: 0,
scaleX: 0.2,
scaleY: 0.2,
rotation: self.rotation + Math.PI / 4 // Rotate like peeling off
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
// Award points based on time remaining
var pointsAwarded = Math.ceil(self.points * (self.timeRemaining / self.maxTime));
score += pointsAwarded;
scoreText.setText("SCORE: " + score);
// NEW: Reduce stress when problem is solved
var stressReduction = Math.ceil(self.stressValue * 0.5); // 50% of the full stress value
stressLevel = Math.max(0, stressLevel - stressReduction);
updateStressBar();
// Show points popup - Now yellow with "SCORE" text
var pointsPopup = new Text2("+" + pointsAwarded + " SCORE", {
size: 50,
fill: 0xFFFF00,
stroke: 0x000000,
strokeThickness: 4
});
pointsPopup.anchor.set(0.5, 0.5);
pointsPopup.x = self.x;
pointsPopup.y = self.y;
game.addChild(pointsPopup);
// NEW: Show stress reduction popup - Keep green for stress reduction
var stressReductionPopup = new Text2("-" + stressReduction + " STRESS!", {
size: 40,
fill: 0x00cc00,
// Green for stress reduction
stroke: 0x000000,
strokeThickness: 3,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
stressReductionPopup.anchor.set(0.5, 0.5);
stressReductionPopup.x = self.x;
stressReductionPopup.y = self.y + 50;
game.addChild(stressReductionPopup);
// Animate stress reduction popup
tween(stressReductionPopup, {
y: stressReductionPopup.y - 50,
alpha: 0
}, {
duration: 3500,
easing: tween.easeOut,
onFinish: function onFinish() {
stressReductionPopup.destroy();
}
});
// Animate points popup
tween(pointsPopup, {
y: pointsPopup.y - 100,
alpha: 0
}, {
duration: 3500,
easing: tween.easeOut,
onFinish: function onFinish() {
pointsPopup.destroy();
}
});
};
// Update timer - THIS IS THE CRITICAL PART THAT WASN'T WORKING
self.update = function (delta) {
if (!self.active) {
return;
}
// CRITICAL FIX: Ensure delta is a valid number
var safeTimeDelta = isNaN(delta) ? 0.016 : delta; // Default to 60fps if delta is invalid
// CRITICAL FIX: Ensure timeRemaining is a valid number
if (isNaN(self.timeRemaining)) {
self.timeRemaining = self.maxTime; // Reset to max time if invalid
}
// CRITICAL FIX: Ensure maxTime is valid
if (isNaN(self.maxTime) || self.maxTime <= 0) {
self.maxTime = 3.0; // Default to 3 seconds if invalid
}
// Decrease timer with safety checks
self.timeRemaining = Math.max(0, self.timeRemaining - safeTimeDelta);
// Calculate timer percentage with safety checks
var timerPercent = self.timeRemaining && self.maxTime ? self.timeRemaining / self.maxTime : 0;
timerPercent = Math.max(0, Math.min(1, timerPercent)); // Clamp between 0-1
// Update timer bar width
var timerWidth = Math.max(0, Math.floor(180 * timerPercent));
self.timerBar.width = timerWidth;
// Change timer color as time runs out
if (timerPercent > 0.6) {
self.timerBar.tint = 0x00ff00; // Green
} else if (timerPercent > 0.3) {
self.timerBar.tint = 0xffff00; // Yellow
} else {
self.timerBar.tint = 0xff0000; // Red
}
// CRITICAL FIX: Update timer text with safety check
var timerText = self.timeRemaining >= 0 ? self.timeRemaining.toFixed(1) : "0.0";
self.timerText.setText(timerText);
// Check if timer expired
if (self.timeRemaining <= 0) {
self.active = false;
// Visual feedback for expired timer
LK.getSound('stress').play();
// Add the remaining 70% of stress when timer expires (since 30% was added when the problem appeared)
var finalStress = Math.ceil(self.stressValue * 0.7);
stressLevel += finalStress;
updateStressBar();
// Flash screen red
LK.effects.flashScreen(0xff0000, 200, 0.3);
// Crumpling animation for sticky note
tween(self, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1,
rotation: Math.random() * Math.PI - Math.PI / 2 // Random rotation like crumpling
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
self.destroy();
}
});
// Show stress increase popup
var stressPopup = new Text2("+" + self.stressValue + " STRESS!", {
size: 40,
fill: 0xff0000,
stroke: 0x000000,
strokeThickness: 4,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
stressPopup.anchor.set(0.5, 0.5);
stressPopup.x = self.x;
stressPopup.y = self.y;
game.addChild(stressPopup);
// Animate stress popup
tween(stressPopup, {
y: stressPopup.y - 100,
alpha: 0
}, {
duration: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
stressPopup.destroy();
}
});
}
};
// No code needed here - removing completely
// NEW: Show stress increase popup when problem appears
var appearanceStressPopup = new Text2("+" + initialStress + " STRESS!", {
size: 30,
fill: 0xff6600,
// Orange for initial stress
stroke: 0x000000,
strokeThickness: 3,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
appearanceStressPopup.anchor.set(0.5, 0.5);
appearanceStressPopup.x = self.x;
appearanceStressPopup.y = self.y - 40;
game.addChild(appearanceStressPopup);
// Animate initial stress popup
tween(appearanceStressPopup, {
y: appearanceStressPopup.y - 50,
alpha: 0
}, {
duration: 1500,
easing: tween.easeOut,
onFinish: function onFinish() {
appearanceStressPopup.destroy();
}
});
// Spawn animation - "sticking" effect
self.scale.set(1.2);
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.backOut
});
return self;
});
var StressBar = Container.expand(function () {
var self = Container.call(this);
self.interactive = true;
var dragOffsetX = 0;
var dragOffsetY = 0;
// Create stress bar elements
var background = self.attachAsset('progressBar', {
anchorX: 0.5,
anchorY: 0.5,
width: 1000,
height: 80
});
var fill = self.attachAsset('progressFill', {
anchorX: 0,
anchorY: 0.5,
x: -background.width / 2,
y: 0,
width: 0 // Start with 0 width
});
// Add stress label
var label = new Text2("STRESS LEVEL", {
size: 40,
fill: 0xFFFFFF,
fontWeight: 'bold',
stroke: 0x000000,
strokeThickness: 4,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
label.anchor.set(0.5, 0.5);
label.x = 0;
label.y = 0;
self.addChild(label);
// Add drag functionality
self.down = function (x, y, obj) {
// No-op: stress bar should not be draggable
return false;
};
self.up = function (x, y, obj) {
// Clear drag state
dragOffsetX = 0;
dragOffsetY = 0;
};
self.move = function (x, y, obj) {
// No-op: stress bar should not be draggable
return false;
};
// Update fill based on stress level
self.updateFill = function (stressLevel) {
var maxWidth = background.width;
var newWidth = stressLevel / 100 * maxWidth;
// Tween the fill bar
tween(fill, {
width: newWidth
}, {
duration: 300,
easing: tween.easeOut
});
// Change fill color based on stress level
if (stressLevel < 30) {
fill.tint = 0x00ff00; // Green
} else if (stressLevel < 60) {
fill.tint = 0xffff00; // Yellow
} else if (stressLevel < 90) {
fill.tint = 0xff9900; // Orange
} else {
fill.tint = 0xff0000; // Red
}
// Text color update is now handled in Player.updateAppearance with complete text replacement
};
return self;
});
// Create a special problem just for the tutorial that has no timer or functionality
var TutorialProblem = Container.expand(function () {
var self = Container.call(this);
// Use yellow sticky note color for consistency
var stickyColor = 0xFFFF99;
// Create problem background (sticky note)
var problemGraphic = self.attachAsset('problem', {
anchorX: 0.5,
anchorY: 0.5,
tint: stickyColor
});
// Add slight rotation for natural look
self.rotation = 0.05;
// Create problem text
var problemText = new Text2("Deadline Changed!", {
size: 36,
fill: 0x000000,
// Black text for readability
align: 'center',
wordWrap: true,
wordWrapWidth: 180,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" // Handwritten-style font
});
problemText.anchor.set(0.5, 0.5);
problemText.y = -20; // Move text up to make room for timer
self.addChild(problemText);
// Create static timer bar
var timerBar = self.attachAsset('timer', {
anchorX: 0,
anchorY: 0.5,
x: -90,
// Center the timer bar
y: 40,
// Position below the text
width: 120,
// Show as partially depleted
height: 20,
tint: 0xffff00 // Yellow to show it's in progress
});
// Add static timer text
var timerText = new Text2("2.5", {
size: 30,
fill: 0x000000,
// Black text for consistency
align: 'center',
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
timerText.anchor.set(0.5, 0.5);
timerText.x = 0;
timerText.y = 70;
self.addChild(timerText);
return self;
});
/****
* Initialize Game
****/
// Create a tutorial-only example problem and add it to tutorial container
var game = new LK.Game({
backgroundColor: 0x192a56 // Dark blue background
});
/****
* Game Code
****/
// Game state variables
var score = 0;
var stressLevel = 0;
var gameLevel = 1;
var problems = [];
var lastProblemTime = 0;
var problemSpawnInterval = 1800; // ms between problem spawns
var maxProblemsOnScreen = 4; // Maximum problems on screen at once
var gameRunning = true;
var gameStarted = false;
var tutorialActive = false; // Flag to track when tutorial is active
var lastUpdate = Date.now();
// Set up code background - keep it faint but visible in the background
var codeBackground = new CodeBackground();
codeBackground.initialize();
codeBackground.alpha = 0.15; // Increase alpha to make it more visible while still subtle
game.addChild(codeBackground);
// Set up regular background - slightly transparent to show code through
var background = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 0.85 // More transparent to let code background show through better
});
game.addChild(background);
// Set up player
var player = new Player();
player.x = 350; // Move to left side
player.y = 2732 - 500;
player.alpha = 0; // Initially hidden until game starts
game.addChild(player);
// Set up score text
var scoreText = new Text2("SCORE: 0", {
size: 70,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 5
});
scoreText.anchor.set(0.5, 0);
scoreText.x = 2048 / 2;
scoreText.y = 20;
LK.gui.top.addChild(scoreText);
// Set up level text
var levelText = new Text2("DAY: 1", {
size: 50,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
levelText.anchor.set(0.5, 0);
levelText.x = 2048 / 2 - 400 + 200 - 75 - 50 - 20 + 10;
levelText.y = 30;
levelText.alpha = 0; // Hide initially until game starts
LK.gui.addChild(levelText);
// Game title
var titleText = new Text2("I'M FINE!", {
size: 100,
fill: 0xff4d4d,
fontWeight: 'bold',
stroke: 0xFFFFFF,
strokeThickness: 10,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2 - 300; // Move 300 pixels to the left
titleText.y = 500;
LK.gui.addChild(titleText);
// Game subtitle
var subtitleText = new Text2("(a game about pretending everything is OK)", {
size: 60,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 2048 / 2 - 300; // Move 300 pixels to the left
subtitleText.y = 635; // Moved 35 pixels down from 600
LK.gui.addChild(subtitleText);
// Create start button
var startButton = new Container();
startButton.interactive = true;
var startBg = LK.getAsset('problem', {
anchorX: 0.5,
anchorY: 0.5,
width: 500,
height: 120,
tint: 0x444444,
alpha: 0,
radius: 30 // Rounded corners
});
startButton.addChild(startBg);
// No triangle needed
var startText = new Text2("PLAY", {
size: 85,
fill: 0xff4d4d,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive",
fontWeight: 'bold',
stroke: 0xFFFFFF,
strokeThickness: 5,
underline: true
});
startText.anchor.set(0.5, 0.5);
startText.x = 0; // Center text after triangle removal
startText.y = 0;
startButton.addChild(startText);
startButton.x = 2048 / 2 - 300; // Move 300 pixels to the left
startButton.y = 2732 / 2 - 450 + 145 + 70 + 350 - 45; // Move 305 pixels down from previous position (45px up from previous position)
LK.gui.addChild(startButton);
// Create and position stress bar
var stressBar = new StressBar();
stressBar.x = player.x + player.statusText.width / 2 + 733; // Position next to the status text with 703px more to the right
stressBar.y = player.y + 420; // Move down 70px from original position
stressBar.alpha = gameStarted ? 1 : 0; // Show if game started, otherwise hide
game.addChild(stressBar); // Add to game instead of gui to ensure visibility
// Refresh button removed
// Update stress bar
function updateStressBar() {
// Clamp stress level between 0-100
stressLevel = Math.min(100, Math.max(0, stressLevel));
// Update stress bar fill
stressBar.updateFill(stressLevel);
// Update player appearance
player.updateAppearance(stressLevel);
// Check for game over
if (stressLevel >= 100 && gameRunning) {
gameOver();
}
}
// Spawn a new problem
function spawnProblem() {
// Don't spawn if tutorial is active, game not running, or not started
if (tutorialActive || !gameRunning || !gameStarted) {
// Clear any existing problems if tutorial is visible
for (var i = problems.length - 1; i >= 0; i--) {
if (problems[i].parent) {
problems[i].destroy();
}
}
problems = [];
return;
}
// Don't spawn if we already have max problems
if (problems.length >= maxProblemsOnScreen) {
return;
}
// Create new problem
var problem = new Problem();
// Position randomly, but keep away from edges
problem.x = Math.random() * (2048 - 400) + 200;
problem.y = Math.random() * (2732 - 800) + 400;
// Make sure it doesn't overlap with player
var distToPlayer = Math.sqrt(Math.pow(problem.x - player.x, 2) + Math.pow(problem.y - player.y, 2));
if (distToPlayer < 500) {
// Too close to player, adjust position
var angle = Math.random() * Math.PI * 2;
problem.x = player.x + Math.cos(angle) * 600;
problem.y = player.y + Math.sin(angle) * 600;
// Keep within screen bounds
problem.x = Math.max(200, Math.min(problem.x, 2048 - 200));
problem.y = Math.max(400, Math.min(problem.y, 2732 - 400));
}
game.addChild(problem);
problems.push(problem);
}
// Start game function
function startGame() {
// Set gameStarted to true but not running yet (tutorial will show first)
gameStarted = true;
gameRunning = false;
tutorialActive = true; // Set tutorial flag
// Hide start screen elements
tween(titleText, {
y: -200,
alpha: 0
}, {
duration: 500,
easing: tween.easeIn
});
tween(subtitleText, {
y: -200,
alpha: 0
}, {
duration: 500,
easing: tween.easeIn
});
tween(startButton, {
y: 2732 + 200,
alpha: 0
}, {
duration: 500,
easing: tween.easeIn,
onFinish: function onFinish() {
// Clean up any problems that might exist
for (var i = problems.length - 1; i >= 0; i--) {
if (problems[i] && problems[i].parent) {
problems[i].destroy();
}
}
problems = [];
// Reset the timer
lastProblemTime = Date.now();
// Show tutorial first - the game will start when tutorial is closed
showTutorial();
// Instructions button removed
// Ensure code background continues during gameplay
codeBackground.alpha = 0.05;
// Music will be played when the START! button is pressed
}
});
}
// Show tutorial
function showTutorial() {
var tutorialContainer = new Container();
// Set tutorial active flag to prevent problems from spawning
tutorialActive = true;
gameRunning = false;
// Hide player and other game elements
player.alpha = 0;
stressBar.alpha = 0;
levelText.alpha = 0;
// Darken background
var tutorialBg = LK.getAsset('problem', {
width: 2048,
height: 2732,
tint: 0x000000,
alpha: 0.7
});
tutorialContainer.addChild(tutorialBg);
// Title
var tutorialTitle = new Text2("HOW TO PLAY", {
size: 100,
fill: 0xFFFFFF,
fontWeight: 'bold',
stroke: 0x000000,
// Added stroke for consistency and visibility
strokeThickness: 4,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
tutorialTitle.anchor.set(0.5, 0.5);
tutorialTitle.x = 2048 / 2 - 300;
tutorialTitle.y = 100;
tutorialContainer.addChild(tutorialTitle);
// FIXED: Consistent formatting for tutorial instructions with new stress mechanics
var instructions = new Text2("• PROBLEMS appear randomly and cause STRESS\n\n" + "• TAP problems before their timer runs out to REDUCE stress and EARN points\n\n" + "• If timers expire, you get MORE stress\n\n" + "• Clear ALL problems on screen to recover stress faster\n\n" + "• Don't let your stress reach 100%\n\n" + "• Just keep calm and whisper \"I'M FINE!\"", {
size: 40,
fill: 0xFFFFFF,
align: 'left',
lineHeight: 45,
stroke: 0x000000,
strokeThickness: 3,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
instructions.anchor.set(0, 0);
instructions.x = 2048 / 2 - 1000;
instructions.y = 220; // Position right below the title
instructions.width = 1400; // Ensure text fits within screen width
tutorialContainer.addChild(instructions);
// Create a tutorial-only example problem and add it to tutorial container
var exampleProblem = new TutorialProblem();
exampleProblem.x = 2048 / 2 - 300;
exampleProblem.y = 1500; // Adjusted position
tutorialContainer.addChild(exampleProblem);
// Continue button with improved styling
var continueButton = new Container();
continueButton.interactive = true;
var continueText = new Text2("START!", {
size: 70,
fill: 0xff0000,
fontWeight: 'bold',
stroke: 0xFFFFFF,
strokeThickness: 3,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
continueText.anchor.set(0.5, 0.5);
continueText.x = 0;
continueText.y = 0;
continueButton.addChild(continueText);
continueButton.x = 2048 / 2 - 300;
continueButton.y = 1800;
tutorialContainer.addChild(continueButton);
// Add to GUI
LK.gui.addChild(tutorialContainer);
// Make the continue button interactive to close tutorial
continueButton.down = function () {
tutorialContainer.destroy();
// Clean up any remaining problems
for (var i = problems.length - 1; i >= 0; i--) {
if (problems[i] && problems[i].parent) {
problems[i].destroy();
}
}
problems = [];
// Reset the timer
lastProblemTime = Date.now();
// Clear tutorial flag and start the game
tutorialActive = false;
gameRunning = true;
// Start background music when game starts
LK.playMusic('bgmusic');
// Don't stop code background animation, just keep it at low opacity during gameplay
codeBackground.alpha = 0.15; // Keep subtle matrix effect in background
// Show player and elements with animation
tween(player, {
alpha: 1
}, {
duration: 800,
easing: tween.elasticOut
});
// Show stress bar
tween(stressBar, {
alpha: 1
}, {
duration: 500
});
// Show level text
tween(levelText, {
alpha: 1
}, {
duration: 800,
easing: tween.elasticOut
});
// Refresh button removed
};
// Make the tutorial container interactive
tutorialContainer.interactive = true;
tutorialContainer.down = function (x, y, obj) {
// Only trigger if clicked on the container background, not on buttons or text
if (obj === tutorialContainer || obj === tutorialBg) {
continueButton.down();
}
};
}
// Instructions popup
function showInstructions() {
var popup = new Container();
// Darken background
var bg = LK.getAsset('problem', {
anchorX: 0.5,
anchorY: 0.5,
width: 2048,
height: 2732,
tint: 0x000000,
alpha: 0.7
});
popup.addChild(bg);
// Panel background
var panel = LK.getAsset('problem', {
anchorX: 0.5,
anchorY: 0.5,
width: 1600,
height: 1800,
tint: 0xFFFFFF,
alpha: 0.9
});
panel.x = 2048 / 2;
panel.y = 2732 / 2;
popup.addChild(panel);
// Instructions with new stress mechanics
var tutorialTitle = new Text2("HOW TO PLAY", {
size: 100,
fill: 0xFFFFFF,
fontWeight: 'bold',
stroke: 0x000000,
// Added stroke for consistency and visibility
strokeThickness: 4,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
tutorialTitle.anchor.set(0.5, 0.5);
tutorialTitle.x = 2048 / 2 - 300;
tutorialTitle.y = 100;
tutorialContainer.addChild(tutorialTitle);
// FIXED: Consistent formatting for tutorial instructions with new stress mechanics
var instructions = new Text2("• PROBLEMS appear randomly and cause STRESS\n\n" + "• TAP problems before their timer runs out to REDUCE stress and EARN points\n\n" + "• If timers expire, you get MORE stress\n\n" + "• Clear ALL problems on screen to recover stress faster\n\n" + "• Don't let your stress reach 100%\n\n" + "• Just keep calm and whisper \"I'M FINE!\"", {
size: 40,
fill: 0xFFFFFF,
align: 'left',
lineHeight: 45,
stroke: 0x000000,
strokeThickness: 3,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
instructions.anchor.set(0, 0);
instructions.x = 2048 / 2 - 300;
instructions.y = 220; // Position right below the title
instructions.width = 1400; // Ensure text fits within screen width
tutorialContainer.addChild(instructions);
// Create a tutorial-only example problem and add it to tutorial container
var exampleProblem = new TutorialProblem();
exampleProblem.x = 2048 / 2 - 300;
exampleProblem.y = 1500; // Adjusted position
tutorialContainer.addChild(exampleProblem);
// Continue button with improved styling
var continueButton = new Container();
continueButton.interactive = true;
var continueText = new Text2("START!", {
size: 70,
fill: 0xff0000,
fontWeight: 'bold',
stroke: 0xFFFFFF,
strokeThickness: 3,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
continueText.anchor.set(0.5, 0.5);
continueText.x = 0;
continueText.y = 0;
continueButton.addChild(continueText);
continueButton.x = 2048 / 2 - 300;
continueButton.y = 1800;
tutorialContainer.addChild(continueButton);
// Pause game while instructions are open
var wasPaused = !gameRunning;
gameRunning = false;
tutorialActive = true; // Set tutorial active to prevent problems
closeButton.down = function () {
popup.destroy();
// Clean up any problems that might have been created
for (var i = problems.length - 1; i >= 0; i--) {
if (problems[i] && problems[i].parent) {
problems[i].destroy();
}
}
problems = [];
tutorialActive = false; // Clear tutorial active flag
if (!wasPaused) {
gameRunning = true;
}
};
LK.gui.addChild(popup);
}
// Check if level should increase
function checkLevelProgress() {
var newLevel = Math.floor(score / 10) + 1;
if (newLevel > gameLevel) {
gameLevel = newLevel;
levelText.setText("DAY: " + gameLevel);
// Make game harder as level increases
problemSpawnInterval = Math.max(500, 1800 - gameLevel * 100);
maxProblemsOnScreen = Math.min(8, 4 + Math.floor(gameLevel / 2));
// Visual and audio feedback
LK.effects.flashScreen(0x00ff00, 500, 0.3);
LK.getSound('levelup').play();
// Show level up text
var levelUpText = new Text2("Let's Gooo!", {
size: 100,
fill: 0x00ff00,
stroke: 0x000000,
strokeThickness: 6,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
levelUpText.anchor.set(0.5, 0.5);
levelUpText.x = 2048 / 2 - 300;
levelUpText.y = 1000;
LK.gui.addChild(levelUpText);
// Animate and remove
tween(levelUpText, {
scaleX: 2,
scaleY: 2,
alpha: 0
}, {
duration: 3500,
easing: tween.easeOut,
onFinish: function onFinish() {
levelUpText.destroy();
}
});
}
}
// Game over function
function gameOver() {
gameRunning = false;
// Stop the background music when game over
LK.stopMusic();
// Visual effects
LK.effects.flashScreen(0xff0000, 1000);
// Game over container
var gameOverContainer = new Container();
// Darken background
var darkOverlay = LK.getAsset('problem', {
anchorX: 0.5,
anchorY: 0.5,
width: 2048,
height: 2732,
tint: 0x000000,
alpha: 0.8
});
darkOverlay.x = 2048 / 2;
darkOverlay.y = 2732 / 2;
gameOverContainer.addChild(darkOverlay);
// Game over text - properly centered with larger font
var gameOverText = new Text2("YOU'RE NOT FINE!", {
size: 60,
fill: 0xff0000,
fontWeight: 'bold',
stroke: 0xFFFFFF,
strokeThickness: 8,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
gameOverText.anchor.set(0.5, 0.5); // Center anchor
gameOverText.x = 2048 / 2 - 300; // Center horizontally
gameOverText.y = 200; // Position from top with more space
gameOverContainer.addChild(gameOverText);
// Meme text - position BELOW main text
var memeText = new Text2("(But we've all been there...)", {
size: 35,
fill: 0xFFFFFF,
fontStyle: 'italic',
align: 'center',
stroke: 0x000000,
strokeThickness: 2,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
memeText.anchor.set(0.5, 0.5);
memeText.x = 2048 / 2 - 300; // Center horizontally
memeText.y = gameOverText.y + 250; // Position below game over text with more space
gameOverContainer.addChild(memeText);
// Final score text
var finalScoreText = new Text2("FINAL SCORE: " + score, {
size: 50,
fill: 0xffff00,
stroke: 0x000000,
strokeThickness: 5,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" // Add font
});
finalScoreText.anchor.set(0.5, 0.5);
finalScoreText.x = 2048 / 2 - 300; // Center horizontally
finalScoreText.y = 850; // Position from top
gameOverContainer.addChild(finalScoreText);
// Level reached - updated positioning and font
var levelReachedText = new Text2("DAYS WITHOUT BURNOUT: " + gameLevel, {
size: 35,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 3,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" // Add font
});
levelReachedText.anchor.set(0.5, 0.5);
levelReachedText.x = 2048 / 2 - 300; // Center horizontally
levelReachedText.y = 1300; // Position below score with more space
gameOverContainer.addChild(levelReachedText);
// Restart button - FIXED: Made it more visible and properly centered
var restartButton = new Container();
restartButton.interactive = true;
// No background button
var restartText = new Text2("PLAY AGAIN", {
size: 35,
fill: 0xff0000,
fontWeight: 'bold',
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
restartText.anchor.set(0.5, 0.5);
restartText.x = 0;
restartText.y = 0;
restartButton.addChild(restartText);
restartButton.x = 2048 / 2 - 300; // Center horizontally
restartButton.y = 1600; // Position below level text with more space
gameOverContainer.addChild(restartButton);
// Add fun meme quote at the bottom with improved formatting
var memeQuote = new Text2(getRandomMemeQuote(), {
size: 55,
fill: 0xFFFFFF,
fontStyle: 'italic',
align: 'center',
wordWrap: true,
wordWrapWidth: 1400,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive" // Add font
});
memeQuote.anchor.set(0.5, 0.5);
memeQuote.x = 2048 / 2 - 300; // Center horizontally
memeQuote.y = 1800; // Position from top with more space
gameOverContainer.addChild(memeQuote);
// Animate in with improved timing
gameOverText.alpha = 0;
gameOverText.y -= 100;
memeText.alpha = 0;
finalScoreText.alpha = 0;
levelReachedText.alpha = 0;
restartButton.alpha = 0;
memeQuote.alpha = 0;
tween(gameOverText, {
alpha: 1,
y: gameOverText.y + 100
}, {
duration: 500,
easing: tween.elasticOut
});
tween(memeText, {
alpha: 1
}, {
duration: 500,
delay: 200 // Reduced delay for better flow
});
tween(finalScoreText, {
alpha: 1
}, {
duration: 500,
delay: 400 // Reduced delay
});
tween(levelReachedText, {
alpha: 1
}, {
duration: 500,
delay: 600 // Reduced delay
});
tween(restartButton, {
alpha: 1
}, {
duration: 500,
delay: 800 // Reduced delay
});
tween(memeQuote, {
alpha: 1
}, {
duration: 500,
delay: 1000 // Reduced delay
});
// Handle restart
restartButton.down = function () {
restartGame();
gameOverContainer.destroy();
};
LK.gui.addChild(gameOverContainer);
}
// Restart game
function restartGame() {
// Reset game variables
score = 0;
stressLevel = 0;
gameLevel = 1;
problemSpawnInterval = 1800;
maxProblemsOnScreen = 4;
lastProblemTime = 0;
gameRunning = true; // Start game immediately
tutorialActive = false; // Skip tutorial
// Clear any existing problems
for (var i = 0; i < problems.length; i++) {
if (problems[i] && problems[i].parent) {
problems[i].destroy();
}
}
problems = [];
// Reset UI
scoreText.setText("SCORE: 0");
levelText.setText("DAY: 1");
updateStressBar();
// Reset player
player.updateAppearance(0);
player.alpha = 1; // Show player immediately
// Make game elements visible immediately
stressBar.alpha = 1;
levelText.alpha = 1;
// Keep code background visible but subtle during restart
codeBackground.alpha = 0.15;
// Restart music - ensure music plays when game restarts
LK.playMusic('bgmusic');
// Set last problem time to now
lastProblemTime = Date.now();
}
// Get random meme quote for game over screen
function getRandomMemeQuote() {
var quotes = ["This is fine. Everything is fine.", "When someone asks how you're doing and you say 'fine' for the 47th time today.", "Me pretending my life isn't falling apart.", "Monday: I'm fine. Tuesday: I'M FINE! Friday: EVERYTHING IS FINE!!!", "When the deadline is tomorrow and you haven't started yet: I'M FINE!", "Adult life is saying 'I'm fine' when people ask how you are until you actually are.", "No one: \nMe: I'M FINE!!! EVERYTHING IS FINE!!!", "When your coffee spills, WiFi drops, and deadline changes all at once: I'M TOTALLY FINE!"];
return quotes[Math.floor(Math.random() * quotes.length)];
}
// Screen shake effect
function shakeScreen(intensity) {
if (!gameRunning) {
return;
}
tween(game, {
x: Math.random() * intensity - intensity / 2
}, {
duration: 50,
easing: tween.linear,
onFinish: function onFinish() {
tween(game, {
x: Math.random() * intensity - intensity / 2
}, {
duration: 50,
easing: tween.linear,
onFinish: function onFinish() {
tween(game, {
x: 0
}, {
duration: 50,
easing: tween.linear
});
}
});
}
});
}
// Clean up problems array
function cleanupProblems() {
for (var i = problems.length - 1; i >= 0; i--) {
if (!problems[i].parent) {
problems.splice(i, 1);
}
}
}
// Instructions button removed
// Handle start button
startButton.down = function () {
startGame();
};
// Main game update function
game.update = function () {
// Calculate delta time for consistent updates
var now = Date.now();
var delta = (now - lastUpdate) / 1000; // Convert to seconds
lastUpdate = now;
// Always update code background animation in all game states
if (codeBackground && codeBackground.update) {
console.log("Updating code background"); // Debug output
codeBackground.update();
}
if (!gameRunning || !gameStarted || tutorialActive) {
// Check if there are any problems to remove (during tutorial)
for (var i = problems.length - 1; i >= 0; i--) {
if (problems[i].parent) {
problems[i].destroy();
}
}
problems = [];
return;
}
// Check if it's time to spawn a new problem
if (now - lastProblemTime > problemSpawnInterval) {
spawnProblem();
lastProblemTime = now;
}
// Update all problems
for (var i = 0; i < problems.length; i++) {
if (problems[i] && problems[i].update) {
problems[i].update(delta);
}
}
// Clean up problems array
cleanupProblems();
// Gradually increase stress based on number of active problems
if (problems.length > 0) {
// Each active problem adds 0.8 stress per second, multiplied by delta time for consistent timing
var stressIncrease = problems.length * 0.8 * delta;
stressLevel = Math.min(100, stressLevel + stressIncrease);
updateStressBar();
// Visual feedback for stress increase (show occasionally)
if (Math.random() < 0.02) {
var stressPopup = new Text2("+" + stressIncrease.toFixed(1) + " STRESS", {
size: 30,
fill: 0xFF6600,
stroke: 0x000000,
strokeThickness: 2,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
stressPopup.anchor.set(0.5, 0.5);
stressPopup.x = player.x + (Math.random() * 200 - 100);
stressPopup.y = player.y - 50 - Math.random() * 50;
game.addChild(stressPopup);
// Animate stress popup
tween(stressPopup, {
y: stressPopup.y - 50,
alpha: 0
}, {
duration: 3000,
easing: tween.easeOut,
onFinish: function onFinish() {
stressPopup.destroy();
}
});
}
}
// Check level progress
checkLevelProgress();
// NEW: Reduce stress faster when there are no problems
if (problems.length === 0 && stressLevel > 0) {
// Reduce stress at a higher rate when no problems are present
stressLevel = Math.max(0, stressLevel - 1.0 * delta);
updateStressBar();
// Visual feedback for stress reduction when no problems
if (Math.random() < 0.05) {
// Occasional visual feedback
var relaxPopup = new Text2("-1 STRESS", {
size: 30,
fill: 0x00cc00,
stroke: 0x000000,
strokeThickness: 2,
font: "Caveat, 'Comic Sans MS', 'Bradley Hand', cursive"
});
relaxPopup.anchor.set(0.5, 0.5);
relaxPopup.x = player.x;
relaxPopup.y = player.y + 100;
game.addChild(relaxPopup);
// Animate relaxation popup
tween(relaxPopup, {
y: relaxPopup.y + 50,
alpha: 0
}, {
duration: 3000,
easing: tween.easeOut,
onFinish: function onFinish() {
relaxPopup.destroy();
}
});
}
}
// Randomly reduce stress (small recovery chance)
if (Math.random() < 0.001 * delta * 60 && stressLevel > 0) {
stressLevel = Math.max(0, stressLevel - 0.2);
updateStressBar();
}
// Add screen shake when stress is high
if (stressLevel >= 70 && Math.random() < 0.05) {
var intensity = (stressLevel - 70) / 30 * 20;
shakeScreen(intensity);
}
};
// Music will be played when the START! button is pressed instead
Modern office/workspace with subtle chaotic elements Include desk with scattered papers, coffee stains, overflowing inbox, sticky notes Light, neutral color palette (pale blue/gray) with professional appearance Should look slightly overwhelming but clean enough to not distract from gameplay. In-Game asset. 2d. High contrast. No shadows
Fullscreen modern App Store landscape banner, 16:9, high definition, for a game titled "FOMO Simulator: The Meeting That Could've Been An Email" and with the description "A fast-paced office simulator where you collect meetings, emails, and notifications while managing your energy levels. Strategic decisions must be made about which workplace items to prioritize as your energy depletes. Grab coffee for boosts, avoid missing important meetings, and survive the chaotic 60-second workday!". No text on banner!. In-Game asset. 2d. High contrast. No shadows
Modern App Store icon, high definition, square with rounded corners, for a game titled "FOMO Simulator: The Meeting That Could've Been An Email" and with the description "A fast-paced office simulator where you collect meetings, emails, and notifications while managing your energy levels. Strategic decisions must be made about which workplace items to prioritize as your energy depletes. Grab coffee for boosts, avoid missing important meetings, and survive the chaotic 60-second workday!". No text on icon!. In-Game asset. 2d. High contrast. No shadows