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