/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Baldi = Container.expand(function () { var self = Container.call(this); var baldiGraphics = self.attachAsset('baldiShape', { anchorX: 0.5, anchorY: 0.5 }); self.baseSpeed = 2; self.speed = self.baseSpeed; self.targetX = 0; self.targetY = 0; self.angerLevel = 0; self.lastRulerSound = 0; self.setTarget = function (x, y) { self.targetX = x; self.targetY = y; }; self.update = function () { // Move towards player var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 5) { // Normalize direction dx = dx / distance; dy = dy / distance; // Apply movement with current speed self.x += dx * self.speed; self.y += dy * self.speed; // Play ruler slap sound periodically var currentTime = Date.now(); if (currentTime - self.lastRulerSound > 1500 / (1 + self.angerLevel * 0.2)) { LK.getSound('ruler').play(); self.lastRulerSound = currentTime; } } }; self.increaseAnger = function () { self.angerLevel++; self.speed = self.baseSpeed + self.angerLevel * 0.5; tween(baldiGraphics, { tint: 0xff0000 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { tween(baldiGraphics, { tint: 0xffffff }, { duration: 500, easing: tween.easeIn }); } }); }; return self; }); var Door = Container.expand(function () { var self = Container.call(this); var doorGraphics = self.attachAsset('doorShape', { anchorX: 0.5, anchorY: 0.5 }); self.isLocked = false; self.isExit = false; self.setAsExit = function () { self.isExit = true; self.isLocked = true; doorGraphics.destroy(); var exitDoorGraphics = self.attachAsset('exitDoorShape', { anchorX: 0.5, anchorY: 0.5 }); return self; }; return self; }); var Notebook = Container.expand(function () { var self = Container.call(this); var notebookGraphics = self.attachAsset('notebookShape', { anchorX: 0.5, anchorY: 0.5 }); self.collected = false; self.problems = []; self.generateProblems = function () { self.problems = []; for (var i = 0; i < 3; i++) { var difficulty = game.notebooksCollected; var problem; if (difficulty < 2) { // Simple addition problems var a = Math.floor(Math.random() * 10) + 1; var b = Math.floor(Math.random() * 10) + 1; problem = { question: a + " + " + b + " = ?", answer: a + b }; } else if (difficulty < 4) { // Medium difficulty problems (addition/subtraction) var a = Math.floor(Math.random() * 20) + 1; var b = Math.floor(Math.random() * 10) + 1; var isAddition = Math.random() > 0.5; if (isAddition) { problem = { question: a + " + " + b + " = ?", answer: a + b }; } else { // Ensure a > b for subtraction if (a < b) { var temp = a; a = b; b = temp; } problem = { question: a + " - " + b + " = ?", answer: a - b }; } } else { // Hard problems (multiplication, division) if (Math.random() > 0.5) { // Multiplication var a = Math.floor(Math.random() * 12) + 1; var b = Math.floor(Math.random() * 12) + 1; problem = { question: a + " × " + b + " = ?", answer: a * b }; } else { // Division (make sure it's clean division) var b = Math.floor(Math.random() * 10) + 1; var result = Math.floor(Math.random() * 10) + 1; var a = b * result; problem = { question: a + " ÷ " + b + " = ?", answer: result }; } } // Add occasional trick questions in later notebooks if (difficulty > 3 && Math.random() < 0.2) { problem = { question: Math.random() < 0.5 ? "What is Baldi's favorite number?" : "What sound does a bee make?", answer: "IMPOSSIBLE", isTrick: true }; } self.problems.push(problem); } return self.problems; }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('playerShape', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 7; self.maxStamina = 100; self.stamina = self.maxStamina; self.isRunning = false; self.lastFootstepTime = 0; self.move = function (dx, dy) { var moveSpeed = self.speed; if (self.isRunning && self.stamina > 0) { moveSpeed *= 1.8; self.stamina -= 0.8; if (self.stamina < 0) { self.stamina = 0; } } else { // Recover stamina when not running if (!self.isRunning && self.stamina < self.maxStamina) { self.stamina += 0.3; if (self.stamina > self.maxStamina) { self.stamina = self.maxStamina; } } } // Normalize diagonal movement if (dx !== 0 && dy !== 0) { var length = Math.sqrt(dx * dx + dy * dy); dx = dx / length; dy = dy / length; } // Apply movement var newX = self.x + dx * moveSpeed; var newY = self.y + dy * moveSpeed; // Wall collision will be checked in the game.update method self.x = newX; self.y = newY; // Play footstep sound periodically while moving if (dx !== 0 || dy !== 0) { var currentTime = Date.now(); if (currentTime - self.lastFootstepTime > (self.isRunning ? 250 : 350)) { LK.getSound('footstep').play(); self.lastFootstepTime = currentTime; } } }; self.collidesWith = function (obj) { return self.intersects(obj); }; return self; }); var Principal = Container.expand(function () { var self = Container.call(this); var principalGraphics = self.attachAsset('principalShape', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 3; self.patrolPoints = []; self.currentPatrolIndex = 0; self.waitCounter = 0; self.waitTime = 60; // frames to wait at each patrol point self.isChasing = false; self.chasedPlayer = null; self.detentionDuration = 180; // 3 seconds at 60fps self.setPatrolPoints = function (points) { self.patrolPoints = points; if (points.length > 0) { self.x = points[0].x; self.y = points[0].y; } return self; }; self.update = function () { if (self.isChasing && self.chasedPlayer) { // Chase the running player var dx = self.chasedPlayer.x - self.x; var dy = self.chasedPlayer.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 40) { // Caught the player - put in detention self.isChasing = false; game.putPlayerInDetention(); return; } // Move towards player if (distance > 5) { dx = dx / distance; dy = dy / distance; self.x += dx * (self.speed * 1.2); // Slightly faster when chasing self.y += dy * (self.speed * 1.2); } return; } // Regular patrol behavior if (self.patrolPoints.length === 0) { return; } if (self.waitCounter > 0) { self.waitCounter--; return; } var targetPoint = self.patrolPoints[self.currentPatrolIndex]; var dx = targetPoint.x - self.x; var dy = targetPoint.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 5) { // Reached patrol point, wait and then move to next self.waitCounter = self.waitTime; self.currentPatrolIndex = (self.currentPatrolIndex + 1) % self.patrolPoints.length; } else { // Move towards patrol point dx = dx / distance; dy = dy / distance; self.x += dx * self.speed; self.y += dy * self.speed; } }; self.startChasing = function (player) { self.isChasing = true; self.chasedPlayer = player; LK.getSound('detention').play(); }; self.stopChasing = function () { self.isChasing = false; self.chasedPlayer = null; }; return self; }); var Wall = Container.expand(function () { var self = Container.call(this); var wallGraphics = self.attachAsset('wallShape', { anchorX: 0.5, anchorY: 0.5 }); self.checkCollision = function (player) { return self.intersects(player); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x333333 }); /**** * Game Code ****/ // Game state variables game.player = null; game.baldi = null; game.principal = null; game.notebooks = []; game.walls = []; game.doors = []; game.notebooksCollected = 0; game.totalNotebooks = 7; game.isShowingProblem = false; game.currentNotebook = null; game.currentProblemIndex = 0; game.gameState = "playing"; // playing, detention, mathProblem, gameOver, win game.detentionTimer = 0; game.movementDirection = { x: 0, y: 0 }; game.runButtonPressed = false; game.exitDoor = null; // UI Elements var staminaBarBg = LK.getAsset('staminaBarBg', { anchorX: 0, anchorY: 0, x: 30, y: 30 }); var staminaBarFg = LK.getAsset('staminaBarFg', { anchorX: 0, anchorY: 0, x: 30, y: 30, width: 400 // Will be updated based on stamina }); var notebookCountText = new Text2('0/' + game.totalNotebooks + ' Notebooks', { size: 40, fill: 0xFFFFFF }); notebookCountText.anchor.set(0, 0); var problemText = new Text2('', { size: 60, fill: 0xFFFFFF }); problemText.anchor.set(0.5, 0.5); var answerInput = new Text2('', { size: 50, fill: 0xFFFFFF }); answerInput.anchor.set(0.5, 0.5); var promptText = new Text2('Tap to enter your answer', { size: 30, fill: 0xAAAAAA }); promptText.anchor.set(0.5, 0.5); var currentInputText = ''; // Initialize map function initializeMap() { // Create school walls var mapWidth = 2000; var mapHeight = 2600; var wallThickness = 40; // Outer walls createWall(mapWidth / 2, wallThickness / 2, mapWidth, wallThickness); // Top createWall(mapWidth / 2, mapHeight - wallThickness / 2, mapWidth, wallThickness); // Bottom createWall(wallThickness / 2, mapHeight / 2, wallThickness, mapHeight); // Left createWall(mapWidth - wallThickness / 2, mapHeight / 2, wallThickness, mapHeight); // Right // Inner walls - horizontal createWall(mapWidth / 4, mapHeight / 4, mapWidth / 2, wallThickness); createWall(mapWidth * 3 / 4, mapHeight / 4, mapWidth / 2, wallThickness); createWall(mapWidth / 4, mapHeight / 2, mapWidth / 2, wallThickness); createWall(mapWidth * 3 / 4, mapHeight / 2, mapWidth / 2, wallThickness); createWall(mapWidth / 4, mapHeight * 3 / 4, mapWidth / 2, wallThickness); createWall(mapWidth * 3 / 4, mapHeight * 3 / 4, mapWidth / 2, wallThickness); // Inner walls - vertical createWall(mapWidth / 4, mapHeight * 3 / 8, wallThickness, mapHeight / 4); createWall(mapWidth / 2, mapHeight * 3 / 8, wallThickness, mapHeight / 4); createWall(mapWidth * 3 / 4, mapHeight * 3 / 8, wallThickness, mapHeight / 4); createWall(mapWidth / 4, mapHeight * 7 / 8, wallThickness, mapHeight / 4); createWall(mapWidth / 2, mapHeight * 7 / 8, wallThickness, mapHeight / 4); createWall(mapWidth * 3 / 4, mapHeight * 7 / 8, wallThickness, mapHeight / 4); // Create doors createDoor(mapWidth / 2, mapHeight / 4 + 80); createDoor(mapWidth * 3 / 4, mapHeight / 4 + 80); createDoor(mapWidth / 4, mapHeight / 2 + 80); createDoor(mapWidth / 2, mapHeight / 2 + 80); createDoor(mapWidth * 3 / 4, mapHeight * 3 / 4 - 80); // Exit door game.exitDoor = createDoor(mapWidth - 120, mapHeight / 2); game.exitDoor.setAsExit(); // Create notebooks createNotebook(mapWidth / 4 - 100, mapHeight / 4 - 100); createNotebook(mapWidth * 3 / 4 + 100, mapHeight / 4 - 100); createNotebook(mapWidth / 4 - 100, mapHeight / 2 + 100); createNotebook(mapWidth / 2 + 100, mapHeight / 2 - 100); createNotebook(mapWidth * 3 / 4 + 100, mapHeight * 3 / 4 - 100); createNotebook(mapWidth / 4 - 100, mapHeight * 3 / 4 + 100); createNotebook(mapWidth * 3 / 4 + 100, mapHeight - 200); // Create the player game.player = new Player(); game.player.x = 120; game.player.y = 120; game.addChild(game.player); // Create Baldi game.baldi = new Baldi(); game.baldi.x = mapWidth / 2; game.baldi.y = mapHeight / 2; game.addChild(game.baldi); // Create Principal game.principal = new Principal(); game.principal.setPatrolPoints([{ x: mapWidth / 4, y: mapHeight / 4 }, { x: mapWidth * 3 / 4, y: mapHeight / 4 }, { x: mapWidth * 3 / 4, y: mapHeight * 3 / 4 }, { x: mapWidth / 4, y: mapHeight * 3 / 4 }]); game.addChild(game.principal); } function createWall(x, y, width, height) { var wall = new Wall(); wall.x = x; wall.y = y; wall.width = width; wall.height = height; game.walls.push(wall); game.addChild(wall); return wall; } function createDoor(x, y) { var door = new Door(); door.x = x; door.y = y; game.doors.push(door); game.addChild(door); return door; } function createNotebook(x, y) { var notebook = new Notebook(); notebook.x = x; notebook.y = y; notebook.generateProblems(); game.notebooks.push(notebook); game.addChild(notebook); return notebook; } function setupUI() { // Add stamina bar to GUI LK.gui.addChild(staminaBarBg); LK.gui.addChild(staminaBarFg); // Add notebook counter notebookCountText.x = 30; notebookCountText.y = 80; LK.gui.addChild(notebookCountText); // Set up problem UI (not visible initially) problemText.x = 1024; problemText.y = 1200; LK.gui.addChild(problemText); answerInput.x = 1024; answerInput.y = 1300; LK.gui.addChild(answerInput); promptText.x = 1024; promptText.y = 1400; LK.gui.addChild(promptText); // Hide problem UI initially toggleProblemUI(false); } function toggleProblemUI(show) { problemText.visible = show; answerInput.visible = show; promptText.visible = show; game.isShowingProblem = show; } function showNextProblem() { if (!game.currentNotebook) { return; } var problems = game.currentNotebook.problems; if (game.currentProblemIndex >= problems.length) { // All problems answered, collect notebook collectNotebook(); return; } var problem = problems[game.currentProblemIndex]; problemText.setText(problem.question); answerInput.setText(""); currentInputText = ""; toggleProblemUI(true); } function collectNotebook() { if (!game.currentNotebook) { return; } game.currentNotebook.collected = true; game.notebooksCollected++; notebookCountText.setText(game.notebooksCollected + '/' + game.totalNotebooks + ' Notebooks'); LK.getSound('collect').play(); // Check if all notebooks are collected if (game.notebooksCollected >= game.totalNotebooks) { // Unlock exit game.exitDoor.isLocked = false; tween(game.exitDoor, { tint: 0x00ff00 }, { duration: 1000, easing: tween.easeOut }); } toggleProblemUI(false); game.gameState = "playing"; game.currentNotebook = null; } function submitAnswer() { if (!game.currentNotebook) { return; } var problems = game.currentNotebook.problems; var problem = problems[game.currentProblemIndex]; var userAnswer = currentInputText.trim(); var isCorrect = false; if (problem.isTrick) { // Trick questions always wrong isCorrect = false; } else { // Regular math problems var numAnswer = parseInt(userAnswer); isCorrect = !isNaN(numAnswer) && numAnswer === problem.answer; } if (isCorrect) { LK.getSound('correct').play(); } else { LK.getSound('wrong').play(); game.baldi.increaseAnger(); } game.currentProblemIndex++; LK.setTimeout(showNextProblem, 500); } function handlePlayerInput() { if (game.gameState === "mathProblem") { // Handle numeric input for math problems return; } if (game.gameState === "detention") { // No movement in detention game.movementDirection.x = 0; game.movementDirection.y = 0; return; } // Apply movement if (game.movementDirection.x !== 0 || game.movementDirection.y !== 0) { game.player.move(game.movementDirection.x, game.movementDirection.y); } // Update player running state game.player.isRunning = game.runButtonPressed && game.player.stamina > 0; } function checkCollisions() { // Only check collisions if playing if (game.gameState !== "playing") { return; } // Wall collisions for (var i = 0; i < game.walls.length; i++) { var wall = game.walls[i]; if (game.player.collidesWith(wall)) { // Simple bounce back game.player.x -= game.movementDirection.x * game.player.speed * 1.5; game.player.y -= game.movementDirection.y * game.player.speed * 1.5; } } // Door interactions for (var i = 0; i < game.doors.length; i++) { var door = game.doors[i]; if (game.player.collidesWith(door)) { if (door.isExit && !door.isLocked) { // Win condition LK.showYouWin(); return; } } } // Notebook collection for (var i = 0; i < game.notebooks.length; i++) { var notebook = game.notebooks[i]; if (!notebook.collected && game.player.collidesWith(notebook)) { // Start math problem game.currentNotebook = notebook; game.currentProblemIndex = 0; game.gameState = "mathProblem"; showNextProblem(); return; } } // Baldi collision - game over if (game.player.collidesWith(game.baldi)) { LK.effects.flashScreen(0xff0000, 1000); LK.showGameOver(); return; } // Principal detection if (game.player.isRunning && !game.principal.isChasing && distanceBetween(game.player, game.principal) < 300) { // Principal spots player running game.principal.startChasing(game.player); } } function putPlayerInDetention() { game.gameState = "detention"; game.detentionTimer = 180; // 3 seconds at 60fps LK.getSound('detention').play(); // Flash player tween(game.player, { alpha: 0.5 }, { duration: 250, easing: tween.easeOut, onFinish: function onFinish() { tween(game.player, { alpha: 1 }, { duration: 250, easing: tween.easeIn }); } }); } function updateDetention() { if (game.gameState !== "detention") { return; } game.detentionTimer--; if (game.detentionTimer <= 0) { game.gameState = "playing"; game.principal.stopChasing(); } } function updateNPCs() { // Update Baldi game.baldi.setTarget(game.player.x, game.player.y); game.baldi.update(); // Update Principal game.principal.update(); } function updateUI() { // Update stamina bar var staminaPercent = game.player.stamina / game.player.maxStamina; staminaBarFg.width = 400 * staminaPercent; // Update stamina bar color based on level if (staminaPercent > 0.6) { staminaBarFg.tint = 0x00ff00; } else if (staminaPercent > 0.3) { staminaBarFg.tint = 0xffff00; } else { staminaBarFg.tint = 0xff0000; } } function distanceBetween(obj1, obj2) { var dx = obj1.x - obj2.x; var dy = obj1.y - obj2.y; return Math.sqrt(dx * dx + dy * dy); } // Initialize game initializeMap(); setupUI(); LK.playMusic('gameMusic'); // Set up input handlers game.down = function (x, y, obj) { // Handle input for math problems if (game.gameState === "mathProblem") { // Check if player tapped on a number var gridSize = 120; var startX = 804; // Start position for number grid (center of screen - grid width/2) var startY = 1450; // Calculate which button was pressed var buttonX = Math.floor((x - startX) / gridSize); var buttonY = Math.floor((y - startY) / gridSize); if (buttonX >= 0 && buttonX < 3 && buttonY >= 0 && buttonY < 4) { // Number buttons 1-9 and special buttons var buttonValue = buttonX + buttonY * 3 + 1; if (buttonValue <= 9) { // Numbers 1-9 currentInputText += buttonValue; } else if (buttonValue === 10) { // Button 10 is "0" currentInputText += "0"; } else if (buttonValue === 11) { // Button 11 is "Backspace" if (currentInputText.length > 0) { currentInputText = currentInputText.substring(0, currentInputText.length - 1); } } else if (buttonValue === 12) { // Button 12 is "Enter/Submit" submitAnswer(); return; } answerInput.setText(currentInputText); } return; } // Handle movement controls var centerX = 1024; var centerY = 2200; var dx = x - centerX; var dy = y - centerY; // Check if this is the run button if (y < 2000 && x > 1700) { game.runButtonPressed = true; return; } // Determine movement direction based on touch position var angle = Math.atan2(dy, dx); // Normalize to 8 directions game.movementDirection.x = 0; game.movementDirection.y = 0; if (angle < -Math.PI * 7 / 8 || angle > Math.PI * 7 / 8) { game.movementDirection.x = -1; // Left } else if (angle < -Math.PI * 5 / 8) { game.movementDirection.x = -1; // Up-left game.movementDirection.y = -1; } else if (angle < -Math.PI * 3 / 8) { game.movementDirection.y = -1; // Up } else if (angle < -Math.PI * 1 / 8) { game.movementDirection.x = 1; // Up-right game.movementDirection.y = -1; } else if (angle < Math.PI * 1 / 8) { game.movementDirection.x = 1; // Right } else if (angle < Math.PI * 3 / 8) { game.movementDirection.x = 1; // Down-right game.movementDirection.y = 1; } else if (angle < Math.PI * 5 / 8) { game.movementDirection.y = 1; // Down } else if (angle < Math.PI * 7 / 8) { game.movementDirection.x = -1; // Down-left game.movementDirection.y = 1; } }; game.up = function (x, y, obj) { // Check if this is the run button being released if (y < 2000 && x > 1700) { game.runButtonPressed = false; return; } // Stop movement when touch is released game.movementDirection.x = 0; game.movementDirection.y = 0; }; game.move = function (x, y, obj) { // Update movement direction if the player is dragging if (game.movementDirection.x !== 0 || game.movementDirection.y !== 0) { game.down(x, y, obj); } }; // Main game update function game.update = function () { handlePlayerInput(); checkCollisions(); updateDetention(); updateNPCs(); updateUI(); // Draw number pad if showing math problem if (game.isShowingProblem) { // This would normally be done using actual UI elements, // but for simplicity, we'll handle it in the update function } };
===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,785 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1");
+
+/****
+* Classes
+****/
+var Baldi = Container.expand(function () {
+ var self = Container.call(this);
+ var baldiGraphics = self.attachAsset('baldiShape', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.baseSpeed = 2;
+ self.speed = self.baseSpeed;
+ self.targetX = 0;
+ self.targetY = 0;
+ self.angerLevel = 0;
+ self.lastRulerSound = 0;
+ self.setTarget = function (x, y) {
+ self.targetX = x;
+ self.targetY = y;
+ };
+ self.update = function () {
+ // Move towards player
+ var dx = self.targetX - self.x;
+ var dy = self.targetY - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance > 5) {
+ // Normalize direction
+ dx = dx / distance;
+ dy = dy / distance;
+ // Apply movement with current speed
+ self.x += dx * self.speed;
+ self.y += dy * self.speed;
+ // Play ruler slap sound periodically
+ var currentTime = Date.now();
+ if (currentTime - self.lastRulerSound > 1500 / (1 + self.angerLevel * 0.2)) {
+ LK.getSound('ruler').play();
+ self.lastRulerSound = currentTime;
+ }
+ }
+ };
+ self.increaseAnger = function () {
+ self.angerLevel++;
+ self.speed = self.baseSpeed + self.angerLevel * 0.5;
+ tween(baldiGraphics, {
+ tint: 0xff0000
+ }, {
+ duration: 500,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(baldiGraphics, {
+ tint: 0xffffff
+ }, {
+ duration: 500,
+ easing: tween.easeIn
+ });
+ }
+ });
+ };
+ return self;
+});
+var Door = Container.expand(function () {
+ var self = Container.call(this);
+ var doorGraphics = self.attachAsset('doorShape', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.isLocked = false;
+ self.isExit = false;
+ self.setAsExit = function () {
+ self.isExit = true;
+ self.isLocked = true;
+ doorGraphics.destroy();
+ var exitDoorGraphics = self.attachAsset('exitDoorShape', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ return self;
+ };
+ return self;
+});
+var Notebook = Container.expand(function () {
+ var self = Container.call(this);
+ var notebookGraphics = self.attachAsset('notebookShape', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.collected = false;
+ self.problems = [];
+ self.generateProblems = function () {
+ self.problems = [];
+ for (var i = 0; i < 3; i++) {
+ var difficulty = game.notebooksCollected;
+ var problem;
+ if (difficulty < 2) {
+ // Simple addition problems
+ var a = Math.floor(Math.random() * 10) + 1;
+ var b = Math.floor(Math.random() * 10) + 1;
+ problem = {
+ question: a + " + " + b + " = ?",
+ answer: a + b
+ };
+ } else if (difficulty < 4) {
+ // Medium difficulty problems (addition/subtraction)
+ var a = Math.floor(Math.random() * 20) + 1;
+ var b = Math.floor(Math.random() * 10) + 1;
+ var isAddition = Math.random() > 0.5;
+ if (isAddition) {
+ problem = {
+ question: a + " + " + b + " = ?",
+ answer: a + b
+ };
+ } else {
+ // Ensure a > b for subtraction
+ if (a < b) {
+ var temp = a;
+ a = b;
+ b = temp;
+ }
+ problem = {
+ question: a + " - " + b + " = ?",
+ answer: a - b
+ };
+ }
+ } else {
+ // Hard problems (multiplication, division)
+ if (Math.random() > 0.5) {
+ // Multiplication
+ var a = Math.floor(Math.random() * 12) + 1;
+ var b = Math.floor(Math.random() * 12) + 1;
+ problem = {
+ question: a + " × " + b + " = ?",
+ answer: a * b
+ };
+ } else {
+ // Division (make sure it's clean division)
+ var b = Math.floor(Math.random() * 10) + 1;
+ var result = Math.floor(Math.random() * 10) + 1;
+ var a = b * result;
+ problem = {
+ question: a + " ÷ " + b + " = ?",
+ answer: result
+ };
+ }
+ }
+ // Add occasional trick questions in later notebooks
+ if (difficulty > 3 && Math.random() < 0.2) {
+ problem = {
+ question: Math.random() < 0.5 ? "What is Baldi's favorite number?" : "What sound does a bee make?",
+ answer: "IMPOSSIBLE",
+ isTrick: true
+ };
+ }
+ self.problems.push(problem);
+ }
+ return self.problems;
+ };
+ return self;
+});
+var Player = Container.expand(function () {
+ var self = Container.call(this);
+ var playerGraphics = self.attachAsset('playerShape', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 7;
+ self.maxStamina = 100;
+ self.stamina = self.maxStamina;
+ self.isRunning = false;
+ self.lastFootstepTime = 0;
+ self.move = function (dx, dy) {
+ var moveSpeed = self.speed;
+ if (self.isRunning && self.stamina > 0) {
+ moveSpeed *= 1.8;
+ self.stamina -= 0.8;
+ if (self.stamina < 0) {
+ self.stamina = 0;
+ }
+ } else {
+ // Recover stamina when not running
+ if (!self.isRunning && self.stamina < self.maxStamina) {
+ self.stamina += 0.3;
+ if (self.stamina > self.maxStamina) {
+ self.stamina = self.maxStamina;
+ }
+ }
+ }
+ // Normalize diagonal movement
+ if (dx !== 0 && dy !== 0) {
+ var length = Math.sqrt(dx * dx + dy * dy);
+ dx = dx / length;
+ dy = dy / length;
+ }
+ // Apply movement
+ var newX = self.x + dx * moveSpeed;
+ var newY = self.y + dy * moveSpeed;
+ // Wall collision will be checked in the game.update method
+ self.x = newX;
+ self.y = newY;
+ // Play footstep sound periodically while moving
+ if (dx !== 0 || dy !== 0) {
+ var currentTime = Date.now();
+ if (currentTime - self.lastFootstepTime > (self.isRunning ? 250 : 350)) {
+ LK.getSound('footstep').play();
+ self.lastFootstepTime = currentTime;
+ }
+ }
+ };
+ self.collidesWith = function (obj) {
+ return self.intersects(obj);
+ };
+ return self;
+});
+var Principal = Container.expand(function () {
+ var self = Container.call(this);
+ var principalGraphics = self.attachAsset('principalShape', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.speed = 3;
+ self.patrolPoints = [];
+ self.currentPatrolIndex = 0;
+ self.waitCounter = 0;
+ self.waitTime = 60; // frames to wait at each patrol point
+ self.isChasing = false;
+ self.chasedPlayer = null;
+ self.detentionDuration = 180; // 3 seconds at 60fps
+ self.setPatrolPoints = function (points) {
+ self.patrolPoints = points;
+ if (points.length > 0) {
+ self.x = points[0].x;
+ self.y = points[0].y;
+ }
+ return self;
+ };
+ self.update = function () {
+ if (self.isChasing && self.chasedPlayer) {
+ // Chase the running player
+ var dx = self.chasedPlayer.x - self.x;
+ var dy = self.chasedPlayer.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance < 40) {
+ // Caught the player - put in detention
+ self.isChasing = false;
+ game.putPlayerInDetention();
+ return;
+ }
+ // Move towards player
+ if (distance > 5) {
+ dx = dx / distance;
+ dy = dy / distance;
+ self.x += dx * (self.speed * 1.2); // Slightly faster when chasing
+ self.y += dy * (self.speed * 1.2);
+ }
+ return;
+ }
+ // Regular patrol behavior
+ if (self.patrolPoints.length === 0) {
+ return;
+ }
+ if (self.waitCounter > 0) {
+ self.waitCounter--;
+ return;
+ }
+ var targetPoint = self.patrolPoints[self.currentPatrolIndex];
+ var dx = targetPoint.x - self.x;
+ var dy = targetPoint.y - self.y;
+ var distance = Math.sqrt(dx * dx + dy * dy);
+ if (distance < 5) {
+ // Reached patrol point, wait and then move to next
+ self.waitCounter = self.waitTime;
+ self.currentPatrolIndex = (self.currentPatrolIndex + 1) % self.patrolPoints.length;
+ } else {
+ // Move towards patrol point
+ dx = dx / distance;
+ dy = dy / distance;
+ self.x += dx * self.speed;
+ self.y += dy * self.speed;
+ }
+ };
+ self.startChasing = function (player) {
+ self.isChasing = true;
+ self.chasedPlayer = player;
+ LK.getSound('detention').play();
+ };
+ self.stopChasing = function () {
+ self.isChasing = false;
+ self.chasedPlayer = null;
+ };
+ return self;
+});
+var Wall = Container.expand(function () {
+ var self = Container.call(this);
+ var wallGraphics = self.attachAsset('wallShape', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.checkCollision = function (player) {
+ return self.intersects(player);
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x333333
+});
+
+/****
+* Game Code
+****/
+// Game state variables
+game.player = null;
+game.baldi = null;
+game.principal = null;
+game.notebooks = [];
+game.walls = [];
+game.doors = [];
+game.notebooksCollected = 0;
+game.totalNotebooks = 7;
+game.isShowingProblem = false;
+game.currentNotebook = null;
+game.currentProblemIndex = 0;
+game.gameState = "playing"; // playing, detention, mathProblem, gameOver, win
+game.detentionTimer = 0;
+game.movementDirection = {
+ x: 0,
+ y: 0
+};
+game.runButtonPressed = false;
+game.exitDoor = null;
+// UI Elements
+var staminaBarBg = LK.getAsset('staminaBarBg', {
+ anchorX: 0,
+ anchorY: 0,
+ x: 30,
+ y: 30
+});
+var staminaBarFg = LK.getAsset('staminaBarFg', {
+ anchorX: 0,
+ anchorY: 0,
+ x: 30,
+ y: 30,
+ width: 400 // Will be updated based on stamina
+});
+var notebookCountText = new Text2('0/' + game.totalNotebooks + ' Notebooks', {
+ size: 40,
+ fill: 0xFFFFFF
+});
+notebookCountText.anchor.set(0, 0);
+var problemText = new Text2('', {
+ size: 60,
+ fill: 0xFFFFFF
+});
+problemText.anchor.set(0.5, 0.5);
+var answerInput = new Text2('', {
+ size: 50,
+ fill: 0xFFFFFF
+});
+answerInput.anchor.set(0.5, 0.5);
+var promptText = new Text2('Tap to enter your answer', {
+ size: 30,
+ fill: 0xAAAAAA
+});
+promptText.anchor.set(0.5, 0.5);
+var currentInputText = '';
+// Initialize map
+function initializeMap() {
+ // Create school walls
+ var mapWidth = 2000;
+ var mapHeight = 2600;
+ var wallThickness = 40;
+ // Outer walls
+ createWall(mapWidth / 2, wallThickness / 2, mapWidth, wallThickness); // Top
+ createWall(mapWidth / 2, mapHeight - wallThickness / 2, mapWidth, wallThickness); // Bottom
+ createWall(wallThickness / 2, mapHeight / 2, wallThickness, mapHeight); // Left
+ createWall(mapWidth - wallThickness / 2, mapHeight / 2, wallThickness, mapHeight); // Right
+ // Inner walls - horizontal
+ createWall(mapWidth / 4, mapHeight / 4, mapWidth / 2, wallThickness);
+ createWall(mapWidth * 3 / 4, mapHeight / 4, mapWidth / 2, wallThickness);
+ createWall(mapWidth / 4, mapHeight / 2, mapWidth / 2, wallThickness);
+ createWall(mapWidth * 3 / 4, mapHeight / 2, mapWidth / 2, wallThickness);
+ createWall(mapWidth / 4, mapHeight * 3 / 4, mapWidth / 2, wallThickness);
+ createWall(mapWidth * 3 / 4, mapHeight * 3 / 4, mapWidth / 2, wallThickness);
+ // Inner walls - vertical
+ createWall(mapWidth / 4, mapHeight * 3 / 8, wallThickness, mapHeight / 4);
+ createWall(mapWidth / 2, mapHeight * 3 / 8, wallThickness, mapHeight / 4);
+ createWall(mapWidth * 3 / 4, mapHeight * 3 / 8, wallThickness, mapHeight / 4);
+ createWall(mapWidth / 4, mapHeight * 7 / 8, wallThickness, mapHeight / 4);
+ createWall(mapWidth / 2, mapHeight * 7 / 8, wallThickness, mapHeight / 4);
+ createWall(mapWidth * 3 / 4, mapHeight * 7 / 8, wallThickness, mapHeight / 4);
+ // Create doors
+ createDoor(mapWidth / 2, mapHeight / 4 + 80);
+ createDoor(mapWidth * 3 / 4, mapHeight / 4 + 80);
+ createDoor(mapWidth / 4, mapHeight / 2 + 80);
+ createDoor(mapWidth / 2, mapHeight / 2 + 80);
+ createDoor(mapWidth * 3 / 4, mapHeight * 3 / 4 - 80);
+ // Exit door
+ game.exitDoor = createDoor(mapWidth - 120, mapHeight / 2);
+ game.exitDoor.setAsExit();
+ // Create notebooks
+ createNotebook(mapWidth / 4 - 100, mapHeight / 4 - 100);
+ createNotebook(mapWidth * 3 / 4 + 100, mapHeight / 4 - 100);
+ createNotebook(mapWidth / 4 - 100, mapHeight / 2 + 100);
+ createNotebook(mapWidth / 2 + 100, mapHeight / 2 - 100);
+ createNotebook(mapWidth * 3 / 4 + 100, mapHeight * 3 / 4 - 100);
+ createNotebook(mapWidth / 4 - 100, mapHeight * 3 / 4 + 100);
+ createNotebook(mapWidth * 3 / 4 + 100, mapHeight - 200);
+ // Create the player
+ game.player = new Player();
+ game.player.x = 120;
+ game.player.y = 120;
+ game.addChild(game.player);
+ // Create Baldi
+ game.baldi = new Baldi();
+ game.baldi.x = mapWidth / 2;
+ game.baldi.y = mapHeight / 2;
+ game.addChild(game.baldi);
+ // Create Principal
+ game.principal = new Principal();
+ game.principal.setPatrolPoints([{
+ x: mapWidth / 4,
+ y: mapHeight / 4
+ }, {
+ x: mapWidth * 3 / 4,
+ y: mapHeight / 4
+ }, {
+ x: mapWidth * 3 / 4,
+ y: mapHeight * 3 / 4
+ }, {
+ x: mapWidth / 4,
+ y: mapHeight * 3 / 4
+ }]);
+ game.addChild(game.principal);
+}
+function createWall(x, y, width, height) {
+ var wall = new Wall();
+ wall.x = x;
+ wall.y = y;
+ wall.width = width;
+ wall.height = height;
+ game.walls.push(wall);
+ game.addChild(wall);
+ return wall;
+}
+function createDoor(x, y) {
+ var door = new Door();
+ door.x = x;
+ door.y = y;
+ game.doors.push(door);
+ game.addChild(door);
+ return door;
+}
+function createNotebook(x, y) {
+ var notebook = new Notebook();
+ notebook.x = x;
+ notebook.y = y;
+ notebook.generateProblems();
+ game.notebooks.push(notebook);
+ game.addChild(notebook);
+ return notebook;
+}
+function setupUI() {
+ // Add stamina bar to GUI
+ LK.gui.addChild(staminaBarBg);
+ LK.gui.addChild(staminaBarFg);
+ // Add notebook counter
+ notebookCountText.x = 30;
+ notebookCountText.y = 80;
+ LK.gui.addChild(notebookCountText);
+ // Set up problem UI (not visible initially)
+ problemText.x = 1024;
+ problemText.y = 1200;
+ LK.gui.addChild(problemText);
+ answerInput.x = 1024;
+ answerInput.y = 1300;
+ LK.gui.addChild(answerInput);
+ promptText.x = 1024;
+ promptText.y = 1400;
+ LK.gui.addChild(promptText);
+ // Hide problem UI initially
+ toggleProblemUI(false);
+}
+function toggleProblemUI(show) {
+ problemText.visible = show;
+ answerInput.visible = show;
+ promptText.visible = show;
+ game.isShowingProblem = show;
+}
+function showNextProblem() {
+ if (!game.currentNotebook) {
+ return;
+ }
+ var problems = game.currentNotebook.problems;
+ if (game.currentProblemIndex >= problems.length) {
+ // All problems answered, collect notebook
+ collectNotebook();
+ return;
+ }
+ var problem = problems[game.currentProblemIndex];
+ problemText.setText(problem.question);
+ answerInput.setText("");
+ currentInputText = "";
+ toggleProblemUI(true);
+}
+function collectNotebook() {
+ if (!game.currentNotebook) {
+ return;
+ }
+ game.currentNotebook.collected = true;
+ game.notebooksCollected++;
+ notebookCountText.setText(game.notebooksCollected + '/' + game.totalNotebooks + ' Notebooks');
+ LK.getSound('collect').play();
+ // Check if all notebooks are collected
+ if (game.notebooksCollected >= game.totalNotebooks) {
+ // Unlock exit
+ game.exitDoor.isLocked = false;
+ tween(game.exitDoor, {
+ tint: 0x00ff00
+ }, {
+ duration: 1000,
+ easing: tween.easeOut
+ });
+ }
+ toggleProblemUI(false);
+ game.gameState = "playing";
+ game.currentNotebook = null;
+}
+function submitAnswer() {
+ if (!game.currentNotebook) {
+ return;
+ }
+ var problems = game.currentNotebook.problems;
+ var problem = problems[game.currentProblemIndex];
+ var userAnswer = currentInputText.trim();
+ var isCorrect = false;
+ if (problem.isTrick) {
+ // Trick questions always wrong
+ isCorrect = false;
+ } else {
+ // Regular math problems
+ var numAnswer = parseInt(userAnswer);
+ isCorrect = !isNaN(numAnswer) && numAnswer === problem.answer;
+ }
+ if (isCorrect) {
+ LK.getSound('correct').play();
+ } else {
+ LK.getSound('wrong').play();
+ game.baldi.increaseAnger();
+ }
+ game.currentProblemIndex++;
+ LK.setTimeout(showNextProblem, 500);
+}
+function handlePlayerInput() {
+ if (game.gameState === "mathProblem") {
+ // Handle numeric input for math problems
+ return;
+ }
+ if (game.gameState === "detention") {
+ // No movement in detention
+ game.movementDirection.x = 0;
+ game.movementDirection.y = 0;
+ return;
+ }
+ // Apply movement
+ if (game.movementDirection.x !== 0 || game.movementDirection.y !== 0) {
+ game.player.move(game.movementDirection.x, game.movementDirection.y);
+ }
+ // Update player running state
+ game.player.isRunning = game.runButtonPressed && game.player.stamina > 0;
+}
+function checkCollisions() {
+ // Only check collisions if playing
+ if (game.gameState !== "playing") {
+ return;
+ }
+ // Wall collisions
+ for (var i = 0; i < game.walls.length; i++) {
+ var wall = game.walls[i];
+ if (game.player.collidesWith(wall)) {
+ // Simple bounce back
+ game.player.x -= game.movementDirection.x * game.player.speed * 1.5;
+ game.player.y -= game.movementDirection.y * game.player.speed * 1.5;
+ }
+ }
+ // Door interactions
+ for (var i = 0; i < game.doors.length; i++) {
+ var door = game.doors[i];
+ if (game.player.collidesWith(door)) {
+ if (door.isExit && !door.isLocked) {
+ // Win condition
+ LK.showYouWin();
+ return;
+ }
+ }
+ }
+ // Notebook collection
+ for (var i = 0; i < game.notebooks.length; i++) {
+ var notebook = game.notebooks[i];
+ if (!notebook.collected && game.player.collidesWith(notebook)) {
+ // Start math problem
+ game.currentNotebook = notebook;
+ game.currentProblemIndex = 0;
+ game.gameState = "mathProblem";
+ showNextProblem();
+ return;
+ }
+ }
+ // Baldi collision - game over
+ if (game.player.collidesWith(game.baldi)) {
+ LK.effects.flashScreen(0xff0000, 1000);
+ LK.showGameOver();
+ return;
+ }
+ // Principal detection
+ if (game.player.isRunning && !game.principal.isChasing && distanceBetween(game.player, game.principal) < 300) {
+ // Principal spots player running
+ game.principal.startChasing(game.player);
+ }
+}
+function putPlayerInDetention() {
+ game.gameState = "detention";
+ game.detentionTimer = 180; // 3 seconds at 60fps
+ LK.getSound('detention').play();
+ // Flash player
+ tween(game.player, {
+ alpha: 0.5
+ }, {
+ duration: 250,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ tween(game.player, {
+ alpha: 1
+ }, {
+ duration: 250,
+ easing: tween.easeIn
+ });
+ }
+ });
+}
+function updateDetention() {
+ if (game.gameState !== "detention") {
+ return;
+ }
+ game.detentionTimer--;
+ if (game.detentionTimer <= 0) {
+ game.gameState = "playing";
+ game.principal.stopChasing();
+ }
+}
+function updateNPCs() {
+ // Update Baldi
+ game.baldi.setTarget(game.player.x, game.player.y);
+ game.baldi.update();
+ // Update Principal
+ game.principal.update();
+}
+function updateUI() {
+ // Update stamina bar
+ var staminaPercent = game.player.stamina / game.player.maxStamina;
+ staminaBarFg.width = 400 * staminaPercent;
+ // Update stamina bar color based on level
+ if (staminaPercent > 0.6) {
+ staminaBarFg.tint = 0x00ff00;
+ } else if (staminaPercent > 0.3) {
+ staminaBarFg.tint = 0xffff00;
+ } else {
+ staminaBarFg.tint = 0xff0000;
+ }
+}
+function distanceBetween(obj1, obj2) {
+ var dx = obj1.x - obj2.x;
+ var dy = obj1.y - obj2.y;
+ return Math.sqrt(dx * dx + dy * dy);
+}
+// Initialize game
+initializeMap();
+setupUI();
+LK.playMusic('gameMusic');
+// Set up input handlers
+game.down = function (x, y, obj) {
+ // Handle input for math problems
+ if (game.gameState === "mathProblem") {
+ // Check if player tapped on a number
+ var gridSize = 120;
+ var startX = 804; // Start position for number grid (center of screen - grid width/2)
+ var startY = 1450;
+ // Calculate which button was pressed
+ var buttonX = Math.floor((x - startX) / gridSize);
+ var buttonY = Math.floor((y - startY) / gridSize);
+ if (buttonX >= 0 && buttonX < 3 && buttonY >= 0 && buttonY < 4) {
+ // Number buttons 1-9 and special buttons
+ var buttonValue = buttonX + buttonY * 3 + 1;
+ if (buttonValue <= 9) {
+ // Numbers 1-9
+ currentInputText += buttonValue;
+ } else if (buttonValue === 10) {
+ // Button 10 is "0"
+ currentInputText += "0";
+ } else if (buttonValue === 11) {
+ // Button 11 is "Backspace"
+ if (currentInputText.length > 0) {
+ currentInputText = currentInputText.substring(0, currentInputText.length - 1);
+ }
+ } else if (buttonValue === 12) {
+ // Button 12 is "Enter/Submit"
+ submitAnswer();
+ return;
+ }
+ answerInput.setText(currentInputText);
+ }
+ return;
+ }
+ // Handle movement controls
+ var centerX = 1024;
+ var centerY = 2200;
+ var dx = x - centerX;
+ var dy = y - centerY;
+ // Check if this is the run button
+ if (y < 2000 && x > 1700) {
+ game.runButtonPressed = true;
+ return;
+ }
+ // Determine movement direction based on touch position
+ var angle = Math.atan2(dy, dx);
+ // Normalize to 8 directions
+ game.movementDirection.x = 0;
+ game.movementDirection.y = 0;
+ if (angle < -Math.PI * 7 / 8 || angle > Math.PI * 7 / 8) {
+ game.movementDirection.x = -1; // Left
+ } else if (angle < -Math.PI * 5 / 8) {
+ game.movementDirection.x = -1; // Up-left
+ game.movementDirection.y = -1;
+ } else if (angle < -Math.PI * 3 / 8) {
+ game.movementDirection.y = -1; // Up
+ } else if (angle < -Math.PI * 1 / 8) {
+ game.movementDirection.x = 1; // Up-right
+ game.movementDirection.y = -1;
+ } else if (angle < Math.PI * 1 / 8) {
+ game.movementDirection.x = 1; // Right
+ } else if (angle < Math.PI * 3 / 8) {
+ game.movementDirection.x = 1; // Down-right
+ game.movementDirection.y = 1;
+ } else if (angle < Math.PI * 5 / 8) {
+ game.movementDirection.y = 1; // Down
+ } else if (angle < Math.PI * 7 / 8) {
+ game.movementDirection.x = -1; // Down-left
+ game.movementDirection.y = 1;
+ }
+};
+game.up = function (x, y, obj) {
+ // Check if this is the run button being released
+ if (y < 2000 && x > 1700) {
+ game.runButtonPressed = false;
+ return;
+ }
+ // Stop movement when touch is released
+ game.movementDirection.x = 0;
+ game.movementDirection.y = 0;
+};
+game.move = function (x, y, obj) {
+ // Update movement direction if the player is dragging
+ if (game.movementDirection.x !== 0 || game.movementDirection.y !== 0) {
+ game.down(x, y, obj);
+ }
+};
+// Main game update function
+game.update = function () {
+ handlePlayerInput();
+ checkCollisions();
+ updateDetention();
+ updateNPCs();
+ updateUI();
+ // Draw number pad if showing math problem
+ if (game.isShowingProblem) {
+ // This would normally be done using actual UI elements,
+ // but for simplicity, we'll handle it in the update function
+ }
+};
\ No newline at end of file