/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
currentNight: 1,
highestNight: 1
});
/****
* Classes
****/
var Animatronic = Container.expand(function (id, startingRoom, aggressiveness) {
var self = Container.call(this);
self.id = id;
self.currentRoom = startingRoom;
self.previousRoom = startingRoom;
self.aggressiveness = aggressiveness;
self.moveTimer = 0;
self.moveCooldown = Math.floor(600 / self.aggressiveness);
self.active = true;
var sprite = self.attachAsset('animatronic', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9
});
self.update = function () {
// Prevent animatronic from moving at 12:00 AM (gameTime < 60)
if (typeof gameTime !== "undefined" && gameTime < 60) return;
if (!self.active) return;
// Increment move timer
self.moveTimer++;
// Check if it's time to move
if (self.moveTimer >= self.moveCooldown) {
self.moveTimer = 0;
// Determine if animatronic will move based on aggressiveness
if (Math.random() * 100 < self.aggressiveness) {
self.moveToNextRoom();
}
}
};
self.moveToNextRoom = function () {
self.previousRoom = self.currentRoom;
// Instead of only adjacent rooms, allow animatronic to appear at any random room
var allRooms = Object.keys(roomMap);
// Exclude office itself as a spawn, but allow officeLeft/officeRight
var validRooms = allRooms.filter(function (room) {
return room !== 'office';
});
var targetRoom = validRooms[Math.floor(Math.random() * validRooms.length)];
self.currentRoom = targetRoom;
// If moved to office or right outside office door, check door status
if (self.currentRoom === 'officeLeft' || self.currentRoom === 'officeRight') {
// Play BearCame sound when animatronic comes to the door
LK.getSound('BearCame').play();
var doorSide = self.currentRoom === 'officeLeft' ? 'left' : 'right';
if (!doors[doorSide].closed) {
// Jumpscare if door is open!
triggerJumpscare(self.id);
}
}
// Notify that an animatronic moved for camera updates
animatronicMoved = true;
};
self.render = function (cameraElement) {
// Position the animatronic in the correct spot based on the camera view
if (self.currentRoom === currentCamera) {
sprite.alpha = 1;
// Position differently based on the room
var roomPosition = cameraPositions[self.currentRoom];
if (roomPosition) {
sprite.x = roomPosition.x;
sprite.y = roomPosition.y;
// Add to the camera feed
cameraElement.addChild(sprite);
}
}
};
return self;
});
var Door = Container.expand(function (side) {
var self = Container.call(this);
self.side = side; // 'left' or 'right'
self.closed = false;
var doorGraphic = self.attachAsset('door', {
anchorX: 0.5,
anchorY: 0.5
});
var doorButton = self.attachAsset('doorButton', {
anchorX: 0.5,
anchorY: 0.5,
y: -250
});
var buttonLabel = new Text2("DOOR", {
size: 20,
fill: 0xFFFFFF
});
buttonLabel.anchor.set(0.5, 0.5);
doorButton.addChild(buttonLabel);
// Door starts open (hidden)
doorGraphic.alpha = 0;
self.toggleDoor = function () {
// Only allow door mechanics in easy mode
if (typeof selectedDifficulty === "undefined" || selectedDifficulty === "easy") {
self.closed = !self.closed;
if (self.closed) {
// Close door
doorGraphic.alpha = 1;
LK.getSound('doorClose').play();
buttonLabel.setText("OPEN");
doorButton.tint = 0xff0000;
// Use power
increasePowerUsage();
// If animatronic is attacking at this door, cancel attack and make animatronic leave
if (typeof animatronicAttacking !== "undefined" && animatronicAttacking[self.side]) {
animatronicAttacking[self.side] = false;
if (typeof animatronicAttackTimeouts !== "undefined" && animatronicAttackTimeouts[self.side]) {
LK.clearTimeout(animatronicAttackTimeouts[self.side]);
animatronicAttackTimeouts[self.side] = null;
}
}
// Make animatronic leave: move to a random non-office room if any animatronic is at the door (regardless of attack state)
for (var i = 0; i < animatronics.length; i++) {
var dangerRoom = self.side === 'left' ? 'officeLeft' : 'officeRight';
if (animatronics[i].currentRoom === dangerRoom) {
// Pick a random non-office room
var allRooms = Object.keys(roomMap).filter(function (room) {
return room !== 'office' && room !== 'officeLeft' && room !== 'officeRight';
});
var newRoom = allRooms[Math.floor(Math.random() * allRooms.length)];
animatronics[i].currentRoom = newRoom;
animatronicMoved = true;
}
}
} else {
// Open door
doorGraphic.alpha = 0;
LK.getSound('doorOpen').play();
buttonLabel.setText("DOOR");
doorButton.tint = 0x008000;
// Save power
decreasePowerUsage();
// Check if any animatronics are waiting outside
for (var i = 0; i < animatronics.length; i++) {
var dangerRoom = self.side === 'left' ? 'officeLeft' : 'officeRight';
if (animatronics[i].currentRoom === dangerRoom) {
// Jumpscare!
triggerJumpscare(animatronics[i].id);
return;
}
}
}
}
};
doorButton.down = function () {
self.toggleDoor();
};
return self;
});
var PowerSystem = Container.expand(function () {
var self = Container.call(this);
self.powerLevel = 100;
self.powerUsage = 1; // Base level (always uses some power)
self.drainTimer = 0;
var powerBarBg = self.attachAsset('powerBarBg', {
anchorX: 0,
anchorY: 0.5
});
var powerBar = self.attachAsset('powerBar', {
anchorX: 0,
anchorY: 0.5,
width: 400 // Start at full width
});
var powerLabel = new Text2("POWER: 100%", {
size: 30,
fill: 0xFFFFFF
});
powerLabel.anchor.set(0, 0.5);
powerLabel.x = 420;
self.addChild(powerLabel);
var usageLabel = new Text2("USAGE: ▮", {
size: 30,
fill: 0xFFFFFF
});
usageLabel.anchor.set(0, 0.5);
usageLabel.y = 40;
usageLabel.visible = true;
self.addChild(usageLabel);
// Track if usage rectangle should be shown
self.usageRectVisible = true;
self.update = function () {
// --- EASY MODE: Usage always 0 unless camera is open or a door is closed ---
if (typeof selectedDifficulty === "undefined" || selectedDifficulty === "easy") {
// Check if camera is open or any door is closed
var cameraOpen = typeof cameraSystemActive !== "undefined" && cameraSystemActive;
var leftClosed = typeof doors !== "undefined" && doors.left && doors.left.closed;
var rightClosed = typeof doors !== "undefined" && doors.right && doors.right.closed;
if (!cameraOpen && !leftClosed && !rightClosed) {
// Hide usage rectangle (▮) but keep "USAGE:" text
self.usageRectVisible = false;
self.powerUsage = 1;
self.updateUsageDisplay && self.updateUsageDisplay();
// Prevent power from decreasing at all in easy mode unless camera is open or a door is closed
return;
} else {
// Show only one rectangle (▮) if camera is open or only one door is closed
var count = 0;
if (cameraOpen) count++;
if (leftClosed) count++;
if (rightClosed) count++;
// Only show one rectangle if exactly one of these is true
if (count === 1) {
self.usageRectVisible = true;
self.powerUsage = 1;
} else if (count > 1) {
// If more than one (e.g. camera and a door, or both doors), show more rectangles as normal
self.usageRectVisible = true;
self.powerUsage = count;
}
self.updateUsageDisplay && self.updateUsageDisplay();
}
}
// Drain power based on usage level and game difficulty
self.drainTimer++;
// Drain every X frames based on current night (higher nights drain faster)
// Hard mode: power drains faster
var drainRate;
if (typeof selectedDifficulty === "undefined" || selectedDifficulty === "easy") {
drainRate = Math.max(15 - currentNight * 2, 5);
} else {
drainRate = Math.max(10 - currentNight * 3, 3);
}
if (self.drainTimer >= drainRate) {
self.drainTimer = 0;
self.powerLevel -= self.powerUsage * 0.1;
// Update power bar width
powerBar.width = 400 * (self.powerLevel / 100);
// Update label
powerLabel.setText("POWER: " + Math.floor(self.powerLevel) + "%");
// Change color as power decreases
if (self.powerLevel <= 20) {
powerBar.tint = 0xff0000; // Red when low
// Warning sounds when power is very low
if (self.powerLevel <= 10 && self.drainTimer % 5 === 0) {
LK.getSound('warning').play();
}
} else if (self.powerLevel <= 50) {
powerBar.tint = 0xffff00; // Yellow when medium
}
// Check for power out
if (self.powerLevel <= 0) {
powerOut();
}
}
};
self.updateUsageDisplay = function () {
var usageText = "USAGE:";
if (self.usageRectVisible) {
usageText += " ";
for (var i = 0; i < self.powerUsage; i++) {
usageText += "▮";
}
}
usageLabel.setText(usageText);
};
return self;
});
var SecurityCamera = Container.expand(function (roomId, x, y) {
var self = Container.call(this);
self.roomId = roomId;
self.x = x;
self.y = y;
self.isActive = false;
// Use a unique camera feed image for each room
var camFeedAssetId = 'camFeed_' + roomId;
var cameraFeed = self.attachAsset(camFeedAssetId, {
anchorX: 0.5,
anchorY: 0.5,
width: 120,
height: 112.5
});
var roomLabel = new Text2(roomId.toUpperCase(), {
size: 24,
fill: 0xFF0000
});
roomLabel.anchor.set(0.5, 0);
roomLabel.y = -cameraFeed.height / 2 - 30;
self.addChild(roomLabel);
var staticOverlay = self.attachAsset('staticOverlay', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3,
width: 120,
height: 80
});
self.activate = function () {
self.isActive = true;
LK.getSound('camSwitch').play();
// Increase static effect briefly
tween(staticOverlay, {
alpha: 0.7
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(staticOverlay, {
alpha: 0.3
}, {
duration: 300,
easing: tween.easeIn
});
}
});
// Always clear and re-add animatronics to prevent black feed
self.updateAnimatronics();
};
self.deactivate = function () {
self.isActive = false;
// Clear any animatronics from view
while (cameraFeed.children.length > 0) {
cameraFeed.removeChild(cameraFeed.children[0]);
}
// Also reset static overlay to default alpha
staticOverlay.alpha = 0.3;
};
self.updateAnimatronics = function () {
// Clear previous animatronics
while (cameraFeed.children.length > 0) {
cameraFeed.removeChild(cameraFeed.children[0]);
}
// Add animatronics that are in this room
for (var i = 0; i < animatronics.length; i++) {
// --- EASY MODE: Always show animatronic at the door and play BearCame sound ---
if ((typeof selectedDifficulty === "undefined" || selectedDifficulty === "easy") && (self.roomId === 'officeLeft' || self.roomId === 'officeRight')) {
// Force animatronic to be at the door in easy mode
animatronics[i].currentRoom = self.roomId;
animatronics[i].render(cameraFeed);
// Play BearCame sound every time camera is refreshed (safe, as it's a short sound)
LK.getSound('BearCame').play();
// No waitTimer logic needed in easy mode
continue;
}
// --- Normal logic for other rooms or hard mode ---
if (animatronics[i].currentRoom === self.roomId && self.isActive) {
animatronics[i].render(cameraFeed);
// --- BearCame sound logic for animatronic waiting in officeLeft/officeRight ---
// Only for officeLeft or officeRight, and only if animatronic has been there for 5 seconds
if (self.roomId === 'officeLeft' || self.roomId === 'officeRight') {
if (!animatronics[i].waitTimer) animatronics[i].waitTimer = 0;
// Play BearCame sound immediately when animatronic starts waiting in front of office
if (animatronics[i].waitTimer === 0) {
LK.getSound('BearCame').play();
}
animatronics[i].waitTimer++;
// 5 seconds = 5*60 = 300 frames
if (animatronics[i].waitTimer === 300) {
// (No need to play BearCame here anymore, already played at waitTimer === 0)
}
} else {
// Reset waitTimer if not in front of office
animatronics[i].waitTimer = 0;
}
} else if (animatronics[i].currentRoom === self.roomId) {
// Not active camera, but still reset waitTimer if not in officeLeft/officeRight
if (self.roomId !== 'officeLeft' && self.roomId !== 'officeRight') {
animatronics[i].waitTimer = 0;
}
}
}
};
self.down = function () {
// When this camera is clicked, make it the active camera
if (cameraSystemActive && self.roomId !== currentCamera) {
switchCamera(self.roomId);
}
};
return self;
});
var SecurityMonitor = Container.expand(function () {
var self = Container.call(this);
var monitorBg = self.attachAsset('securityMonitor', {
anchorX: 0.5,
anchorY: 0.5
});
var mapContainer = new Container();
// Center the map in the monitor background
mapContainer.x = -monitorBg.width / 2 + 200;
mapContainer.y = -monitorBg.height / 2 + 100;
self.addChild(mapContainer);
var cameraViewContainer = new Container();
cameraViewContainer.x = 200;
cameraViewContainer.y = 0;
self.addChild(cameraViewContainer);
var activeCamera = null;
var cameraLabel = new Text2("CAMERA: NONE", {
size: 40,
fill: 0xFF0000
});
cameraLabel.anchor.set(0.5, 0);
cameraLabel.x = 200;
cameraLabel.y = -monitorBg.height / 2 + 50;
self.addChild(cameraLabel);
var closeButton = self.attachAsset('closeCameraButton', {
anchorX: 0.5,
anchorY: 0.5,
x: monitorBg.width / 2 - 50,
y: -monitorBg.height / 2 + 50
});
var closeLabel = new Text2("X", {
size: 40,
fill: 0xFFFFFF
});
closeLabel.anchor.set(0.5, 0.5);
closeButton.addChild(closeLabel);
closeButton.down = function () {
toggleCameraSystem();
};
self.setup = function () {
// Optionally: Draw lines or dots to visually separate rooms (spacer lines)
// We'll use simple rectangles as spacers between clusters of rooms
// (This is a visual aid, not interactive)
var roomGroups = [['stage', 'kitchen', 'diningArea', 'laundry', 'storage'], ['arcade', 'partyRoom', 'backstage', 'restroom'], ['westHall', 'westCorner', 'officeLeft'], ['eastHall', 'eastCorner', 'officeRight']];
// Draw spacers between groups
for (var g = 1; g < roomGroups.length; g++) {
var prevGroup = roomGroups[g - 1];
var currGroup = roomGroups[g];
// Find center of last room in prev group and first room in curr group
var prevRoom = prevGroup[prevGroup.length - 1];
var currRoom = currGroup[0];
var prevPos = mapPositions[prevRoom];
var currPos = mapPositions[currRoom];
if (prevPos && currPos) {
var spacer = new Container();
var line = spacer.attachAsset('powerBarBg', {
anchorX: 0,
anchorY: 0.5,
width: Math.abs(currPos.x - prevPos.x),
height: 10,
tint: 0x222222,
alpha: 0.5
});
spacer.x = Math.min(prevPos.x, currPos.x);
spacer.y = (prevPos.y + currPos.y) / 2;
mapContainer.addChild(spacer);
}
}
// Create cameras for each room
for (var room in cameraPositions) {
var pos = mapPositions[room] || {
x: 0,
y: 0
};
var camera = new SecurityCamera(room, pos.x, pos.y);
mapContainer.addChild(camera);
cameras[room] = camera;
}
// Set initial camera to show
self.switchCamera('stage');
};
self.switchCamera = function (roomId) {
// Deactivate current camera
if (activeCamera) {
activeCamera.deactivate();
}
// Activate new camera
activeCamera = cameras[roomId];
if (activeCamera) {
activeCamera.activate();
currentCamera = roomId;
cameraLabel.setText("CAMERA: " + roomId.toUpperCase());
}
};
self.updateCameras = function () {
if (activeCamera) {
activeCamera.updateAnimatronics();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Unique assets for UI (not doorButton)
// Game constants and settings
var currentNight = storage.currentNight || 1;
var gameTime = 0; // in seconds
var nightDuration = 360; // 6 minutes per night
var cameraSystemActive = false;
var currentCamera = 'stage';
var animatronicMoved = false;
var gameOver = false;
var powerOutTriggered = false;
// Room layout definitions
var roomMap = {
'stage': ['diningArea'],
'diningArea': ['stage', 'westHall', 'eastHall', 'kitchen', 'arcade', 'partyRoom', 'laundry', 'backstage'],
'westHall': ['diningArea', 'westCorner', 'officeLeft', 'storage', 'laundry'],
'eastHall': ['diningArea', 'eastCorner', 'officeRight', 'arcade'],
'westCorner': ['westHall', 'officeLeft'],
'eastCorner': ['eastHall', 'officeRight'],
'kitchen': ['diningArea', 'storage', 'laundry'],
'arcade': ['diningArea', 'eastHall', 'partyRoom'],
'partyRoom': ['diningArea', 'arcade', 'storage', 'backstage'],
'storage': ['westHall', 'kitchen', 'partyRoom', 'laundry'],
'laundry': ['storage', 'kitchen', 'westHall', 'diningArea'],
'backstage': ['partyRoom', 'diningArea'],
// 'restroom' removed
'officeLeft': ['westCorner', 'office'],
'officeRight': ['eastCorner', 'office'],
'office': ['officeLeft', 'officeRight']
};
// Distance from each room to the office (for AI pathfinding)
var roomDistanceToOffice = {
'office': 0,
'officeLeft': 1,
'officeRight': 1,
'westCorner': 2,
'eastCorner': 2,
'westHall': 3,
'eastHall': 3,
'diningArea': 4,
'kitchen': 5,
'arcade': 5,
'partyRoom': 5,
'storage': 6,
'laundry': 6,
'backstage': 6,
'stage': 6
};
// Camera positions on the map (expanded area, problematic rooms adjusted/removed)
var mapPositions = {
'stage': {
x: 200,
y: 200
},
'diningArea': {
x: 500,
y: 200
},
'kitchen': {
x: 800,
y: 200
},
'laundry': {
x: 1100,
y: 200
},
'storage': {
x: 200,
y: 500
},
'partyRoom': {
x: 500,
y: 500
},
'arcade': {
x: 800,
y: 500
},
'backstage': {
x: 1100,
y: 500
},
// 'restroom' removed for clarity and space (no camera will be created for restroom)
'westHall': {
x: 200,
y: 800
},
// 'eastHall', 'eastCorner', and 'officeRight' removed from mapPositions to prevent their camera creation
'westCorner': {
x: 200,
y: 1100
},
'officeLeft': {
x: 200,
y: 1400
}
};
// Camera positions for rendering animatronics
var cameraPositions = {
'stage': {
x: 0,
y: 0
},
'diningArea': {
x: 50,
y: 0
},
'westHall': {
x: -50,
y: 0
},
// 'eastHall', 'eastCorner', and 'officeRight' removed from cameraPositions to prevent animatronic rendering in those rooms
'westCorner': {
x: -80,
y: 20
},
'kitchen': {
x: 0,
y: -30
},
'arcade': {
x: 60,
y: -20
},
'partyRoom': {
x: 0,
y: 40
},
'storage': {
x: -60,
y: -40
},
'laundry': {
x: -30,
y: -60
},
'backstage': {
x: 100,
y: -50
},
// (restroom removed to prevent out-of-bounds camera)
'officeLeft': {
x: -100,
y: 0
}
};
// Initialize game objects
var securityMonitor = new SecurityMonitor();
var powerSystem = new PowerSystem();
var doors = {
'left': new Door('left'),
'right': new Door('right')
};
var cameras = {};
var animatronics = [];
var clockDisplay, nightDisplay, cameraToggleBtn;
// Initialize office background as a single image covering the whole office
var officeFull = LK.getAsset('officeFull', {
anchorX: 0.5,
anchorY: 0,
x: 2048 / 2,
y: 1200
});
game.addChild(officeFull);
// Position and add doors on top of the officeFull image
doors.left.x = 800; // moved further to the right from 700 to 800
doors.left.y = 1200 + 400;
doors.right.x = 1748; // 2048 - 300
doors.right.y = 1200 + 400;
game.addChild(doors.left);
game.addChild(doors.right);
// Add security monitor (initially hidden)
securityMonitor.visible = false;
securityMonitor.y = 1300;
game.addChild(securityMonitor);
// Camera navigation buttons
var cameraRoomOrder = ['stage', 'diningArea', 'kitchen', 'laundry', 'storage', 'partyRoom', 'arcade', 'backstage', 'westHall', 'westCorner', 'officeLeft'];
// easthall, eastcorner, and officeRight removed from cameraRoomOrder to delete their cameras
function getCurrentCameraIndex() {
for (var i = 0; i < cameraRoomOrder.length; i++) {
if (cameraRoomOrder[i] === currentCamera) return i;
}
return 0;
}
// Set up camera button
cameraToggleBtn = LK.getAsset('cameraButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2200
});
game.addChild(cameraToggleBtn);
var cameraLabel = new Text2("CAMERAS", {
size: 30,
fill: 0xFFFFFF
});
cameraLabel.anchor.set(0.5, 0.5);
cameraToggleBtn.addChild(cameraLabel);
// Set up power display
powerSystem.x = 150;
powerSystem.y = 150;
LK.gui.topLeft.addChild(powerSystem);
// Set up clock
clockDisplay = new Text2("12:00 AM", {
size: 60,
fill: 0xFFFFFF
});
clockDisplay.anchor.set(0.5, 0);
LK.gui.top.addChild(clockDisplay);
// --- Fullscreen Button ---
// Place at top right, but not overlapping nightDisplay (which is x = -150 from right edge)
var fullscreenBtn = LK.getAsset('fullscreenButton', {
anchorX: 0.5,
anchorY: 0.5,
x: -300,
// further left from nightDisplay
y: 80,
width: 120,
height: 120,
alpha: 0.8
});
LK.gui.topRight.addChild(fullscreenBtn);
var fullscreenLabel = new Text2("⛶", {
size: 60,
fill: 0xffffff
});
fullscreenLabel.anchor.set(0.5, 0.5);
fullscreenBtn.addChild(fullscreenLabel);
// Only show if not already fullscreen
fullscreenBtn.visible = !LK.isFullscreen || !LK.isFullscreen();
// Handler to enter fullscreen
fullscreenBtn.down = function () {
if (LK.requestFullscreen) {
LK.requestFullscreen();
}
// Optionally hide the button after entering fullscreen
fullscreenBtn.visible = false;
};
// Set up night display
nightDisplay = new Text2("NIGHT " + currentNight, {
size: 60,
fill: 0xFFFFFF
});
nightDisplay.anchor.set(1, 0);
nightDisplay.x = -150;
LK.gui.topRight.addChild(nightDisplay);
// Night overlay for transitions
var nightOverlay = LK.getAsset('nightOverlay', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 1
});
nightOverlay.visible = false; // Always keep overlay hidden
game.addChild(nightOverlay);
// Initialize animatronics based on current night
function setupAnimatronics() {
animatronics = [];
// Clear any existing animatronics
for (var i = 0; i < animatronics.length; i++) {
if (animatronics[i].parent) {
animatronics[i].parent.removeChild(animatronics[i]);
}
}
// All animatronics start on the stage (except Foxy)
// Difficulty affects aggressiveness
var baseAggressiveness;
if (typeof selectedDifficulty === "undefined" || selectedDifficulty === "easy") {
baseAggressiveness = 5 + currentNight * 5;
} else {
baseAggressiveness = 15 + currentNight * 8;
}
// Define animatronic turn order (farthest to closest)
var animatronicOrder = [];
animatronicOrder.push({
id: 'freddy',
start: 'stage',
aggr: baseAggressiveness
});
if (currentNight >= 2) {
animatronicOrder.push({
id: 'bonnie',
start: 'stage',
aggr: baseAggressiveness + 5
});
}
if (currentNight >= 3) {
animatronicOrder.push({
id: 'chica',
start: 'stage',
aggr: baseAggressiveness + 2
});
}
if (currentNight >= 4) {
animatronicOrder.push({
id: 'foxy',
start: 'westHall',
aggr: baseAggressiveness + 10
});
}
// Create animatronics in order
for (var i = 0; i < animatronicOrder.length; i++) {
var a = animatronicOrder[i];
animatronics.push(new Animatronic(a.id, a.start, a.aggr));
}
// Track whose turn it is to move
animatronicTurnIndex = 0;
}
// Function to start a new night
function startNight() {
// Reset game state
gameTime = 0;
cameraSystemActive = false;
currentCamera = 'stage';
animatronicMoved = false;
gameOver = false;
powerOutTriggered = false;
// Difficulty is already set by menu, nothing to do here
// Reset doors
doors.left.closed = false;
doors.right.closed = false;
doors.left.toggleDoor();
doors.left.toggleDoor();
doors.right.toggleDoor();
doors.right.toggleDoor();
// Reset power
powerSystem.powerLevel = 100;
powerSystem.powerUsage = 1;
powerSystem.updateUsageDisplay();
// Setup security cameras
securityMonitor.setup();
// Setup animatronics
setupAnimatronics();
// Update display
nightDisplay.setText("NIGHT " + currentNight);
// Fade in
tween(nightOverlay, {
alpha: 0
}, {
duration: 2000,
easing: tween.easeIn
});
// Play ambient sounds
LK.playMusic('ambientMusic', {
loop: true
});
LK.getSound('ambient').play();
}
// Function to toggle camera system
function toggleCameraSystem() {
cameraSystemActive = !cameraSystemActive;
if (cameraSystemActive) {
// Show camera system
securityMonitor.visible = true;
cameraToggleBtn.tint = 0xff0000;
// Use more power
increasePowerUsage();
// Play sound
LK.getSound('camSwitch').play();
} else {
// Hide camera system
securityMonitor.visible = false;
cameraToggleBtn.tint = 0x990000;
// Use less power
decreasePowerUsage();
// Play sound
LK.getSound('camSwitch').play();
}
}
// Function to switch camera views
function switchCamera(roomId) {
// Always allow switching to any valid camera, including the first one
if (cameras[roomId]) {
// Deactivate all cameras first to prevent multiple active states
for (var camKey in cameras) {
if (cameras.hasOwnProperty(camKey)) {
cameras[camKey].deactivate();
}
}
securityMonitor.switchCamera(roomId);
currentCamera = roomId;
// Play sound
LK.getSound('camSwitch').play();
}
}
// Function to increase power usage
function increasePowerUsage() {
powerSystem.powerUsage++;
powerSystem.updateUsageDisplay();
}
// Function to decrease power usage
function decreasePowerUsage() {
if (powerSystem.powerUsage > 1) {
powerSystem.powerUsage--;
powerSystem.updateUsageDisplay();
}
}
// Function to handle power outage
function powerOut() {
if (powerOutTriggered) return;
powerOutTriggered = true;
// Turn off all systems
securityMonitor.visible = false;
cameraSystemActive = false;
// Open all doors
if (doors.left.closed) doors.left.toggleDoor();
if (doors.right.closed) doors.right.toggleDoor();
// Play power down sound
LK.getSound('powerDown').play();
// Game over with slight delay (for tension)
LK.setTimeout(function () {
triggerJumpscare('freddy');
}, 5000);
}
// Function to trigger jumpscare
function triggerJumpscare(animatronicId) {
if (gameOver) return;
gameOver = true;
// Play jumpscare sound
LK.getSound('jumpscare').play();
// Flash screen red
LK.effects.flashScreen(0xff0000, 500);
// --- Jumpscare image and animation ---
var jumpscareImg = LK.getAsset('animatronic', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
width: 1200,
height: 1200,
alpha: 0
});
game.addChild(jumpscareImg);
// Terrifying GAME OVER text
var gameOverText = new Text2("GAME OVER", {
size: 200,
fill: 0xff0000,
font: "Impact, 'Arial Black', Tahoma"
});
gameOverText.anchor.set(0.5, 0.5);
gameOverText.x = 2048 / 2;
gameOverText.y = 2732 / 2 + 500;
gameOverText.alpha = 0;
game.addChild(gameOverText);
// Animate: fade in and scale up for a terrifying effect
jumpscareImg.scaleX = 1;
jumpscareImg.scaleY = 1;
tween(jumpscareImg, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 350,
easing: tween.easeIn,
onFinish: function onFinish() {
// Hold for a moment, then fade in GAME OVER text and fade out jumpscare
tween(gameOverText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
// Fade out jumpscare image, keep GAME OVER text for a bit
tween(jumpscareImg, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
if (jumpscareImg.parent) jumpscareImg.parent.removeChild(jumpscareImg);
// Hold GAME OVER text, then fade out and show LK game over
tween(gameOverText, {
alpha: 0
}, {
duration: 800,
delay: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
if (gameOverText.parent) gameOverText.parent.removeChild(gameOverText);
LK.showGameOver();
}
});
}
});
}
});
}
});
}
// Function to complete the night successfully
function completeNight() {
// Update stored progress
if (currentNight >= storage.highestNight) {
storage.highestNight = currentNight + 1;
}
currentNight++;
storage.currentNight = currentNight;
// Show win screen
LK.showYouWin();
}
// Events for camera toggle button
cameraToggleBtn.down = function () {
toggleCameraSystem();
};
// Update game time and clock display
function updateClock() {
var hour = Math.floor(gameTime / 60) + 12;
if (hour > 12) hour -= 12;
var timeString = hour + ":00 AM";
clockDisplay.setText(timeString);
// Check if night is complete
if (gameTime >= nightDuration) {
completeNight();
}
}
// Main game update function
game.update = function () {
if (nightOverlay.alpha > 0) return; // Don't update while fading in
// Update game time (every half second, so time passes 2x faster)
if (LK.ticks % 30 === 0) {
gameTime++;
updateClock();
}
// Update power system
powerSystem.update();
// Animatronics take turns moving, from farthest to closest (one per update cycle)
if (typeof animatronicTurnIndex === "undefined") {
animatronicTurnIndex = 0;
}
if (animatronics.length > 0) {
// Only one animatronic moves per update
animatronics[animatronicTurnIndex].update();
animatronicTurnIndex++;
if (animatronicTurnIndex >= animatronics.length) {
animatronicTurnIndex = 0;
}
}
// Update camera feed if an animatronic moved
if (animatronicMoved) {
animatronicMoved = false;
securityMonitor.updateCameras();
}
};
// --- Main Menu Overlay ---
var mainMenuOverlay = new Container();
mainMenuOverlay.x = 0;
mainMenuOverlay.y = 0;
mainMenuOverlay.width = 2048;
mainMenuOverlay.height = 2732;
mainMenuOverlay.visible = true;
// Dimmed background
var menuBg = mainMenuOverlay.attachAsset('nightOverlay', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732,
alpha: 0.85
});
mainMenuOverlay.addChild(menuBg);
// Game Title
var titleText = new Text2("FNAF FRVR", {
size: 180,
fill: 0xffcc00,
font: "Impact, 'Arial Black', Tahoma"
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 700;
mainMenuOverlay.addChild(titleText);
// --- Difficulty Buttons (only on main menu) ---
var selectedDifficulty = "easy";
var easyBtn = LK.getAsset('easyButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 - 250,
y: 1050,
width: 300,
height: 120,
alpha: 0.95
});
mainMenuOverlay.addChild(easyBtn);
var easyLabel = new Text2("EASY", {
size: 60,
fill: 0xffffff,
font: "Impact, 'Arial Black', Tahoma"
});
easyLabel.anchor.set(0.5, 0.5);
easyBtn.addChild(easyLabel);
var hardBtn = LK.getAsset('hardButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 + 250,
y: 1050,
width: 300,
height: 120,
alpha: 0.95
});
mainMenuOverlay.addChild(hardBtn);
var hardLabel = new Text2("HARD", {
size: 60,
fill: 0xffffff,
font: "Impact, 'Arial Black', Tahoma"
});
hardLabel.anchor.set(0.5, 0.5);
hardBtn.addChild(hardLabel);
function updateDifficultyButtons() {
if (selectedDifficulty === "easy") {
easyBtn.tint = 0x00ff00;
hardBtn.tint = 0xcc0000;
} else {
easyBtn.tint = 0x00cc00;
hardBtn.tint = 0xff2222;
}
}
easyBtn.down = function () {
selectedDifficulty = "easy";
updateDifficultyButtons();
};
hardBtn.down = function () {
selectedDifficulty = "hard";
updateDifficultyButtons();
};
updateDifficultyButtons();
// Start Button
var startBtn = LK.getAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1200,
width: 400,
height: 200,
alpha: 0.95
});
mainMenuOverlay.addChild(startBtn);
var startLabel = new Text2("START", {
size: 90,
fill: 0xffffff,
font: "Impact, 'Arial Black', Tahoma"
});
startLabel.anchor.set(0.5, 0.5);
startBtn.addChild(startLabel);
// Optionally: Instructions
var instrText = new Text2("Kapılardan hayatta kal!\nKameraları kullan, kapıları kapat, gücünü idare et.", {
size: 48,
fill: 0xffffff,
font: "Tahoma"
});
instrText.anchor.set(0.5, 0);
instrText.x = 2048 / 2;
instrText.y = 1450;
mainMenuOverlay.addChild(instrText);
// Add overlay to game
game.addChild(mainMenuOverlay);
// Disable all game UI until menu is dismissed
function showMainMenu() {
mainMenuOverlay.visible = true;
// Hide night overlay in main menu
if (typeof nightOverlay !== "undefined" && nightOverlay) nightOverlay.visible = false;
// Reset difficulty to easy by default
selectedDifficulty = "easy";
if (typeof updateDifficultyButtons === "function") updateDifficultyButtons();
// Optionally hide other UI
securityMonitor.visible = false;
cameraToggleBtn.visible = false;
powerSystem.visible = false;
clockDisplay.visible = false;
nightDisplay.visible = false;
fullscreenBtn.visible = false;
if (typeof leftArrow !== "undefined" && leftArrow) leftArrow.visible = false;
if (typeof rightArrow !== "undefined" && rightArrow) rightArrow.visible = false;
if (typeof upArrow !== "undefined" && upArrow) upArrow.visible = false;
if (typeof downArrow !== "undefined" && downArrow) downArrow.visible = false;
if (typeof playerDot !== "undefined" && playerDot) playerDot.visible = false;
if (typeof officeFull !== "undefined" && officeFull) officeFull.visible = false;
if (typeof doors !== "undefined" && doors.left) doors.left.visible = false;
if (typeof doors !== "undefined" && doors.right) doors.right.visible = false;
// Make absolutely sure nightOverlay is hidden in main menu
if (typeof nightOverlay !== "undefined" && nightOverlay) nightOverlay.visible = false;
}
function hideMainMenu() {
mainMenuOverlay.visible = false;
// Do not show night overlay when game starts
if (typeof nightOverlay !== "undefined" && nightOverlay) nightOverlay.visible = false;
// Show UI
securityMonitor.visible = false;
cameraToggleBtn.visible = true;
powerSystem.visible = true;
clockDisplay.visible = true;
nightDisplay.visible = true;
fullscreenBtn.visible = !LK.isFullscreen || !LK.isFullscreen();
if (typeof leftArrow !== "undefined" && leftArrow) leftArrow.visible = true;
if (typeof rightArrow !== "undefined" && rightArrow) rightArrow.visible = true;
if (typeof upArrow !== "undefined" && upArrow) upArrow.visible = true;
if (typeof downArrow !== "undefined" && downArrow) downArrow.visible = true;
if (typeof playerDot !== "undefined" && playerDot) playerDot.visible = true;
if (typeof officeFull !== "undefined" && officeFull) officeFull.visible = true;
if (typeof doors !== "undefined" && doors.left) doors.left.visible = true;
if (typeof doors !== "undefined" && doors.right) doors.right.visible = true;
// Make absolutely sure nightOverlay is visible when game starts
if (typeof nightOverlay !== "undefined" && nightOverlay) nightOverlay.visible = true;
}
// Start game when start button is pressed
startBtn.down = function () {
hideMainMenu();
startNight();
};
// Show menu at launch
showMainMenu();
;
// --- On-screen Arrow Keys for Player Movement ---
// Arrow key asset sizes and positions
var arrowSize = 180;
var arrowAlpha = 0.7;
var arrowY = 2732 - 250;
var arrowXCenter = 2048 / 2;
var arrowSpacing = 220;
// Create arrow containers
var leftArrow = new Container();
var rightArrow = new Container();
var upArrow = new Container();
var downArrow = new Container();
// Add arrow graphics
var leftArrowGraphic = leftArrow.attachAsset('arrowLeft', {
anchorX: 0.5,
anchorY: 0.5,
width: arrowSize,
height: arrowSize,
alpha: arrowAlpha
});
var rightArrowGraphic = rightArrow.attachAsset('arrowRight', {
anchorX: 0.5,
anchorY: 0.5,
width: arrowSize,
height: arrowSize,
alpha: arrowAlpha
});
var upArrowGraphic = upArrow.attachAsset('arrowUp', {
anchorX: 0.5,
anchorY: 0.5,
width: arrowSize,
height: arrowSize,
alpha: arrowAlpha
});
var downArrowGraphic = downArrow.attachAsset('arrowDown', {
anchorX: 0.5,
anchorY: 0.5,
width: arrowSize,
height: arrowSize,
alpha: arrowAlpha
});
// Add arrow labels
var leftLabel = new Text2("◀", {
size: 100,
fill: 0xFFFFFF
});
leftLabel.anchor.set(0.5, 0.5);
leftArrow.addChild(leftLabel);
var rightLabel = new Text2("▶", {
size: 100,
fill: 0xFFFFFF
});
rightLabel.anchor.set(0.5, 0.5);
rightArrow.addChild(rightLabel);
var upLabel = new Text2("▲", {
size: 100,
fill: 0xFFFFFF
});
upLabel.anchor.set(0.5, 0.5);
upArrow.addChild(upLabel);
var downLabel = new Text2("▼", {
size: 100,
fill: 0xFFFFFF
});
downLabel.anchor.set(0.5, 0.5);
downArrow.addChild(downLabel);
// Position arrows (bottom center, spaced out)
leftArrow.x = arrowXCenter - arrowSpacing;
leftArrow.y = arrowY;
rightArrow.x = arrowXCenter + arrowSpacing;
rightArrow.y = arrowY;
upArrow.x = arrowXCenter;
upArrow.y = arrowY - arrowSpacing;
downArrow.x = arrowXCenter;
downArrow.y = arrowY + arrowSpacing / 1.5;
// Add to game
game.addChild(leftArrow);
game.addChild(rightArrow);
game.addChild(upArrow);
game.addChild(downArrow);
// Hide arrows initially (main menu is visible at start)
leftArrow.visible = false;
rightArrow.visible = false;
upArrow.visible = false;
downArrow.visible = false;
// --- Player movement logic ---
// Define player position in the office (for demo, just a dot in the office)
if (typeof playerPos === "undefined") {
var playerPos = {
x: 2048 / 2,
y: 1800
};
}
if (typeof playerDot === "undefined") {
var playerDot = new Container();
var characterGraphic = playerDot.attachAsset('playerCharacter', {
anchorX: 0.5,
anchorY: 0.5,
width: 120,
height: 120,
alpha: 1
});
playerDot.x = playerPos.x;
playerDot.y = playerPos.y;
game.addChild(playerDot);
}
// Movement boundaries (keep player in office area)
var minX = 300 + 80,
maxX = 1748 - 80;
var minY = 1200 + 80,
maxY = 1200 + 600 - 80;
// Move player and update dot position
function movePlayer(dx, dy) {
// Only allow mechanics if easy mode is selected
if (typeof selectedDifficulty === "undefined" || selectedDifficulty === "easy") {
playerPos.x += dx;
playerPos.y += dy;
// Clamp to bounds
if (playerPos.x < minX) playerPos.x = minX;
if (playerPos.x > maxX) playerPos.x = maxX;
if (playerPos.y < minY) playerPos.y = minY;
if (playerPos.y > maxY) playerPos.y = maxY;
playerDot.x = playerPos.x;
playerDot.y = playerPos.y;
// --- Animatronic comes to the door when player arrives ---
// Define door trigger areas (left and right)
var doorTriggerYMin = 1200 + 200;
var doorTriggerYMax = 1200 + 600 - 200;
var leftDoorX = 300;
var rightDoorX = 1748;
var doorTriggerDist = 100;
// Check if player is at left door
if (playerPos.x >= leftDoorX - doorTriggerDist && playerPos.x <= leftDoorX + doorTriggerDist && playerPos.y >= doorTriggerYMin && playerPos.y <= doorTriggerYMax) {
// Play scary sound before animatronic comes to the door
LK.getSound('warning').play();
// Move a random animatronic to officeLeft if not already there
for (var i = 0; i < animatronics.length; i++) {
if (animatronics[i].currentRoom !== 'officeLeft') {
animatronics[i].currentRoom = 'officeLeft';
animatronicMoved = true;
// Play BearCame sound when animatronic comes to the door (left)
LK.getSound('BearCame').play();
// Start 5-second timer for player to close the left door
if (typeof animatronicAttackTimeouts === "undefined") animatronicAttackTimeouts = {};
if (animatronicAttackTimeouts['left']) {
LK.clearTimeout(animatronicAttackTimeouts['left']);
}
// Mark animatronic as attacking at left
if (typeof animatronicAttacking === "undefined") animatronicAttacking = {};
animatronicAttacking['left'] = true;
animatronicAttackTimeouts['left'] = LK.setTimeout(function () {
// If door is not closed after 5 seconds, trigger jumpscare
if (!doors.left.closed && animatronicAttacking['left']) {
triggerJumpscare(animatronics[i].id);
}
animatronicAttacking['left'] = false;
animatronicAttackTimeouts['left'] = null;
}, 5000);
break;
}
}
}
// Check if player is at right door
if (playerPos.x >= rightDoorX - doorTriggerDist && playerPos.x <= rightDoorX + doorTriggerDist && playerPos.y >= doorTriggerYMin && playerPos.y <= doorTriggerYMax) {
// Play scary sound before animatronic comes to the door
LK.getSound('warning').play();
// Move a random animatronic to officeRight if not already there
for (var i = 0; i < animatronics.length; i++) {
if (animatronics[i].currentRoom !== 'officeRight') {
animatronics[i].currentRoom = 'officeRight';
animatronicMoved = true;
// Play BearCame sound when animatronic comes to the door (right)
LK.getSound('BearCame').play();
// Start 5-second timer for player to close the right door
if (typeof animatronicAttackTimeouts === "undefined") animatronicAttackTimeouts = {};
if (animatronicAttackTimeouts['right']) {
LK.clearTimeout(animatronicAttackTimeouts['right']);
}
// Mark animatronic as attacking at right
if (typeof animatronicAttacking === "undefined") animatronicAttacking = {};
animatronicAttacking['right'] = true;
animatronicAttackTimeouts['right'] = LK.setTimeout(function () {
// If door is not closed after 5 seconds, trigger jumpscare
if (!doors.right.closed && animatronicAttacking['right']) {
triggerJumpscare(animatronics[i].id);
}
animatronicAttacking['right'] = false;
animatronicAttackTimeouts['right'] = null;
}, 5000);
break;
}
}
}
}
}
// Arrow key event handlers
leftArrow.down = function () {
movePlayer(-100, 0);
};
rightArrow.down = function () {
movePlayer(100, 0);
};
upArrow.down = function () {
movePlayer(0, -100);
};
downArrow.down = function () {
movePlayer(0, 100);
}; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
currentNight: 1,
highestNight: 1
});
/****
* Classes
****/
var Animatronic = Container.expand(function (id, startingRoom, aggressiveness) {
var self = Container.call(this);
self.id = id;
self.currentRoom = startingRoom;
self.previousRoom = startingRoom;
self.aggressiveness = aggressiveness;
self.moveTimer = 0;
self.moveCooldown = Math.floor(600 / self.aggressiveness);
self.active = true;
var sprite = self.attachAsset('animatronic', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9
});
self.update = function () {
// Prevent animatronic from moving at 12:00 AM (gameTime < 60)
if (typeof gameTime !== "undefined" && gameTime < 60) return;
if (!self.active) return;
// Increment move timer
self.moveTimer++;
// Check if it's time to move
if (self.moveTimer >= self.moveCooldown) {
self.moveTimer = 0;
// Determine if animatronic will move based on aggressiveness
if (Math.random() * 100 < self.aggressiveness) {
self.moveToNextRoom();
}
}
};
self.moveToNextRoom = function () {
self.previousRoom = self.currentRoom;
// Instead of only adjacent rooms, allow animatronic to appear at any random room
var allRooms = Object.keys(roomMap);
// Exclude office itself as a spawn, but allow officeLeft/officeRight
var validRooms = allRooms.filter(function (room) {
return room !== 'office';
});
var targetRoom = validRooms[Math.floor(Math.random() * validRooms.length)];
self.currentRoom = targetRoom;
// If moved to office or right outside office door, check door status
if (self.currentRoom === 'officeLeft' || self.currentRoom === 'officeRight') {
// Play BearCame sound when animatronic comes to the door
LK.getSound('BearCame').play();
var doorSide = self.currentRoom === 'officeLeft' ? 'left' : 'right';
if (!doors[doorSide].closed) {
// Jumpscare if door is open!
triggerJumpscare(self.id);
}
}
// Notify that an animatronic moved for camera updates
animatronicMoved = true;
};
self.render = function (cameraElement) {
// Position the animatronic in the correct spot based on the camera view
if (self.currentRoom === currentCamera) {
sprite.alpha = 1;
// Position differently based on the room
var roomPosition = cameraPositions[self.currentRoom];
if (roomPosition) {
sprite.x = roomPosition.x;
sprite.y = roomPosition.y;
// Add to the camera feed
cameraElement.addChild(sprite);
}
}
};
return self;
});
var Door = Container.expand(function (side) {
var self = Container.call(this);
self.side = side; // 'left' or 'right'
self.closed = false;
var doorGraphic = self.attachAsset('door', {
anchorX: 0.5,
anchorY: 0.5
});
var doorButton = self.attachAsset('doorButton', {
anchorX: 0.5,
anchorY: 0.5,
y: -250
});
var buttonLabel = new Text2("DOOR", {
size: 20,
fill: 0xFFFFFF
});
buttonLabel.anchor.set(0.5, 0.5);
doorButton.addChild(buttonLabel);
// Door starts open (hidden)
doorGraphic.alpha = 0;
self.toggleDoor = function () {
// Only allow door mechanics in easy mode
if (typeof selectedDifficulty === "undefined" || selectedDifficulty === "easy") {
self.closed = !self.closed;
if (self.closed) {
// Close door
doorGraphic.alpha = 1;
LK.getSound('doorClose').play();
buttonLabel.setText("OPEN");
doorButton.tint = 0xff0000;
// Use power
increasePowerUsage();
// If animatronic is attacking at this door, cancel attack and make animatronic leave
if (typeof animatronicAttacking !== "undefined" && animatronicAttacking[self.side]) {
animatronicAttacking[self.side] = false;
if (typeof animatronicAttackTimeouts !== "undefined" && animatronicAttackTimeouts[self.side]) {
LK.clearTimeout(animatronicAttackTimeouts[self.side]);
animatronicAttackTimeouts[self.side] = null;
}
}
// Make animatronic leave: move to a random non-office room if any animatronic is at the door (regardless of attack state)
for (var i = 0; i < animatronics.length; i++) {
var dangerRoom = self.side === 'left' ? 'officeLeft' : 'officeRight';
if (animatronics[i].currentRoom === dangerRoom) {
// Pick a random non-office room
var allRooms = Object.keys(roomMap).filter(function (room) {
return room !== 'office' && room !== 'officeLeft' && room !== 'officeRight';
});
var newRoom = allRooms[Math.floor(Math.random() * allRooms.length)];
animatronics[i].currentRoom = newRoom;
animatronicMoved = true;
}
}
} else {
// Open door
doorGraphic.alpha = 0;
LK.getSound('doorOpen').play();
buttonLabel.setText("DOOR");
doorButton.tint = 0x008000;
// Save power
decreasePowerUsage();
// Check if any animatronics are waiting outside
for (var i = 0; i < animatronics.length; i++) {
var dangerRoom = self.side === 'left' ? 'officeLeft' : 'officeRight';
if (animatronics[i].currentRoom === dangerRoom) {
// Jumpscare!
triggerJumpscare(animatronics[i].id);
return;
}
}
}
}
};
doorButton.down = function () {
self.toggleDoor();
};
return self;
});
var PowerSystem = Container.expand(function () {
var self = Container.call(this);
self.powerLevel = 100;
self.powerUsage = 1; // Base level (always uses some power)
self.drainTimer = 0;
var powerBarBg = self.attachAsset('powerBarBg', {
anchorX: 0,
anchorY: 0.5
});
var powerBar = self.attachAsset('powerBar', {
anchorX: 0,
anchorY: 0.5,
width: 400 // Start at full width
});
var powerLabel = new Text2("POWER: 100%", {
size: 30,
fill: 0xFFFFFF
});
powerLabel.anchor.set(0, 0.5);
powerLabel.x = 420;
self.addChild(powerLabel);
var usageLabel = new Text2("USAGE: ▮", {
size: 30,
fill: 0xFFFFFF
});
usageLabel.anchor.set(0, 0.5);
usageLabel.y = 40;
usageLabel.visible = true;
self.addChild(usageLabel);
// Track if usage rectangle should be shown
self.usageRectVisible = true;
self.update = function () {
// --- EASY MODE: Usage always 0 unless camera is open or a door is closed ---
if (typeof selectedDifficulty === "undefined" || selectedDifficulty === "easy") {
// Check if camera is open or any door is closed
var cameraOpen = typeof cameraSystemActive !== "undefined" && cameraSystemActive;
var leftClosed = typeof doors !== "undefined" && doors.left && doors.left.closed;
var rightClosed = typeof doors !== "undefined" && doors.right && doors.right.closed;
if (!cameraOpen && !leftClosed && !rightClosed) {
// Hide usage rectangle (▮) but keep "USAGE:" text
self.usageRectVisible = false;
self.powerUsage = 1;
self.updateUsageDisplay && self.updateUsageDisplay();
// Prevent power from decreasing at all in easy mode unless camera is open or a door is closed
return;
} else {
// Show only one rectangle (▮) if camera is open or only one door is closed
var count = 0;
if (cameraOpen) count++;
if (leftClosed) count++;
if (rightClosed) count++;
// Only show one rectangle if exactly one of these is true
if (count === 1) {
self.usageRectVisible = true;
self.powerUsage = 1;
} else if (count > 1) {
// If more than one (e.g. camera and a door, or both doors), show more rectangles as normal
self.usageRectVisible = true;
self.powerUsage = count;
}
self.updateUsageDisplay && self.updateUsageDisplay();
}
}
// Drain power based on usage level and game difficulty
self.drainTimer++;
// Drain every X frames based on current night (higher nights drain faster)
// Hard mode: power drains faster
var drainRate;
if (typeof selectedDifficulty === "undefined" || selectedDifficulty === "easy") {
drainRate = Math.max(15 - currentNight * 2, 5);
} else {
drainRate = Math.max(10 - currentNight * 3, 3);
}
if (self.drainTimer >= drainRate) {
self.drainTimer = 0;
self.powerLevel -= self.powerUsage * 0.1;
// Update power bar width
powerBar.width = 400 * (self.powerLevel / 100);
// Update label
powerLabel.setText("POWER: " + Math.floor(self.powerLevel) + "%");
// Change color as power decreases
if (self.powerLevel <= 20) {
powerBar.tint = 0xff0000; // Red when low
// Warning sounds when power is very low
if (self.powerLevel <= 10 && self.drainTimer % 5 === 0) {
LK.getSound('warning').play();
}
} else if (self.powerLevel <= 50) {
powerBar.tint = 0xffff00; // Yellow when medium
}
// Check for power out
if (self.powerLevel <= 0) {
powerOut();
}
}
};
self.updateUsageDisplay = function () {
var usageText = "USAGE:";
if (self.usageRectVisible) {
usageText += " ";
for (var i = 0; i < self.powerUsage; i++) {
usageText += "▮";
}
}
usageLabel.setText(usageText);
};
return self;
});
var SecurityCamera = Container.expand(function (roomId, x, y) {
var self = Container.call(this);
self.roomId = roomId;
self.x = x;
self.y = y;
self.isActive = false;
// Use a unique camera feed image for each room
var camFeedAssetId = 'camFeed_' + roomId;
var cameraFeed = self.attachAsset(camFeedAssetId, {
anchorX: 0.5,
anchorY: 0.5,
width: 120,
height: 112.5
});
var roomLabel = new Text2(roomId.toUpperCase(), {
size: 24,
fill: 0xFF0000
});
roomLabel.anchor.set(0.5, 0);
roomLabel.y = -cameraFeed.height / 2 - 30;
self.addChild(roomLabel);
var staticOverlay = self.attachAsset('staticOverlay', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3,
width: 120,
height: 80
});
self.activate = function () {
self.isActive = true;
LK.getSound('camSwitch').play();
// Increase static effect briefly
tween(staticOverlay, {
alpha: 0.7
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(staticOverlay, {
alpha: 0.3
}, {
duration: 300,
easing: tween.easeIn
});
}
});
// Always clear and re-add animatronics to prevent black feed
self.updateAnimatronics();
};
self.deactivate = function () {
self.isActive = false;
// Clear any animatronics from view
while (cameraFeed.children.length > 0) {
cameraFeed.removeChild(cameraFeed.children[0]);
}
// Also reset static overlay to default alpha
staticOverlay.alpha = 0.3;
};
self.updateAnimatronics = function () {
// Clear previous animatronics
while (cameraFeed.children.length > 0) {
cameraFeed.removeChild(cameraFeed.children[0]);
}
// Add animatronics that are in this room
for (var i = 0; i < animatronics.length; i++) {
// --- EASY MODE: Always show animatronic at the door and play BearCame sound ---
if ((typeof selectedDifficulty === "undefined" || selectedDifficulty === "easy") && (self.roomId === 'officeLeft' || self.roomId === 'officeRight')) {
// Force animatronic to be at the door in easy mode
animatronics[i].currentRoom = self.roomId;
animatronics[i].render(cameraFeed);
// Play BearCame sound every time camera is refreshed (safe, as it's a short sound)
LK.getSound('BearCame').play();
// No waitTimer logic needed in easy mode
continue;
}
// --- Normal logic for other rooms or hard mode ---
if (animatronics[i].currentRoom === self.roomId && self.isActive) {
animatronics[i].render(cameraFeed);
// --- BearCame sound logic for animatronic waiting in officeLeft/officeRight ---
// Only for officeLeft or officeRight, and only if animatronic has been there for 5 seconds
if (self.roomId === 'officeLeft' || self.roomId === 'officeRight') {
if (!animatronics[i].waitTimer) animatronics[i].waitTimer = 0;
// Play BearCame sound immediately when animatronic starts waiting in front of office
if (animatronics[i].waitTimer === 0) {
LK.getSound('BearCame').play();
}
animatronics[i].waitTimer++;
// 5 seconds = 5*60 = 300 frames
if (animatronics[i].waitTimer === 300) {
// (No need to play BearCame here anymore, already played at waitTimer === 0)
}
} else {
// Reset waitTimer if not in front of office
animatronics[i].waitTimer = 0;
}
} else if (animatronics[i].currentRoom === self.roomId) {
// Not active camera, but still reset waitTimer if not in officeLeft/officeRight
if (self.roomId !== 'officeLeft' && self.roomId !== 'officeRight') {
animatronics[i].waitTimer = 0;
}
}
}
};
self.down = function () {
// When this camera is clicked, make it the active camera
if (cameraSystemActive && self.roomId !== currentCamera) {
switchCamera(self.roomId);
}
};
return self;
});
var SecurityMonitor = Container.expand(function () {
var self = Container.call(this);
var monitorBg = self.attachAsset('securityMonitor', {
anchorX: 0.5,
anchorY: 0.5
});
var mapContainer = new Container();
// Center the map in the monitor background
mapContainer.x = -monitorBg.width / 2 + 200;
mapContainer.y = -monitorBg.height / 2 + 100;
self.addChild(mapContainer);
var cameraViewContainer = new Container();
cameraViewContainer.x = 200;
cameraViewContainer.y = 0;
self.addChild(cameraViewContainer);
var activeCamera = null;
var cameraLabel = new Text2("CAMERA: NONE", {
size: 40,
fill: 0xFF0000
});
cameraLabel.anchor.set(0.5, 0);
cameraLabel.x = 200;
cameraLabel.y = -monitorBg.height / 2 + 50;
self.addChild(cameraLabel);
var closeButton = self.attachAsset('closeCameraButton', {
anchorX: 0.5,
anchorY: 0.5,
x: monitorBg.width / 2 - 50,
y: -monitorBg.height / 2 + 50
});
var closeLabel = new Text2("X", {
size: 40,
fill: 0xFFFFFF
});
closeLabel.anchor.set(0.5, 0.5);
closeButton.addChild(closeLabel);
closeButton.down = function () {
toggleCameraSystem();
};
self.setup = function () {
// Optionally: Draw lines or dots to visually separate rooms (spacer lines)
// We'll use simple rectangles as spacers between clusters of rooms
// (This is a visual aid, not interactive)
var roomGroups = [['stage', 'kitchen', 'diningArea', 'laundry', 'storage'], ['arcade', 'partyRoom', 'backstage', 'restroom'], ['westHall', 'westCorner', 'officeLeft'], ['eastHall', 'eastCorner', 'officeRight']];
// Draw spacers between groups
for (var g = 1; g < roomGroups.length; g++) {
var prevGroup = roomGroups[g - 1];
var currGroup = roomGroups[g];
// Find center of last room in prev group and first room in curr group
var prevRoom = prevGroup[prevGroup.length - 1];
var currRoom = currGroup[0];
var prevPos = mapPositions[prevRoom];
var currPos = mapPositions[currRoom];
if (prevPos && currPos) {
var spacer = new Container();
var line = spacer.attachAsset('powerBarBg', {
anchorX: 0,
anchorY: 0.5,
width: Math.abs(currPos.x - prevPos.x),
height: 10,
tint: 0x222222,
alpha: 0.5
});
spacer.x = Math.min(prevPos.x, currPos.x);
spacer.y = (prevPos.y + currPos.y) / 2;
mapContainer.addChild(spacer);
}
}
// Create cameras for each room
for (var room in cameraPositions) {
var pos = mapPositions[room] || {
x: 0,
y: 0
};
var camera = new SecurityCamera(room, pos.x, pos.y);
mapContainer.addChild(camera);
cameras[room] = camera;
}
// Set initial camera to show
self.switchCamera('stage');
};
self.switchCamera = function (roomId) {
// Deactivate current camera
if (activeCamera) {
activeCamera.deactivate();
}
// Activate new camera
activeCamera = cameras[roomId];
if (activeCamera) {
activeCamera.activate();
currentCamera = roomId;
cameraLabel.setText("CAMERA: " + roomId.toUpperCase());
}
};
self.updateCameras = function () {
if (activeCamera) {
activeCamera.updateAnimatronics();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Unique assets for UI (not doorButton)
// Game constants and settings
var currentNight = storage.currentNight || 1;
var gameTime = 0; // in seconds
var nightDuration = 360; // 6 minutes per night
var cameraSystemActive = false;
var currentCamera = 'stage';
var animatronicMoved = false;
var gameOver = false;
var powerOutTriggered = false;
// Room layout definitions
var roomMap = {
'stage': ['diningArea'],
'diningArea': ['stage', 'westHall', 'eastHall', 'kitchen', 'arcade', 'partyRoom', 'laundry', 'backstage'],
'westHall': ['diningArea', 'westCorner', 'officeLeft', 'storage', 'laundry'],
'eastHall': ['diningArea', 'eastCorner', 'officeRight', 'arcade'],
'westCorner': ['westHall', 'officeLeft'],
'eastCorner': ['eastHall', 'officeRight'],
'kitchen': ['diningArea', 'storage', 'laundry'],
'arcade': ['diningArea', 'eastHall', 'partyRoom'],
'partyRoom': ['diningArea', 'arcade', 'storage', 'backstage'],
'storage': ['westHall', 'kitchen', 'partyRoom', 'laundry'],
'laundry': ['storage', 'kitchen', 'westHall', 'diningArea'],
'backstage': ['partyRoom', 'diningArea'],
// 'restroom' removed
'officeLeft': ['westCorner', 'office'],
'officeRight': ['eastCorner', 'office'],
'office': ['officeLeft', 'officeRight']
};
// Distance from each room to the office (for AI pathfinding)
var roomDistanceToOffice = {
'office': 0,
'officeLeft': 1,
'officeRight': 1,
'westCorner': 2,
'eastCorner': 2,
'westHall': 3,
'eastHall': 3,
'diningArea': 4,
'kitchen': 5,
'arcade': 5,
'partyRoom': 5,
'storage': 6,
'laundry': 6,
'backstage': 6,
'stage': 6
};
// Camera positions on the map (expanded area, problematic rooms adjusted/removed)
var mapPositions = {
'stage': {
x: 200,
y: 200
},
'diningArea': {
x: 500,
y: 200
},
'kitchen': {
x: 800,
y: 200
},
'laundry': {
x: 1100,
y: 200
},
'storage': {
x: 200,
y: 500
},
'partyRoom': {
x: 500,
y: 500
},
'arcade': {
x: 800,
y: 500
},
'backstage': {
x: 1100,
y: 500
},
// 'restroom' removed for clarity and space (no camera will be created for restroom)
'westHall': {
x: 200,
y: 800
},
// 'eastHall', 'eastCorner', and 'officeRight' removed from mapPositions to prevent their camera creation
'westCorner': {
x: 200,
y: 1100
},
'officeLeft': {
x: 200,
y: 1400
}
};
// Camera positions for rendering animatronics
var cameraPositions = {
'stage': {
x: 0,
y: 0
},
'diningArea': {
x: 50,
y: 0
},
'westHall': {
x: -50,
y: 0
},
// 'eastHall', 'eastCorner', and 'officeRight' removed from cameraPositions to prevent animatronic rendering in those rooms
'westCorner': {
x: -80,
y: 20
},
'kitchen': {
x: 0,
y: -30
},
'arcade': {
x: 60,
y: -20
},
'partyRoom': {
x: 0,
y: 40
},
'storage': {
x: -60,
y: -40
},
'laundry': {
x: -30,
y: -60
},
'backstage': {
x: 100,
y: -50
},
// (restroom removed to prevent out-of-bounds camera)
'officeLeft': {
x: -100,
y: 0
}
};
// Initialize game objects
var securityMonitor = new SecurityMonitor();
var powerSystem = new PowerSystem();
var doors = {
'left': new Door('left'),
'right': new Door('right')
};
var cameras = {};
var animatronics = [];
var clockDisplay, nightDisplay, cameraToggleBtn;
// Initialize office background as a single image covering the whole office
var officeFull = LK.getAsset('officeFull', {
anchorX: 0.5,
anchorY: 0,
x: 2048 / 2,
y: 1200
});
game.addChild(officeFull);
// Position and add doors on top of the officeFull image
doors.left.x = 800; // moved further to the right from 700 to 800
doors.left.y = 1200 + 400;
doors.right.x = 1748; // 2048 - 300
doors.right.y = 1200 + 400;
game.addChild(doors.left);
game.addChild(doors.right);
// Add security monitor (initially hidden)
securityMonitor.visible = false;
securityMonitor.y = 1300;
game.addChild(securityMonitor);
// Camera navigation buttons
var cameraRoomOrder = ['stage', 'diningArea', 'kitchen', 'laundry', 'storage', 'partyRoom', 'arcade', 'backstage', 'westHall', 'westCorner', 'officeLeft'];
// easthall, eastcorner, and officeRight removed from cameraRoomOrder to delete their cameras
function getCurrentCameraIndex() {
for (var i = 0; i < cameraRoomOrder.length; i++) {
if (cameraRoomOrder[i] === currentCamera) return i;
}
return 0;
}
// Set up camera button
cameraToggleBtn = LK.getAsset('cameraButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2200
});
game.addChild(cameraToggleBtn);
var cameraLabel = new Text2("CAMERAS", {
size: 30,
fill: 0xFFFFFF
});
cameraLabel.anchor.set(0.5, 0.5);
cameraToggleBtn.addChild(cameraLabel);
// Set up power display
powerSystem.x = 150;
powerSystem.y = 150;
LK.gui.topLeft.addChild(powerSystem);
// Set up clock
clockDisplay = new Text2("12:00 AM", {
size: 60,
fill: 0xFFFFFF
});
clockDisplay.anchor.set(0.5, 0);
LK.gui.top.addChild(clockDisplay);
// --- Fullscreen Button ---
// Place at top right, but not overlapping nightDisplay (which is x = -150 from right edge)
var fullscreenBtn = LK.getAsset('fullscreenButton', {
anchorX: 0.5,
anchorY: 0.5,
x: -300,
// further left from nightDisplay
y: 80,
width: 120,
height: 120,
alpha: 0.8
});
LK.gui.topRight.addChild(fullscreenBtn);
var fullscreenLabel = new Text2("⛶", {
size: 60,
fill: 0xffffff
});
fullscreenLabel.anchor.set(0.5, 0.5);
fullscreenBtn.addChild(fullscreenLabel);
// Only show if not already fullscreen
fullscreenBtn.visible = !LK.isFullscreen || !LK.isFullscreen();
// Handler to enter fullscreen
fullscreenBtn.down = function () {
if (LK.requestFullscreen) {
LK.requestFullscreen();
}
// Optionally hide the button after entering fullscreen
fullscreenBtn.visible = false;
};
// Set up night display
nightDisplay = new Text2("NIGHT " + currentNight, {
size: 60,
fill: 0xFFFFFF
});
nightDisplay.anchor.set(1, 0);
nightDisplay.x = -150;
LK.gui.topRight.addChild(nightDisplay);
// Night overlay for transitions
var nightOverlay = LK.getAsset('nightOverlay', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
alpha: 1
});
nightOverlay.visible = false; // Always keep overlay hidden
game.addChild(nightOverlay);
// Initialize animatronics based on current night
function setupAnimatronics() {
animatronics = [];
// Clear any existing animatronics
for (var i = 0; i < animatronics.length; i++) {
if (animatronics[i].parent) {
animatronics[i].parent.removeChild(animatronics[i]);
}
}
// All animatronics start on the stage (except Foxy)
// Difficulty affects aggressiveness
var baseAggressiveness;
if (typeof selectedDifficulty === "undefined" || selectedDifficulty === "easy") {
baseAggressiveness = 5 + currentNight * 5;
} else {
baseAggressiveness = 15 + currentNight * 8;
}
// Define animatronic turn order (farthest to closest)
var animatronicOrder = [];
animatronicOrder.push({
id: 'freddy',
start: 'stage',
aggr: baseAggressiveness
});
if (currentNight >= 2) {
animatronicOrder.push({
id: 'bonnie',
start: 'stage',
aggr: baseAggressiveness + 5
});
}
if (currentNight >= 3) {
animatronicOrder.push({
id: 'chica',
start: 'stage',
aggr: baseAggressiveness + 2
});
}
if (currentNight >= 4) {
animatronicOrder.push({
id: 'foxy',
start: 'westHall',
aggr: baseAggressiveness + 10
});
}
// Create animatronics in order
for (var i = 0; i < animatronicOrder.length; i++) {
var a = animatronicOrder[i];
animatronics.push(new Animatronic(a.id, a.start, a.aggr));
}
// Track whose turn it is to move
animatronicTurnIndex = 0;
}
// Function to start a new night
function startNight() {
// Reset game state
gameTime = 0;
cameraSystemActive = false;
currentCamera = 'stage';
animatronicMoved = false;
gameOver = false;
powerOutTriggered = false;
// Difficulty is already set by menu, nothing to do here
// Reset doors
doors.left.closed = false;
doors.right.closed = false;
doors.left.toggleDoor();
doors.left.toggleDoor();
doors.right.toggleDoor();
doors.right.toggleDoor();
// Reset power
powerSystem.powerLevel = 100;
powerSystem.powerUsage = 1;
powerSystem.updateUsageDisplay();
// Setup security cameras
securityMonitor.setup();
// Setup animatronics
setupAnimatronics();
// Update display
nightDisplay.setText("NIGHT " + currentNight);
// Fade in
tween(nightOverlay, {
alpha: 0
}, {
duration: 2000,
easing: tween.easeIn
});
// Play ambient sounds
LK.playMusic('ambientMusic', {
loop: true
});
LK.getSound('ambient').play();
}
// Function to toggle camera system
function toggleCameraSystem() {
cameraSystemActive = !cameraSystemActive;
if (cameraSystemActive) {
// Show camera system
securityMonitor.visible = true;
cameraToggleBtn.tint = 0xff0000;
// Use more power
increasePowerUsage();
// Play sound
LK.getSound('camSwitch').play();
} else {
// Hide camera system
securityMonitor.visible = false;
cameraToggleBtn.tint = 0x990000;
// Use less power
decreasePowerUsage();
// Play sound
LK.getSound('camSwitch').play();
}
}
// Function to switch camera views
function switchCamera(roomId) {
// Always allow switching to any valid camera, including the first one
if (cameras[roomId]) {
// Deactivate all cameras first to prevent multiple active states
for (var camKey in cameras) {
if (cameras.hasOwnProperty(camKey)) {
cameras[camKey].deactivate();
}
}
securityMonitor.switchCamera(roomId);
currentCamera = roomId;
// Play sound
LK.getSound('camSwitch').play();
}
}
// Function to increase power usage
function increasePowerUsage() {
powerSystem.powerUsage++;
powerSystem.updateUsageDisplay();
}
// Function to decrease power usage
function decreasePowerUsage() {
if (powerSystem.powerUsage > 1) {
powerSystem.powerUsage--;
powerSystem.updateUsageDisplay();
}
}
// Function to handle power outage
function powerOut() {
if (powerOutTriggered) return;
powerOutTriggered = true;
// Turn off all systems
securityMonitor.visible = false;
cameraSystemActive = false;
// Open all doors
if (doors.left.closed) doors.left.toggleDoor();
if (doors.right.closed) doors.right.toggleDoor();
// Play power down sound
LK.getSound('powerDown').play();
// Game over with slight delay (for tension)
LK.setTimeout(function () {
triggerJumpscare('freddy');
}, 5000);
}
// Function to trigger jumpscare
function triggerJumpscare(animatronicId) {
if (gameOver) return;
gameOver = true;
// Play jumpscare sound
LK.getSound('jumpscare').play();
// Flash screen red
LK.effects.flashScreen(0xff0000, 500);
// --- Jumpscare image and animation ---
var jumpscareImg = LK.getAsset('animatronic', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
width: 1200,
height: 1200,
alpha: 0
});
game.addChild(jumpscareImg);
// Terrifying GAME OVER text
var gameOverText = new Text2("GAME OVER", {
size: 200,
fill: 0xff0000,
font: "Impact, 'Arial Black', Tahoma"
});
gameOverText.anchor.set(0.5, 0.5);
gameOverText.x = 2048 / 2;
gameOverText.y = 2732 / 2 + 500;
gameOverText.alpha = 0;
game.addChild(gameOverText);
// Animate: fade in and scale up for a terrifying effect
jumpscareImg.scaleX = 1;
jumpscareImg.scaleY = 1;
tween(jumpscareImg, {
alpha: 1,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 350,
easing: tween.easeIn,
onFinish: function onFinish() {
// Hold for a moment, then fade in GAME OVER text and fade out jumpscare
tween(gameOverText, {
alpha: 1,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 400,
easing: tween.easeIn,
onFinish: function onFinish() {
// Fade out jumpscare image, keep GAME OVER text for a bit
tween(jumpscareImg, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
if (jumpscareImg.parent) jumpscareImg.parent.removeChild(jumpscareImg);
// Hold GAME OVER text, then fade out and show LK game over
tween(gameOverText, {
alpha: 0
}, {
duration: 800,
delay: 800,
easing: tween.easeOut,
onFinish: function onFinish() {
if (gameOverText.parent) gameOverText.parent.removeChild(gameOverText);
LK.showGameOver();
}
});
}
});
}
});
}
});
}
// Function to complete the night successfully
function completeNight() {
// Update stored progress
if (currentNight >= storage.highestNight) {
storage.highestNight = currentNight + 1;
}
currentNight++;
storage.currentNight = currentNight;
// Show win screen
LK.showYouWin();
}
// Events for camera toggle button
cameraToggleBtn.down = function () {
toggleCameraSystem();
};
// Update game time and clock display
function updateClock() {
var hour = Math.floor(gameTime / 60) + 12;
if (hour > 12) hour -= 12;
var timeString = hour + ":00 AM";
clockDisplay.setText(timeString);
// Check if night is complete
if (gameTime >= nightDuration) {
completeNight();
}
}
// Main game update function
game.update = function () {
if (nightOverlay.alpha > 0) return; // Don't update while fading in
// Update game time (every half second, so time passes 2x faster)
if (LK.ticks % 30 === 0) {
gameTime++;
updateClock();
}
// Update power system
powerSystem.update();
// Animatronics take turns moving, from farthest to closest (one per update cycle)
if (typeof animatronicTurnIndex === "undefined") {
animatronicTurnIndex = 0;
}
if (animatronics.length > 0) {
// Only one animatronic moves per update
animatronics[animatronicTurnIndex].update();
animatronicTurnIndex++;
if (animatronicTurnIndex >= animatronics.length) {
animatronicTurnIndex = 0;
}
}
// Update camera feed if an animatronic moved
if (animatronicMoved) {
animatronicMoved = false;
securityMonitor.updateCameras();
}
};
// --- Main Menu Overlay ---
var mainMenuOverlay = new Container();
mainMenuOverlay.x = 0;
mainMenuOverlay.y = 0;
mainMenuOverlay.width = 2048;
mainMenuOverlay.height = 2732;
mainMenuOverlay.visible = true;
// Dimmed background
var menuBg = mainMenuOverlay.attachAsset('nightOverlay', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
width: 2048,
height: 2732,
alpha: 0.85
});
mainMenuOverlay.addChild(menuBg);
// Game Title
var titleText = new Text2("FNAF FRVR", {
size: 180,
fill: 0xffcc00,
font: "Impact, 'Arial Black', Tahoma"
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 700;
mainMenuOverlay.addChild(titleText);
// --- Difficulty Buttons (only on main menu) ---
var selectedDifficulty = "easy";
var easyBtn = LK.getAsset('easyButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 - 250,
y: 1050,
width: 300,
height: 120,
alpha: 0.95
});
mainMenuOverlay.addChild(easyBtn);
var easyLabel = new Text2("EASY", {
size: 60,
fill: 0xffffff,
font: "Impact, 'Arial Black', Tahoma"
});
easyLabel.anchor.set(0.5, 0.5);
easyBtn.addChild(easyLabel);
var hardBtn = LK.getAsset('hardButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2 + 250,
y: 1050,
width: 300,
height: 120,
alpha: 0.95
});
mainMenuOverlay.addChild(hardBtn);
var hardLabel = new Text2("HARD", {
size: 60,
fill: 0xffffff,
font: "Impact, 'Arial Black', Tahoma"
});
hardLabel.anchor.set(0.5, 0.5);
hardBtn.addChild(hardLabel);
function updateDifficultyButtons() {
if (selectedDifficulty === "easy") {
easyBtn.tint = 0x00ff00;
hardBtn.tint = 0xcc0000;
} else {
easyBtn.tint = 0x00cc00;
hardBtn.tint = 0xff2222;
}
}
easyBtn.down = function () {
selectedDifficulty = "easy";
updateDifficultyButtons();
};
hardBtn.down = function () {
selectedDifficulty = "hard";
updateDifficultyButtons();
};
updateDifficultyButtons();
// Start Button
var startBtn = LK.getAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1200,
width: 400,
height: 200,
alpha: 0.95
});
mainMenuOverlay.addChild(startBtn);
var startLabel = new Text2("START", {
size: 90,
fill: 0xffffff,
font: "Impact, 'Arial Black', Tahoma"
});
startLabel.anchor.set(0.5, 0.5);
startBtn.addChild(startLabel);
// Optionally: Instructions
var instrText = new Text2("Kapılardan hayatta kal!\nKameraları kullan, kapıları kapat, gücünü idare et.", {
size: 48,
fill: 0xffffff,
font: "Tahoma"
});
instrText.anchor.set(0.5, 0);
instrText.x = 2048 / 2;
instrText.y = 1450;
mainMenuOverlay.addChild(instrText);
// Add overlay to game
game.addChild(mainMenuOverlay);
// Disable all game UI until menu is dismissed
function showMainMenu() {
mainMenuOverlay.visible = true;
// Hide night overlay in main menu
if (typeof nightOverlay !== "undefined" && nightOverlay) nightOverlay.visible = false;
// Reset difficulty to easy by default
selectedDifficulty = "easy";
if (typeof updateDifficultyButtons === "function") updateDifficultyButtons();
// Optionally hide other UI
securityMonitor.visible = false;
cameraToggleBtn.visible = false;
powerSystem.visible = false;
clockDisplay.visible = false;
nightDisplay.visible = false;
fullscreenBtn.visible = false;
if (typeof leftArrow !== "undefined" && leftArrow) leftArrow.visible = false;
if (typeof rightArrow !== "undefined" && rightArrow) rightArrow.visible = false;
if (typeof upArrow !== "undefined" && upArrow) upArrow.visible = false;
if (typeof downArrow !== "undefined" && downArrow) downArrow.visible = false;
if (typeof playerDot !== "undefined" && playerDot) playerDot.visible = false;
if (typeof officeFull !== "undefined" && officeFull) officeFull.visible = false;
if (typeof doors !== "undefined" && doors.left) doors.left.visible = false;
if (typeof doors !== "undefined" && doors.right) doors.right.visible = false;
// Make absolutely sure nightOverlay is hidden in main menu
if (typeof nightOverlay !== "undefined" && nightOverlay) nightOverlay.visible = false;
}
function hideMainMenu() {
mainMenuOverlay.visible = false;
// Do not show night overlay when game starts
if (typeof nightOverlay !== "undefined" && nightOverlay) nightOverlay.visible = false;
// Show UI
securityMonitor.visible = false;
cameraToggleBtn.visible = true;
powerSystem.visible = true;
clockDisplay.visible = true;
nightDisplay.visible = true;
fullscreenBtn.visible = !LK.isFullscreen || !LK.isFullscreen();
if (typeof leftArrow !== "undefined" && leftArrow) leftArrow.visible = true;
if (typeof rightArrow !== "undefined" && rightArrow) rightArrow.visible = true;
if (typeof upArrow !== "undefined" && upArrow) upArrow.visible = true;
if (typeof downArrow !== "undefined" && downArrow) downArrow.visible = true;
if (typeof playerDot !== "undefined" && playerDot) playerDot.visible = true;
if (typeof officeFull !== "undefined" && officeFull) officeFull.visible = true;
if (typeof doors !== "undefined" && doors.left) doors.left.visible = true;
if (typeof doors !== "undefined" && doors.right) doors.right.visible = true;
// Make absolutely sure nightOverlay is visible when game starts
if (typeof nightOverlay !== "undefined" && nightOverlay) nightOverlay.visible = true;
}
// Start game when start button is pressed
startBtn.down = function () {
hideMainMenu();
startNight();
};
// Show menu at launch
showMainMenu();
;
// --- On-screen Arrow Keys for Player Movement ---
// Arrow key asset sizes and positions
var arrowSize = 180;
var arrowAlpha = 0.7;
var arrowY = 2732 - 250;
var arrowXCenter = 2048 / 2;
var arrowSpacing = 220;
// Create arrow containers
var leftArrow = new Container();
var rightArrow = new Container();
var upArrow = new Container();
var downArrow = new Container();
// Add arrow graphics
var leftArrowGraphic = leftArrow.attachAsset('arrowLeft', {
anchorX: 0.5,
anchorY: 0.5,
width: arrowSize,
height: arrowSize,
alpha: arrowAlpha
});
var rightArrowGraphic = rightArrow.attachAsset('arrowRight', {
anchorX: 0.5,
anchorY: 0.5,
width: arrowSize,
height: arrowSize,
alpha: arrowAlpha
});
var upArrowGraphic = upArrow.attachAsset('arrowUp', {
anchorX: 0.5,
anchorY: 0.5,
width: arrowSize,
height: arrowSize,
alpha: arrowAlpha
});
var downArrowGraphic = downArrow.attachAsset('arrowDown', {
anchorX: 0.5,
anchorY: 0.5,
width: arrowSize,
height: arrowSize,
alpha: arrowAlpha
});
// Add arrow labels
var leftLabel = new Text2("◀", {
size: 100,
fill: 0xFFFFFF
});
leftLabel.anchor.set(0.5, 0.5);
leftArrow.addChild(leftLabel);
var rightLabel = new Text2("▶", {
size: 100,
fill: 0xFFFFFF
});
rightLabel.anchor.set(0.5, 0.5);
rightArrow.addChild(rightLabel);
var upLabel = new Text2("▲", {
size: 100,
fill: 0xFFFFFF
});
upLabel.anchor.set(0.5, 0.5);
upArrow.addChild(upLabel);
var downLabel = new Text2("▼", {
size: 100,
fill: 0xFFFFFF
});
downLabel.anchor.set(0.5, 0.5);
downArrow.addChild(downLabel);
// Position arrows (bottom center, spaced out)
leftArrow.x = arrowXCenter - arrowSpacing;
leftArrow.y = arrowY;
rightArrow.x = arrowXCenter + arrowSpacing;
rightArrow.y = arrowY;
upArrow.x = arrowXCenter;
upArrow.y = arrowY - arrowSpacing;
downArrow.x = arrowXCenter;
downArrow.y = arrowY + arrowSpacing / 1.5;
// Add to game
game.addChild(leftArrow);
game.addChild(rightArrow);
game.addChild(upArrow);
game.addChild(downArrow);
// Hide arrows initially (main menu is visible at start)
leftArrow.visible = false;
rightArrow.visible = false;
upArrow.visible = false;
downArrow.visible = false;
// --- Player movement logic ---
// Define player position in the office (for demo, just a dot in the office)
if (typeof playerPos === "undefined") {
var playerPos = {
x: 2048 / 2,
y: 1800
};
}
if (typeof playerDot === "undefined") {
var playerDot = new Container();
var characterGraphic = playerDot.attachAsset('playerCharacter', {
anchorX: 0.5,
anchorY: 0.5,
width: 120,
height: 120,
alpha: 1
});
playerDot.x = playerPos.x;
playerDot.y = playerPos.y;
game.addChild(playerDot);
}
// Movement boundaries (keep player in office area)
var minX = 300 + 80,
maxX = 1748 - 80;
var minY = 1200 + 80,
maxY = 1200 + 600 - 80;
// Move player and update dot position
function movePlayer(dx, dy) {
// Only allow mechanics if easy mode is selected
if (typeof selectedDifficulty === "undefined" || selectedDifficulty === "easy") {
playerPos.x += dx;
playerPos.y += dy;
// Clamp to bounds
if (playerPos.x < minX) playerPos.x = minX;
if (playerPos.x > maxX) playerPos.x = maxX;
if (playerPos.y < minY) playerPos.y = minY;
if (playerPos.y > maxY) playerPos.y = maxY;
playerDot.x = playerPos.x;
playerDot.y = playerPos.y;
// --- Animatronic comes to the door when player arrives ---
// Define door trigger areas (left and right)
var doorTriggerYMin = 1200 + 200;
var doorTriggerYMax = 1200 + 600 - 200;
var leftDoorX = 300;
var rightDoorX = 1748;
var doorTriggerDist = 100;
// Check if player is at left door
if (playerPos.x >= leftDoorX - doorTriggerDist && playerPos.x <= leftDoorX + doorTriggerDist && playerPos.y >= doorTriggerYMin && playerPos.y <= doorTriggerYMax) {
// Play scary sound before animatronic comes to the door
LK.getSound('warning').play();
// Move a random animatronic to officeLeft if not already there
for (var i = 0; i < animatronics.length; i++) {
if (animatronics[i].currentRoom !== 'officeLeft') {
animatronics[i].currentRoom = 'officeLeft';
animatronicMoved = true;
// Play BearCame sound when animatronic comes to the door (left)
LK.getSound('BearCame').play();
// Start 5-second timer for player to close the left door
if (typeof animatronicAttackTimeouts === "undefined") animatronicAttackTimeouts = {};
if (animatronicAttackTimeouts['left']) {
LK.clearTimeout(animatronicAttackTimeouts['left']);
}
// Mark animatronic as attacking at left
if (typeof animatronicAttacking === "undefined") animatronicAttacking = {};
animatronicAttacking['left'] = true;
animatronicAttackTimeouts['left'] = LK.setTimeout(function () {
// If door is not closed after 5 seconds, trigger jumpscare
if (!doors.left.closed && animatronicAttacking['left']) {
triggerJumpscare(animatronics[i].id);
}
animatronicAttacking['left'] = false;
animatronicAttackTimeouts['left'] = null;
}, 5000);
break;
}
}
}
// Check if player is at right door
if (playerPos.x >= rightDoorX - doorTriggerDist && playerPos.x <= rightDoorX + doorTriggerDist && playerPos.y >= doorTriggerYMin && playerPos.y <= doorTriggerYMax) {
// Play scary sound before animatronic comes to the door
LK.getSound('warning').play();
// Move a random animatronic to officeRight if not already there
for (var i = 0; i < animatronics.length; i++) {
if (animatronics[i].currentRoom !== 'officeRight') {
animatronics[i].currentRoom = 'officeRight';
animatronicMoved = true;
// Play BearCame sound when animatronic comes to the door (right)
LK.getSound('BearCame').play();
// Start 5-second timer for player to close the right door
if (typeof animatronicAttackTimeouts === "undefined") animatronicAttackTimeouts = {};
if (animatronicAttackTimeouts['right']) {
LK.clearTimeout(animatronicAttackTimeouts['right']);
}
// Mark animatronic as attacking at right
if (typeof animatronicAttacking === "undefined") animatronicAttacking = {};
animatronicAttacking['right'] = true;
animatronicAttackTimeouts['right'] = LK.setTimeout(function () {
// If door is not closed after 5 seconds, trigger jumpscare
if (!doors.right.closed && animatronicAttacking['right']) {
triggerJumpscare(animatronics[i].id);
}
animatronicAttacking['right'] = false;
animatronicAttackTimeouts['right'] = null;
}, 5000);
break;
}
}
}
}
}
// Arrow key event handlers
leftArrow.down = function () {
movePlayer(-100, 0);
};
rightArrow.down = function () {
movePlayer(100, 0);
};
upArrow.down = function () {
movePlayer(0, -100);
};
downArrow.down = function () {
movePlayer(0, 100);
};
A terrifying very big animatronic.. In-Game asset. 2d. High contrast. No shadows
It says Night 1. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
make a red door open and close button. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
nothing. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
Bana bir ofis odası yap. Biraz gerilim salan ama içinde canavar olmayan eski bir karanlık güvenlik ofis odası gibi olsun. In-Game asset. 2d. High contrast. No shadows
A 30-something security guard in a purple uniform, looking tired and vengeful.. In-Game asset. 2d. High contrast. No shadows