/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { currentNight: 1, highestNight: 1 }); /**** * Classes ****/ var AnimatronicCorridor = Container.expand(function (side) { var self = Container.call(this); self.side = side; // "left" or "right" // Create the animatronic for the corridor var animatronic = self.attachAsset('animatronic', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); self.setVisible = function (visible) { self.visible = visible; if (visible) { // Animation for appearing in corridor animatronic.alpha = 0; tween(animatronic, { alpha: 1 }, { duration: 500 }); // Add a creepy movement animation tween(animatronic, { y: animatronic.y + 30 }, { duration: 2000, yoyo: true, repeat: -1 }); } }; // Make initially visible self.visible = true; return self; }); var CameraButton = Container.expand(function (id, x, y) { var self = Container.call(this); self.roomId = id; var button = self.attachAsset('button', { anchorX: 0.5, anchorY: 0.5 }); var text = new Text2('CAM ' + id, { size: 60, fill: 0xFFFFFF }); text.anchor.set(0.5, 0.5); self.addChild(text); self.x = x; self.y = y; self.interactive = true; self.down = function () { tween(button, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100 }); LK.getSound('camera').play(); }; self.up = function () { tween(button, { scaleX: 1, scaleY: 1 }, { duration: 100 }); if (currentCamera !== self.roomId) { currentCamera = self.roomId; showCamera(self.roomId); } }; return self; }); var DoorButton = Container.expand(function (side) { var self = Container.call(this); self.side = side; // "left" or "right" self.isOpen = true; var button = self.attachAsset('button', { anchorX: 0.5, anchorY: 0.5, width: 150, height: 150 }); var text = new Text2('DOOR', { size: 40, fill: 0xFFFFFF }); text.anchor.set(0.5, 0.5); self.addChild(text); self.interactive = true; self.down = function () { tween(button, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100 }); }; self.up = function () { tween(button, { scaleX: 1, scaleY: 1 }, { duration: 100 }); self.toggleDoor(); LK.getSound('door').play(); }; self.toggleDoor = function () { self.isOpen = !self.isOpen; if (self.isOpen) { text.setText("DOOR"); button.tint = 0x333333; powerDrain -= 5; // Reduce power drain when door is opened if (doors[self.side]) { tween(doors[self.side], { y: 2732 - doors[self.side].height / 2, tint: 0x000000 }, { duration: 300 }); } } else { text.setText("OPEN"); button.tint = 0x555555; powerDrain += 5; // Increase power drain when door is closed if (doors[self.side]) { tween(doors[self.side], { y: 2732 - doors[self.side].height, tint: 0xFFFFFF }, { duration: 300 }); } // Check if animatronic is at this door's corridor, and if so, send it back to entrance if (animatronicController && animatronicController.inCorridor && animatronicController.corridorSide === self.side) { // Hide from corridor if (corridorAnimatronics[self.side]) { corridorAnimatronics[self.side].setVisible(false); } // Turn off corridor light if (corridorLights[self.side]) { corridorLights[self.side].visible = false; } // Reset animatronic back to camera 1 (entrance) animatronicController.inCorridor = false; animatronicController.currentRoomIndex = 0; // Camera 1 animatronicRoom = 1; animatronicAtDoor = null; // Record the time when animatronic was sent back to enforce cooldown animatronicController.lastAttackTime = gameTime; // Show in camera 1 if (rooms[0]) { rooms[0].setAnimatronic(true); } // Play movement sound LK.getSound('footstep').play({ volume: 0.7 }); // Reset timer for next move animatronicController.moveTime = 0; } } }; return self; }); var LightButton = Container.expand(function (side) { var self = Container.call(this); self.side = side; // "left" or "right" self.isOn = false; var button = self.attachAsset('button', { anchorX: 0.5, anchorY: 0.5, width: 150, height: 150 }); var text = new Text2('LIGHT', { size: 40, fill: 0xFFFFFF }); text.anchor.set(0.5, 0.5); self.addChild(text); self.interactive = true; self.down = function () { tween(button, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100 }); if (!self.isOn) { self.isOn = true; text.setText("OFF"); powerDrain += 1; if (warnings[self.side]) { warnings[self.side].visible = animatronicAtDoor === self.side; if (animatronicAtDoor === self.side) { LK.getSound('warning').play(); } } // Make corridor visible when light is on if (corridorLights[self.side]) { corridorLights[self.side].visible = true; } } }; self.up = function () { tween(button, { scaleX: 1, scaleY: 1 }, { duration: 100 }); if (self.isOn) { self.isOn = false; text.setText("LIGHT"); powerDrain -= 1; if (warnings[self.side]) { warnings[self.side].visible = false; } // Hide corridor when light is off if (corridorLights[self.side]) { corridorLights[self.side].visible = false; } } }; return self; }); var Room = Container.expand(function (roomId, hasAnimatronic) { var self = Container.call(this); self.roomId = roomId; self.hasAnimatronic = hasAnimatronic || false; var background = self.attachAsset('cameraBg', { anchorX: 0.5, anchorY: 0.5 }); // Special code for Camera 1 if (roomId === 1) { // Camera 1: Entrance/Main Area - brighter, security desk background.tint = 0xd0d0d0; // Brighter area var desk = self.attachAsset('button', { anchorX: 0.5, anchorY: 0.5, x: -200, y: 100, width: 300, height: 150, tint: 0x553300 // Brown desk }); } else if (roomId === 2) { // Camera 2: Hallway - darker, narrow space background.tint = 0x707070; // Darker hallway var hallLight = self.attachAsset('warningLight', { anchorX: 0.5, anchorY: 0.5, x: 300, y: -200, width: 50, height: 50, tint: 0xffffaa // Dimmed hallway light }); } else if (roomId === 3) { // Camera 3: Storage Room - messy with boxes background.tint = 0x606060; // Add some storage boxes for (var i = 0; i < 3; i++) { var box = self.attachAsset('button', { anchorX: 0.5, anchorY: 0.5, x: -300 + i * 200, y: 200, width: 150, height: 150, tint: 0x855500 // Brown boxes }); } } else if (roomId === 4) { // Camera 4: Kitchen area - with counter background.tint = 0x505050; var counter = self.attachAsset('button', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 200, width: 500, height: 100, tint: 0x888888 // Metal counter }); } else if (roomId === 5) { // Camera 5: Back Room - very dark, closest to player background.tint = 0x404040; // Very dark // Add some creepy elements var backLight = self.attachAsset('warningLight', { anchorX: 0.5, anchorY: 0.5, x: -200, y: -250, width: 30, height: 30, tint: 0xff3300 // Red warning light }); // Flicker the light in the back room if (LK.ticks % 120 < 10) { backLight.visible = false; } else { backLight.visible = true; } } // Custom room names instead of generic "Room X" var roomNames = ["Main Entrance", "West Hallway", "Storage Room", "Kitchen Area", "Back Room"]; var roomText = new Text2(roomNames[roomId - 1], { size: 80, fill: 0xFFFFFF }); roomText.anchor.set(0.5, 0); roomText.y = -background.height / 2 + 50; self.addChild(roomText); // Add camera ID indicator in corner var camIdText = new Text2('CAM ' + roomId, { size: 60, fill: 0xFF0000 }); camIdText.anchor.set(0, 0); camIdText.x = -background.width / 2 + 50; camIdText.y = -background.height / 2 + 50; self.addChild(camIdText); // Always create animatronic, but set visibility based on hasAnimatronic var animatronic = self.attachAsset('animatronic', { anchorX: 0.5, anchorY: 1, y: background.height / 2 - 100 }); self.animatronic = animatronic; animatronic.visible = true; // Make animatronic always visible // Position animatronic differently in each room if (roomId === 1) { animatronic.x = -100; // Near the entrance animatronic.scaleX = 1.0; animatronic.scaleY = 1.0; } else if (roomId === 2) { animatronic.x = 200; // Coming down the hallway animatronic.scaleX = 0.9; animatronic.scaleY = 0.9; } else if (roomId === 3) { animatronic.x = -150; // Behind boxes animatronic.scaleX = 0.8; animatronic.scaleY = 0.8; } else if (roomId === 4) { animatronic.x = 50; // By the counter animatronic.scaleX = 1.1; animatronic.scaleY = 1.1; } else if (roomId === 5) { animatronic.x = 0; // In center, closer to camera animatronic.scaleX = 1.3; animatronic.scaleY = 1.3; } // Add method to update animatronic - properly handle visibility self.setAnimatronic = function (visible) { self.hasAnimatronic = visible; if (self.animatronic) { self.animatronic.visible = visible; // Force the update to take effect immediately to prevent glitching self.animatronic.alpha = visible ? 1 : 0; } }; // Add static effect to camera feed self.update = function () { // Skip static effect for Camera 1 (main entrance) if (roomId === 1) { return; } // Greatly reduced static effect when animatronic is in the room var staticProbability = self.hasAnimatronic ? 0.02 : 0.005; // Random static effect on the camera if (Math.random() < staticProbability) { // Occasionally add subtle static effect - less severe when animatronic present var staticTint = self.hasAnimatronic ? 0xffeeee : 0xeeeeee; // Very light tint background.tint = staticTint; // Avoid making animatronic temporarily invisible during static if (self.hasAnimatronic && self.animatronic) { // Keep animatronic visible, just slight movement var originalX = self.animatronic.x; var originalY = self.animatronic.y; // Very subtle movement self.animatronic.x = originalX + (Math.random() * 20 - 10); self.animatronic.y = originalY + (Math.random() * 20 - 10); // Reset position after a brief moment LK.setTimeout(function () { if (self.animatronic) { self.animatronic.x = originalX; self.animatronic.y = originalY; } }, 100); } // Reset the tint back to the room's normal tint after a short delay LK.setTimeout(function () { // Reset the tint back to the room's normal tint if (roomId === 1) { background.tint = 0xd0d0d0; } else if (roomId === 2) { background.tint = 0x707070; } else if (roomId === 3) { background.tint = 0x606060; } else if (roomId === 4) { background.tint = 0x505050; } else if (roomId === 5) { background.tint = 0x404040; } }, 100); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game constants var AnimatronicController = function AnimatronicController() { // Make these properties accessible outside the function this.moveTime = 0; this.initialDelay = 20000; // Initial delay before animatronic starts moving (20 seconds) this.gameStartTime = 0; this.hasStartedMoving = false; this.moveDuration = 20000; // Move every 20 seconds this.currentRoomIndex = 0; // Start at room 1 this.lastAttackTime = 0; // Track when the animatronic last attacked this.attackCooldown = 60000; // One in-game hour cooldown (in ms) var movementPath = [0, 1, 2, 3, 4]; // Room indices (0-based) var atDoorProbability = 0.3; // Probability to go to door when at rooms 3 or 4 this.inCorridor = false; // Make inCorridor a property of the controller this.corridorSide = null; // Make corridorSide a property of the controller rather than a local variable function moveAnimatronic() { // First, set all rooms' animatronic visibility to false for (var i = 0; i < rooms.length; i++) { if (rooms[i]) { rooms[i].setAnimatronic(false); } } // Make sure to hide the standalone cat animatronic as well if (catAnimatronic) { catAnimatronic.visible = false; } // Hide animatronic from corridor as well if (corridorAnimatronics["left"]) { corridorAnimatronics["left"].setVisible(false); } if (corridorAnimatronics["right"]) { corridorAnimatronics["right"].setVisible(false); } // Create a subtle camera disruption effect when animatronic moves if (isCameraActive) { LK.effects.flashScreen(0xcccccc, 200); // Add mild screen shake effect if (cameraView) { var origX = cameraView.x; var origY = cameraView.y; cameraView.x += Math.random() * 20 - 10; cameraView.y += Math.random() * 20 - 10; LK.setTimeout(function () { cameraView.x = origX; cameraView.y = origY; }, 100); } } // Play footstep sound for every move LK.getSound('footstep').play({ volume: 0.7 }); // If the animatronic was in camera 5 (index 4), it should appear in corridor if (currentRoomIndex === 4) { // Check if enough time has passed since last attack (1 in-game hour) var currentTime = gameTime; if (currentTime - this.lastAttackTime < this.attackCooldown) { // Not enough time passed, retreat to camera 1 currentRoomIndex = 0; // Camera 1 animatronicRoom = 1; // Show in camera 1 if (rooms[0]) { rooms[0].hasAnimatronic = true; if (rooms[0].animatronic) { rooms[0].animatronic.visible = true; } } // Reset timer for next move moveTime = 0; return; // Skip attack attempt } // Coming from camera 5 - show in corridor before going to door this.inCorridor = true; corridorSide = Math.random() < 0.5 ? "left" : "right"; this.corridorSide = corridorSide; // Show the animatronic in corridor if (corridorAnimatronics[corridorSide]) { corridorAnimatronics[corridorSide].setVisible(true); } // Turn on corridor light automatically to show the threat if (corridorLights[corridorSide]) { corridorLights[corridorSide].visible = true; } // Play a warning sound to alert player LK.getSound('warning').play({ volume: 0.7 }); // Start a 5-second door timer var doorTimer = LK.setTimeout(function () { // Check if the door is closed var doorObj = corridorSide === "left" ? doorLeft : doorRight; if (doorObj.isOpen) { // Door still open after 5 seconds - trigger jumpscare game.triggerJumpscare(); } else { // Door was closed in time // Hide from corridor if (corridorAnimatronics[corridorSide]) { corridorAnimatronics[corridorSide].setVisible(false); } // Turn off corridor light if (corridorLights[corridorSide]) { corridorLights[corridorSide].visible = false; } // Reset animatronic back to camera 1 after 3 seconds LK.setTimeout(function () { animatronicController.inCorridor = false; currentRoomIndex = 0; // Camera 1 animatronicRoom = 1; animatronicAtDoor = null; // Show in camera 1 if (rooms[0]) { rooms[0].hasAnimatronic = true; if (rooms[0].animatronic) { rooms[0].animatronic.visible = true; } } // Play movement sound LK.getSound('footstep').play({ volume: 0.7 }); // Reset timer for next move moveTime = 0; }, 3000); // Reset back to camera 1 after 3 seconds } }, 5000); // Player has 5 seconds to close the door return; // Early return to handle special corridor case } // Decide next location based on current room var nextIndex = getNextRoom(); currentRoomIndex = nextIndex; // Check if animatronic should go to a door if (currentRoomIndex === -1) { // Animatronic is at door animatronicRoom = -1; animatronicAtDoor = Math.random() < 0.5 ? "left" : "right"; // Play door approach sound (louder to indicate danger) LK.getSound('footstep').play({ volume: 0.9 }); // Also play warning sound when approaching door LK.getSound('warning').play({ volume: 0.7 }); } else { // Normal room movement animatronicRoom = currentRoomIndex + 1; // Show animatronic in new room with a dramatic effect if (rooms[currentRoomIndex]) { rooms[currentRoomIndex].hasAnimatronic = true; if (rooms[currentRoomIndex].animatronic) { rooms[currentRoomIndex].animatronic.visible = true; // Add a sudden scaling effect to make the cat appear more threatening var originalScaleX = rooms[currentRoomIndex].animatronic.scaleX; var originalScaleY = rooms[currentRoomIndex].animatronic.scaleY; rooms[currentRoomIndex].animatronic.scaleX *= 1.2; rooms[currentRoomIndex].animatronic.scaleY *= 1.2; LK.setTimeout(function () { if (rooms[currentRoomIndex] && rooms[currentRoomIndex].animatronic) { rooms[currentRoomIndex].animatronic.scaleX = originalScaleX; rooms[currentRoomIndex].animatronic.scaleY = originalScaleY; } }, 500); } } // Play movement sound LK.getSound('footstep').play(); } // Reset timer moveTime = 0; } function getNextRoom() { // Special logic when at door if (currentRoomIndex === -1) { // If at door, check if door is closed var doorObj = animatronicAtDoor === "left" ? doorLeft : doorRight; if (!doorObj.isOpen) { // Door closed, retreat to room 3 or 4 return Math.random() < 0.5 ? 2 : 3; // Room 3 or 4 (0-based) } else { // Door open, stay at door (will trigger jumpscare in main game code) return -1; } } // As time progresses, make cat more aggressive by increasing probability of going to door var baseAggressiveness = 0.2; // Base aggressiveness var timeAggressiveness = Math.min(0.3, gameTime / GAME_DURATION * 0.5); // Increases with time var totalAggressiveness = baseAggressiveness + timeAggressiveness; // Special case for rooms 3 and 4 - might go to door if (currentRoomIndex === 2 || currentRoomIndex === 3) { if (Math.random() < atDoorProbability + totalAggressiveness) { return -1; // Go to door with increasing probability } } // Sometimes allow cat to skip rooms (becoming more unpredictable) if (Math.random() < totalAggressiveness) { // Skip to a further room or back to beginning for surprise factor var possibleRooms = [0, 1, 2, 3, 4]; // Filter out current room possibleRooms = possibleRooms.filter(function (idx) { return idx !== currentRoomIndex; }); return possibleRooms[Math.floor(Math.random() * possibleRooms.length)]; } // Normal sequential movement return (currentRoomIndex + 1) % ROOM_COUNT; } this.update = function (dt) { if (!gameStarted || gameOver) { return; } // Set game start time when not initialized if (this.gameStartTime === 0) { this.gameStartTime = LK.ticks; } // Check if we should start animatronic movement if (!this.hasStartedMoving) { // Check if it's 12:50 AM to start the movement var gameProgress = Math.min(gameTime / GAME_DURATION, 1); var hour = Math.floor(gameProgress * 6); if (hour === 0) { hour = 12; // 12 AM } var minute = Math.floor(gameProgress * 6 % 1 * 60); // Start moving only when the clock hits exactly 12:50 AM if (hour === 12 && minute === 50) { this.hasStartedMoving = true; // Don't play warning sound initially - only play when first camera movement happens // Play footstep sound when animatronic starts moving LK.getSound('footstep').play({ volume: 0.7 }); console.log("Animatronic has started moving!"); // Visual cue for camera disruption during movement if (isCameraActive) { // No flashing screen effect when animatronic starts moving } // First move is specifically from camera 1 to camera 2 this.currentRoomIndex = 0; // Ensure we're at camera 1 rooms[0].hasAnimatronic = false; if (rooms[0].animatronic) { rooms[0].animatronic.visible = false; } // Set to camera 2 this.currentRoomIndex = 1; animatronicRoom = 2; if (rooms[1]) { rooms[1].hasAnimatronic = true; if (rooms[1].animatronic) { rooms[1].animatronic.visible = true; } } // Play warning sound only if cat is not on the main entrance (Camera 1) if (this.currentRoomIndex !== 0) { LK.getSound('warning').play({ volume: 0.7 }); } // Reset timer for next move after this this.moveTime = 0; } else { return; // Don't update movement time until exactly 12:50 AM } } this.moveTime += dt; // Make cat move more frequently between cameras var movementInterval = this.moveDuration * 0.7; // Faster movement speed // Move to next camera periodically and make cat advance more frequently toward player if (this.moveTime >= movementInterval) { // Cat reached camera 5 if (this.currentRoomIndex === 4) { // Check if enough time has passed since last attack (1 in-game hour) var currentTime = gameTime; if (currentTime - this.lastAttackTime < this.attackCooldown) { // Not enough time passed, retreat to camera 1 this.currentRoomIndex = 0; animatronicRoom = 1; // Show in camera 1 if (rooms[0]) { rooms[0].setAnimatronic(true); } // Reset timer for next move this.moveTime = 0; return; // Skip attack attempt } // Cat reached camera 5 - transition to corridor console.log("Cat reached camera 5, moving to corridor"); // Create a smooth transition out of camera 5 if (rooms[4] && rooms[4].animatronic) { // Fade out from camera 5 tween(rooms[4].animatronic, { alpha: 0 }, { duration: 800, onFinish: function onFinish() { // Hide from camera 5 rooms[4].setAnimatronic(false); // Appear in corridor after transition this.inCorridor = true; corridorSide = Math.random() < 0.5 ? "left" : "right"; animatronicController.corridorSide = corridorSide; // Show in corridor with a fade in effect if (corridorAnimatronics[corridorSide]) { corridorAnimatronics[corridorSide].setVisible(true); } // Play warning sound only if cat is not on the main entrance (Camera 1) if (this.currentRoomIndex !== 0) { LK.getSound('warning').play({ volume: 0.7 }); } // Start 5-second door timer LK.setTimeout(function () { // Check if door is closed var doorObj = corridorSide === "left" ? doorLeft : doorRight; if (doorObj.isOpen && animatronicController.inCorridor) { // Door still open after 5 seconds - trigger jumpscare game.triggerJumpscare(); } }, 5000); // Player has 5 seconds to close the door LK.setTimeout(function () { // Check if door is closed var doorObj = corridorSide === "left" ? doorLeft : doorRight; if (doorObj.isOpen && animatronicController.inCorridor) { // Door still open after 5 seconds - trigger jumpscare game.triggerJumpscare(); } }, 5000); // Player has 5 seconds to close the door LK.setTimeout(function () { // Check if door is closed var doorObj = corridorSide === "left" ? doorLeft : doorRight; if (doorObj.isOpen) { // Door still open after 5 seconds - trigger jumpscare game.triggerJumpscare(); } else { // Door closed in time - cat retreats to camera 1 if (corridorAnimatronics[corridorSide]) { // Fade out from corridor tween(corridorAnimatronics[corridorSide], { alpha: 0 }, { duration: 500, onFinish: function onFinish() { // Hide from corridor corridorAnimatronics[corridorSide].setVisible(false); // Turn off corridor light if (corridorLights[corridorSide]) { corridorLights[corridorSide].visible = false; } // Reset to camera 1 with a delay LK.setTimeout(function () { animatronicController.inCorridor = false; currentRoomIndex = 0; // Camera 1 animatronicRoom = 1; animatronicAtDoor = null; // Show in camera 1 with fade in if (rooms[0]) { rooms[0].setAnimatronic(true); if (rooms[0].animatronic) { rooms[0].animatronic.alpha = 0; tween(rooms[0].animatronic, { alpha: 1 }, { duration: 800 }); } } // Play movement sound LK.getSound('footstep').play({ volume: 0.7 }); // Reset timer for next move cycle moveTime = 0; }, 2000); } }); } } }, 5000); // 5 seconds to close the door } }); } } else { // Normal movement between cameras // Slowly move to next camera with transitions var currentRoom = this.currentRoomIndex; var nextRoom = currentRoom + 1; // Ensure next room is valid if (nextRoom >= 0 && nextRoom < ROOM_COUNT) { // Fade out from current room if (rooms[currentRoom] && rooms[currentRoom].animatronic) { tween(rooms[currentRoom].animatronic, { alpha: 0 }, { duration: 800, onFinish: function onFinish() { // Hide from current room rooms[currentRoom].setAnimatronic(false); // Update room indices animatronicController.currentRoomIndex = nextRoom; animatronicRoom = nextRoom + 1; // Show in next room with fade in if (rooms[nextRoom]) { rooms[nextRoom].setAnimatronic(true); if (rooms[nextRoom].animatronic) { rooms[nextRoom].animatronic.alpha = 0; tween(rooms[nextRoom].animatronic, { alpha: 1 }, { duration: 800 }); } } // Play subtle movement sound LK.getSound('footstep').play({ volume: 0.5 }); } }); } } } // Reset timer for next move this.moveTime = 0; } }; return this; }; var GAME_WIDTH = 2048; var GAME_HEIGHT = 2732; var MAX_POWER = 100; var POWER_DRAIN_RATE = 0.003; // Reduced base drain rate var GAME_DURATION = 360000; // 6 minutes (6 game hours) var ROOM_COUNT = 5; // Game state variables var currentNight = storage.currentNight || 1; var power = MAX_POWER; var powerDrain = 1; // Base power drain var gameTime = 0; var currentCamera = 1; var isCameraActive = false; var gameStarted = false; var gameOver = false; var animatronicRoom = 1; var animatronicMoveProbability = 0.05 * currentNight; var animatronicAtDoor = null; // "left", "right", or null var lastAnimatronicMove = 0; var doorLeftOpen = true; var doorRightOpen = true; var animatronicController = new AnimatronicController(); var rooms = []; var cameraButtons = []; var doors = { left: null, right: null }; var warnings = { left: null, right: null }; var corridorLights = { left: null, right: null }; var corridorAnimatronics = { left: null, right: null }; // Initialize the office view var office = game.addChild(LK.getAsset('office', { anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2, y: GAME_HEIGHT / 2, scaleX: 10, scaleY: 10 })); // We don't need a standalone cat animatronic since we already have animatronics in rooms and corridors // Creating a completely hidden reference for animatronic that will never be shown var catAnimatronic = new Container(); catAnimatronic.x = -9999; catAnimatronic.y = -9999; catAnimatronic.visible = false; catAnimatronic.alpha = 0; catAnimatronic.scaleX = 0; catAnimatronic.scaleY = 0; // Setup camera view var cameraView = new Container(); cameraView.x = GAME_WIDTH / 2; cameraView.y = GAME_HEIGHT / 2; cameraView.visible = false; game.addChild(cameraView); var cameraScreen = cameraView.addChild(LK.getAsset('cameraScreen', { anchorX: 0.5, anchorY: 0.5 })); // Create rooms for the camera system for (var i = 1; i <= ROOM_COUNT; i++) { var room = new Room(i, i === animatronicRoom); room.x = 0; room.y = 0; room.visible = false; cameraView.addChild(room); rooms.push(room); } // Make the first room visible initially and ensure animatronic is visible rooms[0].visible = true; rooms[0].hasAnimatronic = true; if (rooms[0].animatronic) { rooms[0].animatronic.visible = true; } // Create camera buttons panel var cameraPanel = new Container(); cameraPanel.x = GAME_WIDTH / 2; cameraPanel.y = GAME_HEIGHT - 300; cameraPanel.visible = false; game.addChild(cameraPanel); for (var i = 1; i <= ROOM_COUNT; i++) { var col = (i - 1) % 3; var row = Math.floor((i - 1) / 3); var button = new CameraButton(i, (col - 1) * 350, row * 220); cameraPanel.addChild(button); cameraButtons.push(button); } // Create camera toggle button var toggleCameraBtn = game.addChild(LK.getAsset('button', { anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH / 2, y: GAME_HEIGHT - 150 })); var cameraText = new Text2('CAMERAS', { size: 60, fill: 0xFFFFFF }); cameraText.anchor.set(0.5, 0.5); cameraText.x = toggleCameraBtn.x; cameraText.y = toggleCameraBtn.y; game.addChild(cameraText); // Create power indicator var powerBarBg = game.addChild(LK.getAsset('powerBar', { anchorX: 0, anchorY: 0.5, x: 150, y: 150, tint: 0x555555 })); var powerBarFg = game.addChild(LK.getAsset('powerBar', { anchorX: 0, anchorY: 0.5, x: 150, y: 150 })); var powerText = new Text2('Power: 100%', { size: 40, fill: 0xFFFFFF }); powerText.anchor.set(0, 0.5); powerText.x = 150; powerText.y = 200; game.addChild(powerText); // Create clock var clockBg = game.addChild(LK.getAsset('clockBg', { anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH - 200, y: 100 })); var clockText = new Text2('12:00 AM', { size: 50, fill: 0xFFFFFF }); clockText.anchor.set(0.5, 0.5); clockText.x = clockBg.x; clockText.y = clockBg.y; game.addChild(clockText); // Create night indicator var nightText = new Text2('Night ' + currentNight, { size: 70, fill: 0xFFFFFF }); nightText.anchor.set(0.5, 0.5); nightText.x = GAME_WIDTH / 2; nightText.y = 100; game.addChild(nightText); // Create door controls var doorLeft = new DoorButton("left"); doorLeft.x = 150; doorLeft.y = GAME_HEIGHT / 2; game.addChild(doorLeft); var doorRight = new DoorButton("right"); doorRight.x = GAME_WIDTH - 150; doorRight.y = GAME_HEIGHT / 2; game.addChild(doorRight); // Create light controls var lightLeft = new LightButton("left"); lightLeft.x = 150; lightLeft.y = GAME_HEIGHT / 2 + 200; game.addChild(lightLeft); var lightRight = new LightButton("right"); lightRight.x = GAME_WIDTH - 150; lightRight.y = GAME_HEIGHT / 2 + 200; game.addChild(lightRight); // Create door visuals var leftDoor = game.addChild(LK.getAsset('door', { anchorX: 0.5, anchorY: 0, x: 550, y: GAME_HEIGHT - 800 / 2 })); doors.left = leftDoor; var rightDoor = game.addChild(LK.getAsset('door', { anchorX: 0.5, anchorY: 0, x: GAME_WIDTH - 550, y: GAME_HEIGHT - 800 / 2 })); doors.right = rightDoor; // Create warning lights var warningLeft = game.addChild(LK.getAsset('warningLight', { anchorX: 0.5, anchorY: 0.5, x: 550, y: GAME_HEIGHT / 2 })); warningLeft.visible = false; warnings.left = warningLeft; var warningRight = game.addChild(LK.getAsset('warningLight', { anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH - 550, y: GAME_HEIGHT / 2 })); warningRight.visible = false; warnings.right = warningRight; // Create corridor light visuals as simple yellow rectangles var corridorLightLeft = game.addChild(LK.getAsset('button', { anchorX: 0.5, anchorY: 0.5, x: 550, y: GAME_HEIGHT / 2, width: 400, height: 800, tint: 0xffff00 })); corridorLightLeft.visible = false; corridorLights.left = corridorLightLeft; var corridorLightRight = game.addChild(LK.getAsset('button', { anchorX: 0.5, anchorY: 0.5, x: GAME_WIDTH - 550, y: GAME_HEIGHT / 2, width: 400, height: 800, tint: 0xffff00 })); corridorLightRight.visible = false; corridorLights.right = corridorLightRight; // Create corridor animatronics corridorAnimatronics.left = new AnimatronicCorridor("left"); corridorAnimatronics.left.x = 550; corridorAnimatronics.left.y = GAME_HEIGHT / 2; corridorAnimatronics.left.setVisible(false); game.addChild(corridorAnimatronics.left); corridorAnimatronics.right = new AnimatronicCorridor("right"); corridorAnimatronics.right.x = GAME_WIDTH - 550; corridorAnimatronics.right.y = GAME_HEIGHT / 2; corridorAnimatronics.right.setVisible(false); game.addChild(corridorAnimatronics.right); // Create start game instructions var instructionText = new Text2("Click to start Night " + currentNight, { size: 80, fill: 0xFFFFFF }); instructionText.anchor.set(0.5, 0.5); instructionText.x = GAME_WIDTH / 2; instructionText.y = GAME_HEIGHT / 2; game.addChild(instructionText); // Helper function to show camera function showCamera(roomId) { // Ensure camera view is visible cameraView.visible = true; // Make sure valid room is selected if (roomId < 1 || roomId > rooms.length) { roomId = 1; // Default to camera 1 if invalid } // Hide all rooms first for (var i = 0; i < rooms.length; i++) { rooms[i].visible = false; } // Hide corridor animatronics when switching cameras if (corridorAnimatronics["left"]) { corridorAnimatronics["left"].setVisible(false); } if (corridorAnimatronics["right"]) { corridorAnimatronics["right"].setVisible(false); } // Show the selected room rooms[roomId - 1].visible = true; // Make sure the animatronic is shown correctly in this room if (animatronicRoom === roomId) { rooms[roomId - 1].setAnimatronic(true); } else { rooms[roomId - 1].setAnimatronic(false); } } // Helper function to toggle camera view function toggleCamera() { isCameraActive = !isCameraActive; if (isCameraActive) { // Show camera view first cameraView.visible = true; cameraPanel.visible = true; LK.getSound('camera').play(); cameraText.setText("CLOSE"); // Hide corridor animatronics when camera is active if (corridorAnimatronics["left"]) { corridorAnimatronics["left"].setVisible(false); } if (corridorAnimatronics["right"]) { corridorAnimatronics["right"].setVisible(false); } // Show camera immediately to avoid black flash showCamera(currentCamera); powerDrain += 2; // Increased power drain for cameras // Hide doors when camera view is active if (doors.left) { doors.left.visible = false; } if (doors.right) { doors.right.visible = false; } } else { // Hide camera view immediately cameraView.visible = false; cameraPanel.visible = false; cameraText.setText("CAMERAS"); powerDrain -= 2; // Decreased by same amount when turning off // Make sure corridor animatronics are visible/hidden correctly if (corridorAnimatronics["left"]) { corridorAnimatronics["left"].setVisible(animatronicController.corridorSide === "left" && animatronicController.inCorridor); } if (corridorAnimatronics["right"]) { corridorAnimatronics["right"].setVisible(animatronicController.corridorSide === "right" && animatronicController.inCorridor); } // Show doors when returning to office view if (doors.left) { doors.left.visible = true; } if (doors.right) { doors.right.visible = true; } } } // Update animatronic location function has been replaced by the AnimatronicController // Handle power outage scenario game.powerOutage = function powerOutage() { if (gameOver) { return; } gameOver = true; // Turn off all lights if (corridorLights["left"]) { corridorLights["left"].visible = false; } if (corridorLights["right"]) { corridorLights["right"].visible = false; } // Turn off warnings if (warnings["left"]) { warnings["left"].visible = false; } if (warnings["right"]) { warnings["right"].visible = false; } // Hide camera view if active if (isCameraActive) { isCameraActive = false; cameraView.visible = false; cameraPanel.visible = false; cameraText.setText("CAMERAS"); } // Set screen to black LK.effects.flashScreen(0x000000, 500, false); // Play a sound if we have one for power outage // Wait a random time between 2-7 seconds before jumpscare var randomDelay = 2000 + Math.random() * 5000; LK.setTimeout(function () { // Make sure the blue and green cat appears for jumpscare // Place cat in corridor animatronicController.inCorridor = true; animatronicController.corridorSide = Math.random() < 0.5 ? "left" : "right"; // Trigger jumpscare with the power outage flag game.triggerJumpscare(true); }, randomDelay); }; // Trigger jumpscare - defined as a game method to be accessible from AnimatronicController game.triggerJumpscare = function triggerJumpscare(isPowerOutage) { if (gameOver && !isPowerOutage) { return; } // Only check corridor condition if not a power outage if (!isPowerOutage && !animatronicController.inCorridor) { return; } gameOver = true; // Record the time of successful attack for cooldown animatronicController.lastAttackTime = gameTime; LK.getSound('jumpscare').play(); // Make the blue and green cat appear in corridor before jumpscare var corridorSide = animatronicController.corridorSide || (Math.random() < 0.5 ? "left" : "right"); // Hide cat from all cameras for (var i = 0; i < rooms.length; i++) { if (rooms[i]) { rooms[i].setAnimatronic(false); } } // Make cat visible in corridor if (corridorAnimatronics[corridorSide]) { corridorAnimatronics[corridorSide].setVisible(true); // Force cat to be visible during jumpscare corridorAnimatronics[corridorSide].alpha = 1; // Turn on corridor light to make cat visible if (corridorLights[corridorSide]) { corridorLights[corridorSide].visible = true; } // Make sure the cat stays in corridor before jumpscare animatronicController.inCorridor = true; animatronicController.corridorSide = corridorSide; } // Deactivate cameras if they're active if (isCameraActive) { isCameraActive = false; cameraView.visible = false; cameraPanel.visible = false; cameraText.setText("CAMERAS"); // Show doors when returning to office view if (doors.left) { doors.left.visible = true; } if (doors.right) { doors.right.visible = true; } } // Open both doors when jumpscared if (doors.left && !doorLeft.isOpen) { doorLeft.isOpen = true; tween(doors.left, { y: 2732 - doors.left.height / 2, tint: 0x000000 }, { duration: 300 }); } if (doors.right && !doorRight.isOpen) { doorRight.isOpen = true; tween(doors.right, { y: 2732 - doors.right.height / 2, tint: 0x000000 }, { duration: 300 }); } // Create visible jumpscare animation with the animatronic var jumpscare = game.addChild(new Container()); jumpscare.x = GAME_WIDTH / 2; jumpscare.y = GAME_HEIGHT / 2; // Add the cat animatronic to the jumpscare var jumpscareAnimatronic = jumpscare.attachAsset('animatronic', { anchorX: 0.5, anchorY: 0.5, scaleX: 2.0, scaleY: 2.0 }); // Make sure the jumpscare is visible jumpscare.visible = true; // Add jumpscare animation tween(jumpscare, { scaleX: 4.5, scaleY: 4.5, x: GAME_WIDTH / 2 + Math.random() * 100 - 50, // Random movement y: GAME_HEIGHT / 2 + Math.random() * 100 - 50 // Random movement }, { duration: 300, easing: tween.outQuad }); LK.effects.flashScreen(0xff0000, 500); LK.setTimeout(function () { // Reset night to 1 when player dies storage.currentNight = 1; LK.showGameOver(); }, 1500); }; // Handle winning the night function winNight() { if (gameOver) { return; } gameOver = true; // Save progress if (currentNight >= storage.highestNight) { storage.highestNight = currentNight + 1; } storage.currentNight = currentNight + 1; // Display winning message var winText = new Text2("You survived until 6:00 AM! Night " + currentNight + " complete!", { size: 80, fill: 0xFFFFFF }); winText.anchor.set(0.5, 0.5); winText.x = GAME_WIDTH / 2; winText.y = GAME_HEIGHT / 2; game.addChild(winText); LK.setTimeout(function () { LK.showYouWin(); }, 3000); } // Event handlers game.down = function (x, y, obj) { if (!gameStarted) { // Start game when clicked gameStarted = true; instructionText.visible = false; LK.getSound('ambience').play(); LK.playMusic('backgroundMusic'); // Open doors when first night starts if (doors.left) { tween(doors.left, { y: 2732 - doors.left.height / 2, tint: 0x000000 }, { duration: 300 }); doorLeft.isOpen = true; } if (doors.right) { tween(doors.right, { y: 2732 - doors.right.height / 2, tint: 0x000000 }, { duration: 300 }); doorRight.isOpen = true; } return; } // Handle camera toggle button if (x >= toggleCameraBtn.x - toggleCameraBtn.width / 2 && x <= toggleCameraBtn.x + toggleCameraBtn.width / 2 && y >= toggleCameraBtn.y - toggleCameraBtn.height / 2 && y <= toggleCameraBtn.y + toggleCameraBtn.height / 2) { toggleCamera(); } }; // Game update loop game.update = function () { if (!gameStarted || gameOver) { return; } // Update game time gameTime += 16.67; // Approximate milliseconds per frame at 60fps // Update clock (6 hours from 12AM to 6AM in game duration) var gameProgress = Math.min(gameTime / GAME_DURATION, 1); // Check if animatronic is about to start moving based on the controller's timing var nearInitialMove = animatronicController && !animatronicController.hasStartedMoving && LK.ticks - animatronicController.gameStartTime >= animatronicController.initialDelay - 300 && LK.ticks - animatronicController.gameStartTime < animatronicController.initialDelay; if (nearInitialMove) { // Force the clock to show 12:50 AM right before the first movement hour = 12; minute = 50; } else { var hour = Math.floor(gameProgress * 6); if (hour === 0) { hour = 12; // 12 AM } else { hour = hour % 12; if (hour === 0) { hour = 6; } // Cap at 6 AM } var minute = Math.floor(gameProgress * 6 % 1 * 60); } var ampm = "AM"; // Always AM between 12 AM and 6 AM clockText.setText(hour + ":" + (minute < 10 ? "0" + minute : minute) + " " + ampm); // Win condition - survive until 6AM if (hour === 6 && minute === 0) { winNight(); return; } // Update power var closedDoorMultiplier = 1; // Check if doors are closed and increase power drain if (!doorLeft.isOpen && !doorRight.isOpen) { closedDoorMultiplier = 2; // Both doors closed - double drain } else if (!doorLeft.isOpen || !doorRight.isOpen) { closedDoorMultiplier = 1.5; // One door closed - 50% more drain } // Check if lights are on and adjust power drain accordingly var lightMultiplier = 1; if (lightLeft.isOn && lightRight.isOn) { lightMultiplier = 1.5; // Both lights on - 50% more drain } else if (lightLeft.isOn || lightRight.isOn) { lightMultiplier = 1.2; // One light on - 20% more drain } // Add camera multiplier var cameraMultiplier = isCameraActive ? 1.3 : 1; // Camera uses 30% more power when active power -= POWER_DRAIN_RATE * powerDrain * closedDoorMultiplier * lightMultiplier * cameraMultiplier; power = Math.max(0, power); var powerPercent = Math.floor(power); powerText.setText("Power: " + powerPercent + "%"); powerBarFg.width = power / MAX_POWER * powerBarBg.width; // Game over if power runs out if (power <= 0) { game.powerOutage(); return; } // Update animatronic controller animatronicController.update(16.67); // Update warning lights visibility based on light button state if (animatronicAtDoor === "left" && lightLeft.isOn) { warningLeft.visible = true; // Play warning sound occasionally when animatronic is spotted if (LK.ticks % 120 === 0) { // Approximately every 2 seconds LK.getSound('warning').play({ volume: 0.5 }); } } else { warningLeft.visible = false; } if (animatronicAtDoor === "right" && lightRight.isOn) { warningRight.visible = true; // Play warning sound occasionally when animatronic is spotted if (LK.ticks % 120 === 0) { // Approximately every 2 seconds LK.getSound('warning').play({ volume: 0.5 }); } } else { warningRight.visible = false; } // Visual cue when animatronic is moving between cameras if (LK.ticks % 900 === 0 && isCameraActive) { // Every 15 seconds during camera view // No flashing effect } // Add special visual effects when player is viewing the camera that contains the animatronic // but only for cameras other than the main entrance (camera 1) if (isCameraActive && currentCamera === animatronicRoom && rooms[animatronicRoom - 1] && rooms[animatronicRoom - 1].hasAnimatronic && currentCamera !== 1) { // Create occasional glitching/interference effect when looking directly at the animatronic if (LK.ticks % 120 === 0) { // Every 2 seconds // Don't flash red on any camera to make them more usable // Don't play warning sounds on any camera } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
currentNight: 1,
highestNight: 1
});
/****
* Classes
****/
var AnimatronicCorridor = Container.expand(function (side) {
var self = Container.call(this);
self.side = side; // "left" or "right"
// Create the animatronic for the corridor
var animatronic = self.attachAsset('animatronic', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
self.setVisible = function (visible) {
self.visible = visible;
if (visible) {
// Animation for appearing in corridor
animatronic.alpha = 0;
tween(animatronic, {
alpha: 1
}, {
duration: 500
});
// Add a creepy movement animation
tween(animatronic, {
y: animatronic.y + 30
}, {
duration: 2000,
yoyo: true,
repeat: -1
});
}
};
// Make initially visible
self.visible = true;
return self;
});
var CameraButton = Container.expand(function (id, x, y) {
var self = Container.call(this);
self.roomId = id;
var button = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5
});
var text = new Text2('CAM ' + id, {
size: 60,
fill: 0xFFFFFF
});
text.anchor.set(0.5, 0.5);
self.addChild(text);
self.x = x;
self.y = y;
self.interactive = true;
self.down = function () {
tween(button, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100
});
LK.getSound('camera').play();
};
self.up = function () {
tween(button, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
if (currentCamera !== self.roomId) {
currentCamera = self.roomId;
showCamera(self.roomId);
}
};
return self;
});
var DoorButton = Container.expand(function (side) {
var self = Container.call(this);
self.side = side; // "left" or "right"
self.isOpen = true;
var button = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
width: 150,
height: 150
});
var text = new Text2('DOOR', {
size: 40,
fill: 0xFFFFFF
});
text.anchor.set(0.5, 0.5);
self.addChild(text);
self.interactive = true;
self.down = function () {
tween(button, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100
});
};
self.up = function () {
tween(button, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
self.toggleDoor();
LK.getSound('door').play();
};
self.toggleDoor = function () {
self.isOpen = !self.isOpen;
if (self.isOpen) {
text.setText("DOOR");
button.tint = 0x333333;
powerDrain -= 5; // Reduce power drain when door is opened
if (doors[self.side]) {
tween(doors[self.side], {
y: 2732 - doors[self.side].height / 2,
tint: 0x000000
}, {
duration: 300
});
}
} else {
text.setText("OPEN");
button.tint = 0x555555;
powerDrain += 5; // Increase power drain when door is closed
if (doors[self.side]) {
tween(doors[self.side], {
y: 2732 - doors[self.side].height,
tint: 0xFFFFFF
}, {
duration: 300
});
}
// Check if animatronic is at this door's corridor, and if so, send it back to entrance
if (animatronicController && animatronicController.inCorridor && animatronicController.corridorSide === self.side) {
// Hide from corridor
if (corridorAnimatronics[self.side]) {
corridorAnimatronics[self.side].setVisible(false);
}
// Turn off corridor light
if (corridorLights[self.side]) {
corridorLights[self.side].visible = false;
}
// Reset animatronic back to camera 1 (entrance)
animatronicController.inCorridor = false;
animatronicController.currentRoomIndex = 0; // Camera 1
animatronicRoom = 1;
animatronicAtDoor = null;
// Record the time when animatronic was sent back to enforce cooldown
animatronicController.lastAttackTime = gameTime;
// Show in camera 1
if (rooms[0]) {
rooms[0].setAnimatronic(true);
}
// Play movement sound
LK.getSound('footstep').play({
volume: 0.7
});
// Reset timer for next move
animatronicController.moveTime = 0;
}
}
};
return self;
});
var LightButton = Container.expand(function (side) {
var self = Container.call(this);
self.side = side; // "left" or "right"
self.isOn = false;
var button = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
width: 150,
height: 150
});
var text = new Text2('LIGHT', {
size: 40,
fill: 0xFFFFFF
});
text.anchor.set(0.5, 0.5);
self.addChild(text);
self.interactive = true;
self.down = function () {
tween(button, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100
});
if (!self.isOn) {
self.isOn = true;
text.setText("OFF");
powerDrain += 1;
if (warnings[self.side]) {
warnings[self.side].visible = animatronicAtDoor === self.side;
if (animatronicAtDoor === self.side) {
LK.getSound('warning').play();
}
}
// Make corridor visible when light is on
if (corridorLights[self.side]) {
corridorLights[self.side].visible = true;
}
}
};
self.up = function () {
tween(button, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
if (self.isOn) {
self.isOn = false;
text.setText("LIGHT");
powerDrain -= 1;
if (warnings[self.side]) {
warnings[self.side].visible = false;
}
// Hide corridor when light is off
if (corridorLights[self.side]) {
corridorLights[self.side].visible = false;
}
}
};
return self;
});
var Room = Container.expand(function (roomId, hasAnimatronic) {
var self = Container.call(this);
self.roomId = roomId;
self.hasAnimatronic = hasAnimatronic || false;
var background = self.attachAsset('cameraBg', {
anchorX: 0.5,
anchorY: 0.5
});
// Special code for Camera 1
if (roomId === 1) {
// Camera 1: Entrance/Main Area - brighter, security desk
background.tint = 0xd0d0d0; // Brighter area
var desk = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
x: -200,
y: 100,
width: 300,
height: 150,
tint: 0x553300 // Brown desk
});
} else if (roomId === 2) {
// Camera 2: Hallway - darker, narrow space
background.tint = 0x707070; // Darker hallway
var hallLight = self.attachAsset('warningLight', {
anchorX: 0.5,
anchorY: 0.5,
x: 300,
y: -200,
width: 50,
height: 50,
tint: 0xffffaa // Dimmed hallway light
});
} else if (roomId === 3) {
// Camera 3: Storage Room - messy with boxes
background.tint = 0x606060;
// Add some storage boxes
for (var i = 0; i < 3; i++) {
var box = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
x: -300 + i * 200,
y: 200,
width: 150,
height: 150,
tint: 0x855500 // Brown boxes
});
}
} else if (roomId === 4) {
// Camera 4: Kitchen area - with counter
background.tint = 0x505050;
var counter = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 200,
width: 500,
height: 100,
tint: 0x888888 // Metal counter
});
} else if (roomId === 5) {
// Camera 5: Back Room - very dark, closest to player
background.tint = 0x404040; // Very dark
// Add some creepy elements
var backLight = self.attachAsset('warningLight', {
anchorX: 0.5,
anchorY: 0.5,
x: -200,
y: -250,
width: 30,
height: 30,
tint: 0xff3300 // Red warning light
});
// Flicker the light in the back room
if (LK.ticks % 120 < 10) {
backLight.visible = false;
} else {
backLight.visible = true;
}
}
// Custom room names instead of generic "Room X"
var roomNames = ["Main Entrance", "West Hallway", "Storage Room", "Kitchen Area", "Back Room"];
var roomText = new Text2(roomNames[roomId - 1], {
size: 80,
fill: 0xFFFFFF
});
roomText.anchor.set(0.5, 0);
roomText.y = -background.height / 2 + 50;
self.addChild(roomText);
// Add camera ID indicator in corner
var camIdText = new Text2('CAM ' + roomId, {
size: 60,
fill: 0xFF0000
});
camIdText.anchor.set(0, 0);
camIdText.x = -background.width / 2 + 50;
camIdText.y = -background.height / 2 + 50;
self.addChild(camIdText);
// Always create animatronic, but set visibility based on hasAnimatronic
var animatronic = self.attachAsset('animatronic', {
anchorX: 0.5,
anchorY: 1,
y: background.height / 2 - 100
});
self.animatronic = animatronic;
animatronic.visible = true; // Make animatronic always visible
// Position animatronic differently in each room
if (roomId === 1) {
animatronic.x = -100; // Near the entrance
animatronic.scaleX = 1.0;
animatronic.scaleY = 1.0;
} else if (roomId === 2) {
animatronic.x = 200; // Coming down the hallway
animatronic.scaleX = 0.9;
animatronic.scaleY = 0.9;
} else if (roomId === 3) {
animatronic.x = -150; // Behind boxes
animatronic.scaleX = 0.8;
animatronic.scaleY = 0.8;
} else if (roomId === 4) {
animatronic.x = 50; // By the counter
animatronic.scaleX = 1.1;
animatronic.scaleY = 1.1;
} else if (roomId === 5) {
animatronic.x = 0; // In center, closer to camera
animatronic.scaleX = 1.3;
animatronic.scaleY = 1.3;
}
// Add method to update animatronic - properly handle visibility
self.setAnimatronic = function (visible) {
self.hasAnimatronic = visible;
if (self.animatronic) {
self.animatronic.visible = visible;
// Force the update to take effect immediately to prevent glitching
self.animatronic.alpha = visible ? 1 : 0;
}
};
// Add static effect to camera feed
self.update = function () {
// Skip static effect for Camera 1 (main entrance)
if (roomId === 1) {
return;
}
// Greatly reduced static effect when animatronic is in the room
var staticProbability = self.hasAnimatronic ? 0.02 : 0.005;
// Random static effect on the camera
if (Math.random() < staticProbability) {
// Occasionally add subtle static effect - less severe when animatronic present
var staticTint = self.hasAnimatronic ? 0xffeeee : 0xeeeeee; // Very light tint
background.tint = staticTint;
// Avoid making animatronic temporarily invisible during static
if (self.hasAnimatronic && self.animatronic) {
// Keep animatronic visible, just slight movement
var originalX = self.animatronic.x;
var originalY = self.animatronic.y;
// Very subtle movement
self.animatronic.x = originalX + (Math.random() * 20 - 10);
self.animatronic.y = originalY + (Math.random() * 20 - 10);
// Reset position after a brief moment
LK.setTimeout(function () {
if (self.animatronic) {
self.animatronic.x = originalX;
self.animatronic.y = originalY;
}
}, 100);
}
// Reset the tint back to the room's normal tint after a short delay
LK.setTimeout(function () {
// Reset the tint back to the room's normal tint
if (roomId === 1) {
background.tint = 0xd0d0d0;
} else if (roomId === 2) {
background.tint = 0x707070;
} else if (roomId === 3) {
background.tint = 0x606060;
} else if (roomId === 4) {
background.tint = 0x505050;
} else if (roomId === 5) {
background.tint = 0x404040;
}
}, 100);
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game constants
var AnimatronicController = function AnimatronicController() {
// Make these properties accessible outside the function
this.moveTime = 0;
this.initialDelay = 20000; // Initial delay before animatronic starts moving (20 seconds)
this.gameStartTime = 0;
this.hasStartedMoving = false;
this.moveDuration = 20000; // Move every 20 seconds
this.currentRoomIndex = 0; // Start at room 1
this.lastAttackTime = 0; // Track when the animatronic last attacked
this.attackCooldown = 60000; // One in-game hour cooldown (in ms)
var movementPath = [0, 1, 2, 3, 4]; // Room indices (0-based)
var atDoorProbability = 0.3; // Probability to go to door when at rooms 3 or 4
this.inCorridor = false; // Make inCorridor a property of the controller
this.corridorSide = null; // Make corridorSide a property of the controller rather than a local variable
function moveAnimatronic() {
// First, set all rooms' animatronic visibility to false
for (var i = 0; i < rooms.length; i++) {
if (rooms[i]) {
rooms[i].setAnimatronic(false);
}
}
// Make sure to hide the standalone cat animatronic as well
if (catAnimatronic) {
catAnimatronic.visible = false;
}
// Hide animatronic from corridor as well
if (corridorAnimatronics["left"]) {
corridorAnimatronics["left"].setVisible(false);
}
if (corridorAnimatronics["right"]) {
corridorAnimatronics["right"].setVisible(false);
}
// Create a subtle camera disruption effect when animatronic moves
if (isCameraActive) {
LK.effects.flashScreen(0xcccccc, 200);
// Add mild screen shake effect
if (cameraView) {
var origX = cameraView.x;
var origY = cameraView.y;
cameraView.x += Math.random() * 20 - 10;
cameraView.y += Math.random() * 20 - 10;
LK.setTimeout(function () {
cameraView.x = origX;
cameraView.y = origY;
}, 100);
}
}
// Play footstep sound for every move
LK.getSound('footstep').play({
volume: 0.7
});
// If the animatronic was in camera 5 (index 4), it should appear in corridor
if (currentRoomIndex === 4) {
// Check if enough time has passed since last attack (1 in-game hour)
var currentTime = gameTime;
if (currentTime - this.lastAttackTime < this.attackCooldown) {
// Not enough time passed, retreat to camera 1
currentRoomIndex = 0; // Camera 1
animatronicRoom = 1;
// Show in camera 1
if (rooms[0]) {
rooms[0].hasAnimatronic = true;
if (rooms[0].animatronic) {
rooms[0].animatronic.visible = true;
}
}
// Reset timer for next move
moveTime = 0;
return; // Skip attack attempt
}
// Coming from camera 5 - show in corridor before going to door
this.inCorridor = true;
corridorSide = Math.random() < 0.5 ? "left" : "right";
this.corridorSide = corridorSide;
// Show the animatronic in corridor
if (corridorAnimatronics[corridorSide]) {
corridorAnimatronics[corridorSide].setVisible(true);
}
// Turn on corridor light automatically to show the threat
if (corridorLights[corridorSide]) {
corridorLights[corridorSide].visible = true;
}
// Play a warning sound to alert player
LK.getSound('warning').play({
volume: 0.7
});
// Start a 5-second door timer
var doorTimer = LK.setTimeout(function () {
// Check if the door is closed
var doorObj = corridorSide === "left" ? doorLeft : doorRight;
if (doorObj.isOpen) {
// Door still open after 5 seconds - trigger jumpscare
game.triggerJumpscare();
} else {
// Door was closed in time
// Hide from corridor
if (corridorAnimatronics[corridorSide]) {
corridorAnimatronics[corridorSide].setVisible(false);
}
// Turn off corridor light
if (corridorLights[corridorSide]) {
corridorLights[corridorSide].visible = false;
}
// Reset animatronic back to camera 1 after 3 seconds
LK.setTimeout(function () {
animatronicController.inCorridor = false;
currentRoomIndex = 0; // Camera 1
animatronicRoom = 1;
animatronicAtDoor = null;
// Show in camera 1
if (rooms[0]) {
rooms[0].hasAnimatronic = true;
if (rooms[0].animatronic) {
rooms[0].animatronic.visible = true;
}
}
// Play movement sound
LK.getSound('footstep').play({
volume: 0.7
});
// Reset timer for next move
moveTime = 0;
}, 3000); // Reset back to camera 1 after 3 seconds
}
}, 5000); // Player has 5 seconds to close the door
return; // Early return to handle special corridor case
}
// Decide next location based on current room
var nextIndex = getNextRoom();
currentRoomIndex = nextIndex;
// Check if animatronic should go to a door
if (currentRoomIndex === -1) {
// Animatronic is at door
animatronicRoom = -1;
animatronicAtDoor = Math.random() < 0.5 ? "left" : "right";
// Play door approach sound (louder to indicate danger)
LK.getSound('footstep').play({
volume: 0.9
});
// Also play warning sound when approaching door
LK.getSound('warning').play({
volume: 0.7
});
} else {
// Normal room movement
animatronicRoom = currentRoomIndex + 1;
// Show animatronic in new room with a dramatic effect
if (rooms[currentRoomIndex]) {
rooms[currentRoomIndex].hasAnimatronic = true;
if (rooms[currentRoomIndex].animatronic) {
rooms[currentRoomIndex].animatronic.visible = true;
// Add a sudden scaling effect to make the cat appear more threatening
var originalScaleX = rooms[currentRoomIndex].animatronic.scaleX;
var originalScaleY = rooms[currentRoomIndex].animatronic.scaleY;
rooms[currentRoomIndex].animatronic.scaleX *= 1.2;
rooms[currentRoomIndex].animatronic.scaleY *= 1.2;
LK.setTimeout(function () {
if (rooms[currentRoomIndex] && rooms[currentRoomIndex].animatronic) {
rooms[currentRoomIndex].animatronic.scaleX = originalScaleX;
rooms[currentRoomIndex].animatronic.scaleY = originalScaleY;
}
}, 500);
}
}
// Play movement sound
LK.getSound('footstep').play();
}
// Reset timer
moveTime = 0;
}
function getNextRoom() {
// Special logic when at door
if (currentRoomIndex === -1) {
// If at door, check if door is closed
var doorObj = animatronicAtDoor === "left" ? doorLeft : doorRight;
if (!doorObj.isOpen) {
// Door closed, retreat to room 3 or 4
return Math.random() < 0.5 ? 2 : 3; // Room 3 or 4 (0-based)
} else {
// Door open, stay at door (will trigger jumpscare in main game code)
return -1;
}
}
// As time progresses, make cat more aggressive by increasing probability of going to door
var baseAggressiveness = 0.2; // Base aggressiveness
var timeAggressiveness = Math.min(0.3, gameTime / GAME_DURATION * 0.5); // Increases with time
var totalAggressiveness = baseAggressiveness + timeAggressiveness;
// Special case for rooms 3 and 4 - might go to door
if (currentRoomIndex === 2 || currentRoomIndex === 3) {
if (Math.random() < atDoorProbability + totalAggressiveness) {
return -1; // Go to door with increasing probability
}
}
// Sometimes allow cat to skip rooms (becoming more unpredictable)
if (Math.random() < totalAggressiveness) {
// Skip to a further room or back to beginning for surprise factor
var possibleRooms = [0, 1, 2, 3, 4];
// Filter out current room
possibleRooms = possibleRooms.filter(function (idx) {
return idx !== currentRoomIndex;
});
return possibleRooms[Math.floor(Math.random() * possibleRooms.length)];
}
// Normal sequential movement
return (currentRoomIndex + 1) % ROOM_COUNT;
}
this.update = function (dt) {
if (!gameStarted || gameOver) {
return;
}
// Set game start time when not initialized
if (this.gameStartTime === 0) {
this.gameStartTime = LK.ticks;
}
// Check if we should start animatronic movement
if (!this.hasStartedMoving) {
// Check if it's 12:50 AM to start the movement
var gameProgress = Math.min(gameTime / GAME_DURATION, 1);
var hour = Math.floor(gameProgress * 6);
if (hour === 0) {
hour = 12; // 12 AM
}
var minute = Math.floor(gameProgress * 6 % 1 * 60);
// Start moving only when the clock hits exactly 12:50 AM
if (hour === 12 && minute === 50) {
this.hasStartedMoving = true;
// Don't play warning sound initially - only play when first camera movement happens
// Play footstep sound when animatronic starts moving
LK.getSound('footstep').play({
volume: 0.7
});
console.log("Animatronic has started moving!");
// Visual cue for camera disruption during movement
if (isCameraActive) {
// No flashing screen effect when animatronic starts moving
}
// First move is specifically from camera 1 to camera 2
this.currentRoomIndex = 0; // Ensure we're at camera 1
rooms[0].hasAnimatronic = false;
if (rooms[0].animatronic) {
rooms[0].animatronic.visible = false;
}
// Set to camera 2
this.currentRoomIndex = 1;
animatronicRoom = 2;
if (rooms[1]) {
rooms[1].hasAnimatronic = true;
if (rooms[1].animatronic) {
rooms[1].animatronic.visible = true;
}
}
// Play warning sound only if cat is not on the main entrance (Camera 1)
if (this.currentRoomIndex !== 0) {
LK.getSound('warning').play({
volume: 0.7
});
}
// Reset timer for next move after this
this.moveTime = 0;
} else {
return; // Don't update movement time until exactly 12:50 AM
}
}
this.moveTime += dt;
// Make cat move more frequently between cameras
var movementInterval = this.moveDuration * 0.7; // Faster movement speed
// Move to next camera periodically and make cat advance more frequently toward player
if (this.moveTime >= movementInterval) {
// Cat reached camera 5
if (this.currentRoomIndex === 4) {
// Check if enough time has passed since last attack (1 in-game hour)
var currentTime = gameTime;
if (currentTime - this.lastAttackTime < this.attackCooldown) {
// Not enough time passed, retreat to camera 1
this.currentRoomIndex = 0;
animatronicRoom = 1;
// Show in camera 1
if (rooms[0]) {
rooms[0].setAnimatronic(true);
}
// Reset timer for next move
this.moveTime = 0;
return; // Skip attack attempt
}
// Cat reached camera 5 - transition to corridor
console.log("Cat reached camera 5, moving to corridor");
// Create a smooth transition out of camera 5
if (rooms[4] && rooms[4].animatronic) {
// Fade out from camera 5
tween(rooms[4].animatronic, {
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
// Hide from camera 5
rooms[4].setAnimatronic(false);
// Appear in corridor after transition
this.inCorridor = true;
corridorSide = Math.random() < 0.5 ? "left" : "right";
animatronicController.corridorSide = corridorSide;
// Show in corridor with a fade in effect
if (corridorAnimatronics[corridorSide]) {
corridorAnimatronics[corridorSide].setVisible(true);
}
// Play warning sound only if cat is not on the main entrance (Camera 1)
if (this.currentRoomIndex !== 0) {
LK.getSound('warning').play({
volume: 0.7
});
}
// Start 5-second door timer
LK.setTimeout(function () {
// Check if door is closed
var doorObj = corridorSide === "left" ? doorLeft : doorRight;
if (doorObj.isOpen && animatronicController.inCorridor) {
// Door still open after 5 seconds - trigger jumpscare
game.triggerJumpscare();
}
}, 5000); // Player has 5 seconds to close the door
LK.setTimeout(function () {
// Check if door is closed
var doorObj = corridorSide === "left" ? doorLeft : doorRight;
if (doorObj.isOpen && animatronicController.inCorridor) {
// Door still open after 5 seconds - trigger jumpscare
game.triggerJumpscare();
}
}, 5000); // Player has 5 seconds to close the door
LK.setTimeout(function () {
// Check if door is closed
var doorObj = corridorSide === "left" ? doorLeft : doorRight;
if (doorObj.isOpen) {
// Door still open after 5 seconds - trigger jumpscare
game.triggerJumpscare();
} else {
// Door closed in time - cat retreats to camera 1
if (corridorAnimatronics[corridorSide]) {
// Fade out from corridor
tween(corridorAnimatronics[corridorSide], {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
// Hide from corridor
corridorAnimatronics[corridorSide].setVisible(false);
// Turn off corridor light
if (corridorLights[corridorSide]) {
corridorLights[corridorSide].visible = false;
}
// Reset to camera 1 with a delay
LK.setTimeout(function () {
animatronicController.inCorridor = false;
currentRoomIndex = 0; // Camera 1
animatronicRoom = 1;
animatronicAtDoor = null;
// Show in camera 1 with fade in
if (rooms[0]) {
rooms[0].setAnimatronic(true);
if (rooms[0].animatronic) {
rooms[0].animatronic.alpha = 0;
tween(rooms[0].animatronic, {
alpha: 1
}, {
duration: 800
});
}
}
// Play movement sound
LK.getSound('footstep').play({
volume: 0.7
});
// Reset timer for next move cycle
moveTime = 0;
}, 2000);
}
});
}
}
}, 5000); // 5 seconds to close the door
}
});
}
} else {
// Normal movement between cameras
// Slowly move to next camera with transitions
var currentRoom = this.currentRoomIndex;
var nextRoom = currentRoom + 1;
// Ensure next room is valid
if (nextRoom >= 0 && nextRoom < ROOM_COUNT) {
// Fade out from current room
if (rooms[currentRoom] && rooms[currentRoom].animatronic) {
tween(rooms[currentRoom].animatronic, {
alpha: 0
}, {
duration: 800,
onFinish: function onFinish() {
// Hide from current room
rooms[currentRoom].setAnimatronic(false);
// Update room indices
animatronicController.currentRoomIndex = nextRoom;
animatronicRoom = nextRoom + 1;
// Show in next room with fade in
if (rooms[nextRoom]) {
rooms[nextRoom].setAnimatronic(true);
if (rooms[nextRoom].animatronic) {
rooms[nextRoom].animatronic.alpha = 0;
tween(rooms[nextRoom].animatronic, {
alpha: 1
}, {
duration: 800
});
}
}
// Play subtle movement sound
LK.getSound('footstep').play({
volume: 0.5
});
}
});
}
}
}
// Reset timer for next move
this.moveTime = 0;
}
};
return this;
};
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var MAX_POWER = 100;
var POWER_DRAIN_RATE = 0.003; // Reduced base drain rate
var GAME_DURATION = 360000; // 6 minutes (6 game hours)
var ROOM_COUNT = 5;
// Game state variables
var currentNight = storage.currentNight || 1;
var power = MAX_POWER;
var powerDrain = 1; // Base power drain
var gameTime = 0;
var currentCamera = 1;
var isCameraActive = false;
var gameStarted = false;
var gameOver = false;
var animatronicRoom = 1;
var animatronicMoveProbability = 0.05 * currentNight;
var animatronicAtDoor = null; // "left", "right", or null
var lastAnimatronicMove = 0;
var doorLeftOpen = true;
var doorRightOpen = true;
var animatronicController = new AnimatronicController();
var rooms = [];
var cameraButtons = [];
var doors = {
left: null,
right: null
};
var warnings = {
left: null,
right: null
};
var corridorLights = {
left: null,
right: null
};
var corridorAnimatronics = {
left: null,
right: null
};
// Initialize the office view
var office = game.addChild(LK.getAsset('office', {
anchorX: 0.5,
anchorY: 0.5,
x: GAME_WIDTH / 2,
y: GAME_HEIGHT / 2,
scaleX: 10,
scaleY: 10
}));
// We don't need a standalone cat animatronic since we already have animatronics in rooms and corridors
// Creating a completely hidden reference for animatronic that will never be shown
var catAnimatronic = new Container();
catAnimatronic.x = -9999;
catAnimatronic.y = -9999;
catAnimatronic.visible = false;
catAnimatronic.alpha = 0;
catAnimatronic.scaleX = 0;
catAnimatronic.scaleY = 0;
// Setup camera view
var cameraView = new Container();
cameraView.x = GAME_WIDTH / 2;
cameraView.y = GAME_HEIGHT / 2;
cameraView.visible = false;
game.addChild(cameraView);
var cameraScreen = cameraView.addChild(LK.getAsset('cameraScreen', {
anchorX: 0.5,
anchorY: 0.5
}));
// Create rooms for the camera system
for (var i = 1; i <= ROOM_COUNT; i++) {
var room = new Room(i, i === animatronicRoom);
room.x = 0;
room.y = 0;
room.visible = false;
cameraView.addChild(room);
rooms.push(room);
}
// Make the first room visible initially and ensure animatronic is visible
rooms[0].visible = true;
rooms[0].hasAnimatronic = true;
if (rooms[0].animatronic) {
rooms[0].animatronic.visible = true;
}
// Create camera buttons panel
var cameraPanel = new Container();
cameraPanel.x = GAME_WIDTH / 2;
cameraPanel.y = GAME_HEIGHT - 300;
cameraPanel.visible = false;
game.addChild(cameraPanel);
for (var i = 1; i <= ROOM_COUNT; i++) {
var col = (i - 1) % 3;
var row = Math.floor((i - 1) / 3);
var button = new CameraButton(i, (col - 1) * 350, row * 220);
cameraPanel.addChild(button);
cameraButtons.push(button);
}
// Create camera toggle button
var toggleCameraBtn = game.addChild(LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
x: GAME_WIDTH / 2,
y: GAME_HEIGHT - 150
}));
var cameraText = new Text2('CAMERAS', {
size: 60,
fill: 0xFFFFFF
});
cameraText.anchor.set(0.5, 0.5);
cameraText.x = toggleCameraBtn.x;
cameraText.y = toggleCameraBtn.y;
game.addChild(cameraText);
// Create power indicator
var powerBarBg = game.addChild(LK.getAsset('powerBar', {
anchorX: 0,
anchorY: 0.5,
x: 150,
y: 150,
tint: 0x555555
}));
var powerBarFg = game.addChild(LK.getAsset('powerBar', {
anchorX: 0,
anchorY: 0.5,
x: 150,
y: 150
}));
var powerText = new Text2('Power: 100%', {
size: 40,
fill: 0xFFFFFF
});
powerText.anchor.set(0, 0.5);
powerText.x = 150;
powerText.y = 200;
game.addChild(powerText);
// Create clock
var clockBg = game.addChild(LK.getAsset('clockBg', {
anchorX: 0.5,
anchorY: 0.5,
x: GAME_WIDTH - 200,
y: 100
}));
var clockText = new Text2('12:00 AM', {
size: 50,
fill: 0xFFFFFF
});
clockText.anchor.set(0.5, 0.5);
clockText.x = clockBg.x;
clockText.y = clockBg.y;
game.addChild(clockText);
// Create night indicator
var nightText = new Text2('Night ' + currentNight, {
size: 70,
fill: 0xFFFFFF
});
nightText.anchor.set(0.5, 0.5);
nightText.x = GAME_WIDTH / 2;
nightText.y = 100;
game.addChild(nightText);
// Create door controls
var doorLeft = new DoorButton("left");
doorLeft.x = 150;
doorLeft.y = GAME_HEIGHT / 2;
game.addChild(doorLeft);
var doorRight = new DoorButton("right");
doorRight.x = GAME_WIDTH - 150;
doorRight.y = GAME_HEIGHT / 2;
game.addChild(doorRight);
// Create light controls
var lightLeft = new LightButton("left");
lightLeft.x = 150;
lightLeft.y = GAME_HEIGHT / 2 + 200;
game.addChild(lightLeft);
var lightRight = new LightButton("right");
lightRight.x = GAME_WIDTH - 150;
lightRight.y = GAME_HEIGHT / 2 + 200;
game.addChild(lightRight);
// Create door visuals
var leftDoor = game.addChild(LK.getAsset('door', {
anchorX: 0.5,
anchorY: 0,
x: 550,
y: GAME_HEIGHT - 800 / 2
}));
doors.left = leftDoor;
var rightDoor = game.addChild(LK.getAsset('door', {
anchorX: 0.5,
anchorY: 0,
x: GAME_WIDTH - 550,
y: GAME_HEIGHT - 800 / 2
}));
doors.right = rightDoor;
// Create warning lights
var warningLeft = game.addChild(LK.getAsset('warningLight', {
anchorX: 0.5,
anchorY: 0.5,
x: 550,
y: GAME_HEIGHT / 2
}));
warningLeft.visible = false;
warnings.left = warningLeft;
var warningRight = game.addChild(LK.getAsset('warningLight', {
anchorX: 0.5,
anchorY: 0.5,
x: GAME_WIDTH - 550,
y: GAME_HEIGHT / 2
}));
warningRight.visible = false;
warnings.right = warningRight;
// Create corridor light visuals as simple yellow rectangles
var corridorLightLeft = game.addChild(LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
x: 550,
y: GAME_HEIGHT / 2,
width: 400,
height: 800,
tint: 0xffff00
}));
corridorLightLeft.visible = false;
corridorLights.left = corridorLightLeft;
var corridorLightRight = game.addChild(LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
x: GAME_WIDTH - 550,
y: GAME_HEIGHT / 2,
width: 400,
height: 800,
tint: 0xffff00
}));
corridorLightRight.visible = false;
corridorLights.right = corridorLightRight;
// Create corridor animatronics
corridorAnimatronics.left = new AnimatronicCorridor("left");
corridorAnimatronics.left.x = 550;
corridorAnimatronics.left.y = GAME_HEIGHT / 2;
corridorAnimatronics.left.setVisible(false);
game.addChild(corridorAnimatronics.left);
corridorAnimatronics.right = new AnimatronicCorridor("right");
corridorAnimatronics.right.x = GAME_WIDTH - 550;
corridorAnimatronics.right.y = GAME_HEIGHT / 2;
corridorAnimatronics.right.setVisible(false);
game.addChild(corridorAnimatronics.right);
// Create start game instructions
var instructionText = new Text2("Click to start Night " + currentNight, {
size: 80,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = GAME_WIDTH / 2;
instructionText.y = GAME_HEIGHT / 2;
game.addChild(instructionText);
// Helper function to show camera
function showCamera(roomId) {
// Ensure camera view is visible
cameraView.visible = true;
// Make sure valid room is selected
if (roomId < 1 || roomId > rooms.length) {
roomId = 1; // Default to camera 1 if invalid
}
// Hide all rooms first
for (var i = 0; i < rooms.length; i++) {
rooms[i].visible = false;
}
// Hide corridor animatronics when switching cameras
if (corridorAnimatronics["left"]) {
corridorAnimatronics["left"].setVisible(false);
}
if (corridorAnimatronics["right"]) {
corridorAnimatronics["right"].setVisible(false);
}
// Show the selected room
rooms[roomId - 1].visible = true;
// Make sure the animatronic is shown correctly in this room
if (animatronicRoom === roomId) {
rooms[roomId - 1].setAnimatronic(true);
} else {
rooms[roomId - 1].setAnimatronic(false);
}
}
// Helper function to toggle camera view
function toggleCamera() {
isCameraActive = !isCameraActive;
if (isCameraActive) {
// Show camera view first
cameraView.visible = true;
cameraPanel.visible = true;
LK.getSound('camera').play();
cameraText.setText("CLOSE");
// Hide corridor animatronics when camera is active
if (corridorAnimatronics["left"]) {
corridorAnimatronics["left"].setVisible(false);
}
if (corridorAnimatronics["right"]) {
corridorAnimatronics["right"].setVisible(false);
}
// Show camera immediately to avoid black flash
showCamera(currentCamera);
powerDrain += 2; // Increased power drain for cameras
// Hide doors when camera view is active
if (doors.left) {
doors.left.visible = false;
}
if (doors.right) {
doors.right.visible = false;
}
} else {
// Hide camera view immediately
cameraView.visible = false;
cameraPanel.visible = false;
cameraText.setText("CAMERAS");
powerDrain -= 2; // Decreased by same amount when turning off
// Make sure corridor animatronics are visible/hidden correctly
if (corridorAnimatronics["left"]) {
corridorAnimatronics["left"].setVisible(animatronicController.corridorSide === "left" && animatronicController.inCorridor);
}
if (corridorAnimatronics["right"]) {
corridorAnimatronics["right"].setVisible(animatronicController.corridorSide === "right" && animatronicController.inCorridor);
}
// Show doors when returning to office view
if (doors.left) {
doors.left.visible = true;
}
if (doors.right) {
doors.right.visible = true;
}
}
}
// Update animatronic location function has been replaced by the AnimatronicController
// Handle power outage scenario
game.powerOutage = function powerOutage() {
if (gameOver) {
return;
}
gameOver = true;
// Turn off all lights
if (corridorLights["left"]) {
corridorLights["left"].visible = false;
}
if (corridorLights["right"]) {
corridorLights["right"].visible = false;
}
// Turn off warnings
if (warnings["left"]) {
warnings["left"].visible = false;
}
if (warnings["right"]) {
warnings["right"].visible = false;
}
// Hide camera view if active
if (isCameraActive) {
isCameraActive = false;
cameraView.visible = false;
cameraPanel.visible = false;
cameraText.setText("CAMERAS");
}
// Set screen to black
LK.effects.flashScreen(0x000000, 500, false);
// Play a sound if we have one for power outage
// Wait a random time between 2-7 seconds before jumpscare
var randomDelay = 2000 + Math.random() * 5000;
LK.setTimeout(function () {
// Make sure the blue and green cat appears for jumpscare
// Place cat in corridor
animatronicController.inCorridor = true;
animatronicController.corridorSide = Math.random() < 0.5 ? "left" : "right";
// Trigger jumpscare with the power outage flag
game.triggerJumpscare(true);
}, randomDelay);
};
// Trigger jumpscare - defined as a game method to be accessible from AnimatronicController
game.triggerJumpscare = function triggerJumpscare(isPowerOutage) {
if (gameOver && !isPowerOutage) {
return;
}
// Only check corridor condition if not a power outage
if (!isPowerOutage && !animatronicController.inCorridor) {
return;
}
gameOver = true;
// Record the time of successful attack for cooldown
animatronicController.lastAttackTime = gameTime;
LK.getSound('jumpscare').play();
// Make the blue and green cat appear in corridor before jumpscare
var corridorSide = animatronicController.corridorSide || (Math.random() < 0.5 ? "left" : "right");
// Hide cat from all cameras
for (var i = 0; i < rooms.length; i++) {
if (rooms[i]) {
rooms[i].setAnimatronic(false);
}
}
// Make cat visible in corridor
if (corridorAnimatronics[corridorSide]) {
corridorAnimatronics[corridorSide].setVisible(true);
// Force cat to be visible during jumpscare
corridorAnimatronics[corridorSide].alpha = 1;
// Turn on corridor light to make cat visible
if (corridorLights[corridorSide]) {
corridorLights[corridorSide].visible = true;
}
// Make sure the cat stays in corridor before jumpscare
animatronicController.inCorridor = true;
animatronicController.corridorSide = corridorSide;
}
// Deactivate cameras if they're active
if (isCameraActive) {
isCameraActive = false;
cameraView.visible = false;
cameraPanel.visible = false;
cameraText.setText("CAMERAS");
// Show doors when returning to office view
if (doors.left) {
doors.left.visible = true;
}
if (doors.right) {
doors.right.visible = true;
}
}
// Open both doors when jumpscared
if (doors.left && !doorLeft.isOpen) {
doorLeft.isOpen = true;
tween(doors.left, {
y: 2732 - doors.left.height / 2,
tint: 0x000000
}, {
duration: 300
});
}
if (doors.right && !doorRight.isOpen) {
doorRight.isOpen = true;
tween(doors.right, {
y: 2732 - doors.right.height / 2,
tint: 0x000000
}, {
duration: 300
});
}
// Create visible jumpscare animation with the animatronic
var jumpscare = game.addChild(new Container());
jumpscare.x = GAME_WIDTH / 2;
jumpscare.y = GAME_HEIGHT / 2;
// Add the cat animatronic to the jumpscare
var jumpscareAnimatronic = jumpscare.attachAsset('animatronic', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.0,
scaleY: 2.0
});
// Make sure the jumpscare is visible
jumpscare.visible = true;
// Add jumpscare animation
tween(jumpscare, {
scaleX: 4.5,
scaleY: 4.5,
x: GAME_WIDTH / 2 + Math.random() * 100 - 50,
// Random movement
y: GAME_HEIGHT / 2 + Math.random() * 100 - 50 // Random movement
}, {
duration: 300,
easing: tween.outQuad
});
LK.effects.flashScreen(0xff0000, 500);
LK.setTimeout(function () {
// Reset night to 1 when player dies
storage.currentNight = 1;
LK.showGameOver();
}, 1500);
};
// Handle winning the night
function winNight() {
if (gameOver) {
return;
}
gameOver = true;
// Save progress
if (currentNight >= storage.highestNight) {
storage.highestNight = currentNight + 1;
}
storage.currentNight = currentNight + 1;
// Display winning message
var winText = new Text2("You survived until 6:00 AM! Night " + currentNight + " complete!", {
size: 80,
fill: 0xFFFFFF
});
winText.anchor.set(0.5, 0.5);
winText.x = GAME_WIDTH / 2;
winText.y = GAME_HEIGHT / 2;
game.addChild(winText);
LK.setTimeout(function () {
LK.showYouWin();
}, 3000);
}
// Event handlers
game.down = function (x, y, obj) {
if (!gameStarted) {
// Start game when clicked
gameStarted = true;
instructionText.visible = false;
LK.getSound('ambience').play();
LK.playMusic('backgroundMusic');
// Open doors when first night starts
if (doors.left) {
tween(doors.left, {
y: 2732 - doors.left.height / 2,
tint: 0x000000
}, {
duration: 300
});
doorLeft.isOpen = true;
}
if (doors.right) {
tween(doors.right, {
y: 2732 - doors.right.height / 2,
tint: 0x000000
}, {
duration: 300
});
doorRight.isOpen = true;
}
return;
}
// Handle camera toggle button
if (x >= toggleCameraBtn.x - toggleCameraBtn.width / 2 && x <= toggleCameraBtn.x + toggleCameraBtn.width / 2 && y >= toggleCameraBtn.y - toggleCameraBtn.height / 2 && y <= toggleCameraBtn.y + toggleCameraBtn.height / 2) {
toggleCamera();
}
};
// Game update loop
game.update = function () {
if (!gameStarted || gameOver) {
return;
}
// Update game time
gameTime += 16.67; // Approximate milliseconds per frame at 60fps
// Update clock (6 hours from 12AM to 6AM in game duration)
var gameProgress = Math.min(gameTime / GAME_DURATION, 1);
// Check if animatronic is about to start moving based on the controller's timing
var nearInitialMove = animatronicController && !animatronicController.hasStartedMoving && LK.ticks - animatronicController.gameStartTime >= animatronicController.initialDelay - 300 && LK.ticks - animatronicController.gameStartTime < animatronicController.initialDelay;
if (nearInitialMove) {
// Force the clock to show 12:50 AM right before the first movement
hour = 12;
minute = 50;
} else {
var hour = Math.floor(gameProgress * 6);
if (hour === 0) {
hour = 12; // 12 AM
} else {
hour = hour % 12;
if (hour === 0) {
hour = 6;
} // Cap at 6 AM
}
var minute = Math.floor(gameProgress * 6 % 1 * 60);
}
var ampm = "AM"; // Always AM between 12 AM and 6 AM
clockText.setText(hour + ":" + (minute < 10 ? "0" + minute : minute) + " " + ampm);
// Win condition - survive until 6AM
if (hour === 6 && minute === 0) {
winNight();
return;
}
// Update power
var closedDoorMultiplier = 1;
// Check if doors are closed and increase power drain
if (!doorLeft.isOpen && !doorRight.isOpen) {
closedDoorMultiplier = 2; // Both doors closed - double drain
} else if (!doorLeft.isOpen || !doorRight.isOpen) {
closedDoorMultiplier = 1.5; // One door closed - 50% more drain
}
// Check if lights are on and adjust power drain accordingly
var lightMultiplier = 1;
if (lightLeft.isOn && lightRight.isOn) {
lightMultiplier = 1.5; // Both lights on - 50% more drain
} else if (lightLeft.isOn || lightRight.isOn) {
lightMultiplier = 1.2; // One light on - 20% more drain
}
// Add camera multiplier
var cameraMultiplier = isCameraActive ? 1.3 : 1; // Camera uses 30% more power when active
power -= POWER_DRAIN_RATE * powerDrain * closedDoorMultiplier * lightMultiplier * cameraMultiplier;
power = Math.max(0, power);
var powerPercent = Math.floor(power);
powerText.setText("Power: " + powerPercent + "%");
powerBarFg.width = power / MAX_POWER * powerBarBg.width;
// Game over if power runs out
if (power <= 0) {
game.powerOutage();
return;
}
// Update animatronic controller
animatronicController.update(16.67);
// Update warning lights visibility based on light button state
if (animatronicAtDoor === "left" && lightLeft.isOn) {
warningLeft.visible = true;
// Play warning sound occasionally when animatronic is spotted
if (LK.ticks % 120 === 0) {
// Approximately every 2 seconds
LK.getSound('warning').play({
volume: 0.5
});
}
} else {
warningLeft.visible = false;
}
if (animatronicAtDoor === "right" && lightRight.isOn) {
warningRight.visible = true;
// Play warning sound occasionally when animatronic is spotted
if (LK.ticks % 120 === 0) {
// Approximately every 2 seconds
LK.getSound('warning').play({
volume: 0.5
});
}
} else {
warningRight.visible = false;
}
// Visual cue when animatronic is moving between cameras
if (LK.ticks % 900 === 0 && isCameraActive) {
// Every 15 seconds during camera view
// No flashing effect
}
// Add special visual effects when player is viewing the camera that contains the animatronic
// but only for cameras other than the main entrance (camera 1)
if (isCameraActive && currentCamera === animatronicRoom && rooms[animatronicRoom - 1] && rooms[animatronicRoom - 1].hasAnimatronic && currentCamera !== 1) {
// Create occasional glitching/interference effect when looking directly at the animatronic
if (LK.ticks % 120 === 0) {
// Every 2 seconds
// Don't flash red on any camera to make them more usable
// Don't play warning sounds on any camera
}
}
};
An anthropomorphic blue and green cat animatronic wearing rockstar attire. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Metal door. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Two doorways. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
Pet store. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows