/****
* 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