/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Animatronic class
var Animatronic = Container.expand(function () {
var self = Container.call(this);
// Add animatronic body (behind jaw and head)
var body = self.attachAsset('animatronicBody', {
anchorX: 0.5,
anchorY: 0,
x: 350,
y: 570
});
// Jaw (behind head)
var jaw = self.attachAsset('animatronicJaw', {
anchorX: 0.5,
anchorY: 0,
x: 350,
y: 400
});
// Head (in front of jaw)
var head = self.attachAsset('animatronicHead', {
anchorX: 0.5,
anchorY: 0.5,
x: 350,
y: 250
});
// (Eyes, pupils, and nose removed)
// State
self.jawOpen = 0; // 0 closed, 1 open
self.headTilt = 0; // -1 left, 0 center, 1 right
self.glitchTimer = 0;
self.glitching = false;
self.glitchState = 0;
self.glitchDuration = 0;
self.glitchCooldown = 0;
// Helper: set pose
self.setPose = function (jawOpen, headTilt) {
self.jawOpen = jawOpen;
self.headTilt = headTilt;
// Jaw open/close
jaw.y = 400 + 60 * jawOpen;
// Head tilt
head.rotation = headTilt * 0.12;
// (Ears removed)
// (Eyes, pupils, and nose removed)
};
// Helper: set pupils offset (for glitch)
self.setPupilOffset = function (dx, dy) {
// (Pupil offset removed)
};
// Helper: set head position offset (for glitch)
self.setHeadOffset = function (dx, dy) {
self.x = self.baseX + dx;
self.y = self.baseY + dy;
};
// Helper: reset all offsets
self.resetOffsets = function () {
self.setHeadOffset(0, 0);
};
// Animate jaw open/close
self.animateJaw = function (open) {
tween(self, {
jawOpen: open
}, {
duration: 180,
easing: tween.cubicInOut
});
};
// Animate head tilt
self.animateTilt = function (target) {
tween(self, {
headTilt: target
}, {
duration: 220,
easing: tween.cubicInOut
});
};
// Glitch effect: random pose, random offset, short duration
self.triggerGlitch = function () {
self.glitching = true;
self.glitchState = Math.floor(Math.random() * 3);
self.glitchDuration = 6 + Math.floor(Math.random() * 6); // 6-12 frames
self.glitchCooldown = 30 + Math.floor(Math.random() * 60); // 0.5-1.5s
// Random pose
var jaw = Math.random() > 0.5 ? 1 : 0;
var tilt = [-1, 0, 1][Math.floor(Math.random() * 3)];
self.setPose(jaw, tilt);
// Random offset
var dx = -10 + Math.random() * 20;
var dy = -10 + Math.random() * 20;
self.setHeadOffset(dx, dy);
// (Random pupils removed)
};
// Update
self.update = function () {
// Animate jaw and tilt
self.setPose(self.jawOpen, self.headTilt);
// Glitch logic
if (self.glitching) {
self.glitchDuration--;
if (self.glitchDuration <= 0) {
self.glitching = false;
self.resetOffsets();
}
} else {
self.glitchCooldown--;
if (self.glitchCooldown <= 0) {
self.triggerGlitch();
}
}
};
// For centering
self.baseX = 0;
self.baseY = 0;
return self;
});
// Button class
var MenuButton = Container.expand(function () {
var self = Container.call(this);
var bg = self.attachAsset('buttonRect', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0
});
bg.alpha = 0.0;
self.label = new Text2('', {
size: 80,
fill: 0xFFFFFF
});
self.label.anchor.set(0.5, 0.5);
self.addChild(self.label);
self.setText = function (txt) {
self.label.setText(txt);
};
self.setActive = function (active) {
bg.alpha = 0.0;
self.label.alpha = active ? 1 : 0.7;
};
return self;
});
// VHS Static overlay class
var VHSStatic = Container.expand(function () {
var self = Container.call(this);
var staticNode = self.attachAsset('vhsStatic', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
staticNode.alpha = 0.08;
// Add horizontal noise lines
var noiseLines = [];
for (var i = 0; i < 8; i++) {
var line = self.attachAsset('vhsStatic', {
anchorX: 0,
anchorY: 0,
x: 0,
y: Math.random() * 2732,
width: 2048,
height: 8,
color: 0xffffff
});
line.alpha = 0.08 + Math.random() * 0.10;
noiseLines.push(line);
}
self.update = function () {
// Animate static flicker
staticNode.alpha = 0.06 + Math.random() * 0.10;
// Animate noise lines: randomize y and alpha for each line
for (var i = 0; i < noiseLines.length; i++) {
var line = noiseLines[i];
// Move line vertically, wrap around
line.y += 32 + Math.random() * 32;
if (line.y > 2732) line.y = -8;
// Flicker alpha
line.alpha = 0.08 + Math.random() * 0.12;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Button shape
// VHS static overlay
// Animatronic nose
// Animatronic right ear
// Animatronic left ear
// Animatronic right pupil
// Animatronic left pupil
// Animatronic right eye
// Animatronic left eye
// Animatronic jaw
// Animatronic body (main head)
// Game state
var STATE_MENU = 0;
var STATE_PLAY = 1;
var STATE_NIGHTEND = 2;
var state = STATE_MENU;
// Night and hour
var currentNight = 1;
var currentHour = 12;
// Animatronic
var animatronic = new Animatronic();
// Kuklanın tüm parçalarını biraz küçült ve daha yukarı taşı
var animatronicScale = 1.25; // daha küçük
// Head asset is 700px wide, 500px tall, so center based on that
animatronic.baseX = 2048 / 2 - 700 * animatronicScale / 2;
// Daha yukarı taşı: 420 yerine 700 px yukarıda
animatronic.baseY = 2732 - 500 * animatronicScale - 700;
animatronic.x = animatronic.baseX;
animatronic.y = animatronic.baseY;
animatronic.scaleX = animatronicScale;
animatronic.scaleY = animatronicScale;
game.addChild(animatronic);
// VHS static overlay
var vhsStatic = new VHSStatic();
game.addChild(vhsStatic);
// Menu UI
var titleText = new Text2('', {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0);
titleText.x = 2048 / 2;
titleText.y = 220;
// Set initial title text to English regardless of language
titleText.setText('FNAF : FINISH THE NIGHT');
var btnNewGame = new MenuButton();
btnNewGame.x = 2048 / 2;
btnNewGame.y = 600;
btnNewGame.setText('YENİ OYUN');
var btnContinue = new MenuButton();
btnContinue.x = 2048 / 2;
btnContinue.y = 800;
btnContinue.setText('DEVAM ET');
// Leaderboard button
var btnLeaderboard = new MenuButton();
// Move to left side, but not in the top left 100x100 area (avoid platform menu)
// Place at x=400, y=1000 (moved right from 200 to 400)
btnLeaderboard.x = 400;
btnLeaderboard.y = 1000;
btnLeaderboard.setText('SKOR TABLOSU');
// Language select button (now below continue)
var btnLang = new MenuButton();
btnLang.x = 2048 / 2;
// Calculate vertical gap between continue and new game buttons
var menuButtonGap = btnContinue.y - btnNewGame.y;
// Place language button the same gap below continue button
btnLang.y = btnContinue.y + menuButtonGap;
btnLang.setText('DİL: Türkçe');
var continueNightText = new Text2('', {
size: 38,
fill: 0xFFFFFF
});
continueNightText.anchor.set(0, 0.5);
continueNightText.x = btnContinue.x + 380;
continueNightText.y = btnContinue.y;
// Leaderboard UI
var leaderboardText = new Text2('', {
size: 60,
fill: 0xFFFF00
});
leaderboardText.anchor.set(0.5, 0);
leaderboardText.x = 2048 / 2;
leaderboardText.y = 300;
leaderboardText.visible = false;
// Leaderboard close button
var btnLeaderboardClose = new MenuButton();
btnLeaderboardClose.x = 2048 / 2;
btnLeaderboardClose.y = 2200;
btnLeaderboardClose.setText('KAPAT');
btnLeaderboardClose.visible = false;
// Menu selection
var menuSelected = 0; // 0: new game, 1: continue
// Night info UI
var nightText = new Text2('', {
size: 110,
fill: 0xFFFFFF
});
nightText.anchor.set(0.5, 0.5);
nightText.x = 2048 / 2;
nightText.y = 400;
nightText.alpha = 0;
var hourText = new Text2('', {
size: 90,
fill: 0xFFFFFF
});
hourText.anchor.set(0.5, 0.5);
hourText.x = 2048 / 2;
hourText.y = 540;
hourText.alpha = 0;
// Test: End night button
var btnEndNight = new MenuButton();
btnEndNight.x = 2048 / 2;
btnEndNight.y = 1200;
btnEndNight.setText('GECEYİ BİTİR');
btnEndNight.visible = false;
// 6:00 screen
var sixText = new Text2('06:00', {
size: 180,
fill: 0xFFFFFF
});
sixText.anchor.set(0.5, 0.5);
sixText.x = 2048 / 2;
sixText.y = 700;
sixText.alpha = 0;
// Add menu UI to game
game.addChild(titleText);
game.addChild(btnNewGame);
game.addChild(btnContinue);
game.addChild(btnLeaderboard);
game.addChild(btnLang);
game.addChild(continueNightText);
game.addChild(leaderboardText);
game.addChild(btnLeaderboardClose);
// Leaderboard storage setup
var leaderboard = storage; // Use storage as leaderboard for getTop/submit
// Leaderboard button logic
btnLeaderboard.down = function (x, y, obj) {
// Show leaderboard UI, but do NOT auto-close after click
titleText.visible = false;
btnNewGame.visible = false;
btnContinue.visible = false;
btnLeaderboard.visible = false;
btnLang.visible = false;
continueNightText.visible = false;
leaderboardText.visible = true;
btnLeaderboardClose.visible = true;
// Fetch and show leaderboard (sadece en yüksek skor gösterilecek)
var text = languages[currentLangIndex].code === 'en' ? 'LEADERBOARD\n' : 'SKOR TABLOSU\n';
var leaderboardFlat = storage.leaderboardEntries || [];
if (leaderboardFlat.length < 2 || typeof leaderboardFlat[1] !== "number" || leaderboardFlat[1] === 0) {
// No score yet, show "Gece içinde" or "Night in progress"
text += languages[currentLangIndex].code === 'en' ? 'Night in progress' : 'Gece içinde';
} else {
var name = typeof leaderboardFlat[0] === "string" ? leaderboardFlat[0] : "Anonim";
var score = leaderboardFlat[1];
text += '1. ' + name + ' - ' + score + '\n';
}
leaderboardText.setText(text);
// Do not close leaderboard automatically; user must press KAPAT
// (No code here to auto-close or hide leaderboard)
};
// Leaderboard close button logic
btnLeaderboardClose.down = function (x, y, obj) {
leaderboardText.visible = false;
btnLeaderboardClose.visible = false;
showMenu();
};
// Add night info and test UI
game.addChild(nightText);
game.addChild(hourText);
game.addChild(btnEndNight);
game.addChild(sixText);
// Hide all except menu
function showMenu() {
state = STATE_MENU;
titleText.visible = true;
btnNewGame.visible = true;
btnLang.visible = true;
btnContinue.visible = true;
btnLeaderboard.visible = true;
continueNightText.visible = true;
nightText.visible = false;
hourText.visible = false;
btnEndNight.visible = false;
sixText.visible = false;
menuSelected = 0;
btnNewGame.setActive(true);
btnContinue.setActive(false);
updateContinueNight();
// Set menu button texts to correct language
if (languages[currentLangIndex].code === 'en') {
// titleText.setText('FNAF : FINISH THE NIGHT');
btnNewGame.setText('NEW GAME');
btnContinue.setText('CONTINUE');
btnEndNight.setText('FINISH NIGHT');
} else {
// titleText.setText('FNAF : GECEYİ BİTİR');
btnNewGame.setText('YENİ OYUN');
btnContinue.setText('DEVAM ET');
btnEndNight.setText('GECEYİ BİTİR');
}
// Do not change titleText here; always English
// Show animatronic in menu
animatronic.visible = true;
// Show VHS static overlay in menu
vhsStatic.visible = true;
// Play looping menu music
LK.playMusic('musicId', {
loop: true
});
}
function showNight() {
state = STATE_PLAY;
titleText.visible = false;
btnNewGame.visible = false;
btnLang.visible = false;
btnContinue.visible = false;
continueNightText.visible = false;
btnLeaderboard.visible = false;
nightText.visible = true;
hourText.visible = true;
btnEndNight.visible = true;
sixText.visible = false;
// Hide VHS static overlay during gameplay
vhsStatic.visible = false;
// Stop menu music
LK.stopMusic();
// Set night and hour text
if (languages[currentLangIndex].code === 'en') {
nightText.setText('NIGHT ' + currentNight);
} else {
nightText.setText('GECE ' + currentNight);
}
hourText.setText(currentHour + ':00');
nightText.alpha = 0;
hourText.alpha = 0;
// Animate in
tween(nightText, {
alpha: 1
}, {
duration: 400,
easing: tween.cubicOut
});
tween(hourText, {
alpha: 1
}, {
duration: 400,
easing: tween.cubicOut
});
// Animatronic: look at player, jaw closed
animatronic.animateJaw(0);
animatronic.animateTilt(0);
// Hide animatronic during gameplay
animatronic.visible = false;
}
function showNightEnd() {
state = STATE_NIGHTEND;
titleText.visible = false;
btnNewGame.visible = false;
btnLang.visible = false;
btnContinue.visible = false;
continueNightText.visible = false;
btnLeaderboard.visible = false;
nightText.visible = false;
hourText.visible = false;
btnEndNight.visible = false;
sixText.visible = true;
sixText.alpha = 0;
// Hide VHS static overlay during night end
vhsStatic.visible = false;
// Stop menu music
LK.stopMusic();
tween(sixText, {
alpha: 1
}, {
duration: 600,
easing: tween.cubicOut
});
// Animatronic: jaw open, head tilt
animatronic.animateJaw(1);
animatronic.animateTilt(1);
// Hide animatronic in night end
animatronic.visible = false;
// Skoru leaderboard'a gönder (en yüksek gece)
// Sadece hesabın en yüksek skorunu sakla
var leaderboardFlat = storage.leaderboardEntries || [];
var maxScore = 0;
for (var i = 0; i < leaderboardFlat.length; i += 2) {
var score = typeof leaderboardFlat[i + 1] === "number" ? leaderboardFlat[i + 1] : 0;
if (score > maxScore) maxScore = score;
}
var newScore = currentNight - 1;
if (newScore > maxScore) {
// Replace with new high score
storage.leaderboardEntries = ['Anonim', newScore];
} else if (leaderboardFlat.length === 0) {
// No previous score, store this one
storage.leaderboardEntries = ['Anonim', newScore];
} else {
// Keep the previous high score
storage.leaderboardEntries = ['Anonim', maxScore];
}
// Geceyi geçince geceyi yükselt
currentNight += 1;
// Reduce waiting period for btnEndNight: -120ms per night until 6, then 40% reduction per night, min 500ms
if (currentNight <= 7) {
btnEndNightWaitPeriod = Math.max(500, btnEndNightWaitPeriod - 120);
} else {
btnEndNightWaitPeriod = Math.max(500, Math.floor(btnEndNightWaitPeriod * 0.6));
}
}
// Update continue night text
function updateContinueNight() {
continueNightText.setText('gece ' + currentNight);
}
// Menu button touch logic
btnNewGame.down = function (x, y, obj) {
menuSelected = 0;
btnNewGame.setActive(true);
btnContinue.setActive(false);
// Start new game
currentNight = 1;
currentHour = 12;
showNight();
};
// Language selection logic
var languages = [{
code: 'tr',
label: 'Türkçe'
}, {
code: 'en',
label: 'English'
}];
var currentLangIndex = 0;
btnLang.down = function (x, y, obj) {
currentLangIndex = (currentLangIndex + 1) % languages.length;
btnLang.setText('DİL: ' + languages[currentLangIndex].label);
// Update menu button texts based on language
if (languages[currentLangIndex].code === 'en') {
// titleText.setText('FNAF : FINISH THE NIGHT');
btnNewGame.setText('NEW GAME');
btnContinue.setText('CONTINUE');
btnEndNight.setText('FINISH NIGHT');
} else {
// titleText.setText('FNAF : GECEYİ BİTİR');
btnNewGame.setText('YENİ OYUN');
btnContinue.setText('DEVAM ET');
btnEndNight.setText('GECEYİ BİTİR');
}
// Do not change titleText here; always English
// Here you could add logic to update all UI text if you implement localization
};
btnContinue.down = function (x, y, obj) {
menuSelected = 1;
btnNewGame.setActive(false);
btnContinue.setActive(true);
// Continue game
currentHour = 12;
showNight();
};
// Track waiting state and timer for btnEndNight
var btnEndNightPressCount = 0;
var btnEndNightWaitTimeout = null;
var btnEndNightWaiting = false;
// Waiting period for btnEndNight (in ms), decreases each night, min 500ms
var btnEndNightWaitPeriod = 1200;
btnEndNight.down = function (x, y, obj) {
if (!btnEndNightWaiting) {
// First press: start waiting period
btnEndNightWaiting = true;
btnEndNightPressCount = 1;
// Start a timer (decreasing period)
btnEndNightWaitTimeout = LK.setTimeout(function () {
// If timer expires and no second press, trigger jump scare/game over
if (btnEndNightWaiting && btnEndNightPressCount === 1) {
// Play jump scare sound
var jumpscareSound = LK.getSound('jumpscare');
if (jumpscareSound) {
jumpscareSound.play();
} else {
// Defensive: always try to play jumpscare sound
var jumpscareSound2 = LK.getSound('jumpscare');
if (jumpscareSound2) jumpscareSound2.play();
}
// Flash screen red for 1 second to indicate death
LK.effects.flashScreen(0xff0000, 1000);
// Show animatronic jumpscare in the center of the screen
var jumpscareAnim = new Animatronic();
jumpscareAnim.baseX = 2048 / 2 - 700 * animatronicScale / 2;
jumpscareAnim.baseY = 2732 / 2 - 500 * animatronicScale / 2 - 100;
jumpscareAnim.x = jumpscareAnim.baseX;
jumpscareAnim.y = jumpscareAnim.baseY;
jumpscareAnim.scaleX = animatronicScale * 1.25;
jumpscareAnim.scaleY = animatronicScale * 1.25;
jumpscareAnim.visible = true;
game.addChild(jumpscareAnim);
// Animate jaw open and head forward for jumpscare
jumpscareAnim.animateJaw(1);
jumpscareAnim.animateTilt(0);
// Show localized game over text in the center of the screen
var gameOverText = new Text2(languages[currentLangIndex].code === 'en' ? 'GAME OVER' : 'OYUN BİTTİ', {
size: 220,
fill: 0xFF0000
});
gameOverText.anchor.set(0.5, 0.5);
gameOverText.x = 2048 / 2;
gameOverText.y = 2732 / 2 + 400;
game.addChild(gameOverText);
// After 1.2s, remove jumpscare and text, then return to menu (no extra 'Game Over'/'Oyun Bitti' text)
LK.setTimeout(function () {
if (gameOverText && gameOverText.parent) {
gameOverText.parent.removeChild(gameOverText);
}
if (jumpscareAnim && jumpscareAnim.parent) {
jumpscareAnim.parent.removeChild(jumpscareAnim);
}
showMenu();
// Reset for next night
currentNight = 1; // Gece sıfırla (reset nights on death)
btnEndNightPressCount = 0;
btnEndNightWaiting = false;
btnEndNightWaitTimeout = null;
}, 1200);
}
// Reset waiting state if not already reset
btnEndNightWaiting = false;
btnEndNightWaitTimeout = null;
}, 1200);
} else if (btnEndNightWaiting && btnEndNightPressCount === 1) {
// Second press during waiting: pass the night
btnEndNightPressCount = 2;
// Cancel the jump scare timer
if (btnEndNightWaitTimeout !== null) {
LK.clearTimeout(btnEndNightWaitTimeout);
btnEndNightWaitTimeout = null;
}
btnEndNightWaiting = false;
// End night, show 6:00
showNightEnd();
// After 2s, return to menu
LK.setTimeout(function () {
showMenu();
// Reset for next night
btnEndNightPressCount = 0;
}, 2000);
}
};
// Touch navigation for menu (disable all except button areas)
game.down = function (x, y, obj) {
// Only allow button interactions, do nothing here
return;
};
// Touch up: disable all except button areas
game.up = function (x, y, obj) {
// Only allow button interactions, do nothing here
return;
};
// Animate animatronic idle (jaw open/close, head tilt)
var animTimer = 0;
function animatronicIdleAnim() {
if (state !== STATE_MENU && state !== STATE_PLAY) return;
animTimer++;
if (animTimer % 90 === 0) {
// Open jaw
animatronic.animateJaw(1);
} else if (animTimer % 90 === 30) {
// Close jaw
animatronic.animateJaw(0);
}
if (animTimer % 180 === 0) {
// Tilt head randomly
var tilt = [-1, 0, 1][Math.floor(Math.random() * 3)];
animatronic.animateTilt(tilt);
}
}
// VHS static overlay always on top
game.children.sort(function (a, b) {
if (a === vhsStatic) return 1;
if (b === vhsStatic) return -1;
return 0;
});
// Main update
game.update = function () {
animatronic.update();
vhsStatic.update();
animatronicIdleAnim();
};
// Start at menu
showMenu(); /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// Animatronic class
var Animatronic = Container.expand(function () {
var self = Container.call(this);
// Add animatronic body (behind jaw and head)
var body = self.attachAsset('animatronicBody', {
anchorX: 0.5,
anchorY: 0,
x: 350,
y: 570
});
// Jaw (behind head)
var jaw = self.attachAsset('animatronicJaw', {
anchorX: 0.5,
anchorY: 0,
x: 350,
y: 400
});
// Head (in front of jaw)
var head = self.attachAsset('animatronicHead', {
anchorX: 0.5,
anchorY: 0.5,
x: 350,
y: 250
});
// (Eyes, pupils, and nose removed)
// State
self.jawOpen = 0; // 0 closed, 1 open
self.headTilt = 0; // -1 left, 0 center, 1 right
self.glitchTimer = 0;
self.glitching = false;
self.glitchState = 0;
self.glitchDuration = 0;
self.glitchCooldown = 0;
// Helper: set pose
self.setPose = function (jawOpen, headTilt) {
self.jawOpen = jawOpen;
self.headTilt = headTilt;
// Jaw open/close
jaw.y = 400 + 60 * jawOpen;
// Head tilt
head.rotation = headTilt * 0.12;
// (Ears removed)
// (Eyes, pupils, and nose removed)
};
// Helper: set pupils offset (for glitch)
self.setPupilOffset = function (dx, dy) {
// (Pupil offset removed)
};
// Helper: set head position offset (for glitch)
self.setHeadOffset = function (dx, dy) {
self.x = self.baseX + dx;
self.y = self.baseY + dy;
};
// Helper: reset all offsets
self.resetOffsets = function () {
self.setHeadOffset(0, 0);
};
// Animate jaw open/close
self.animateJaw = function (open) {
tween(self, {
jawOpen: open
}, {
duration: 180,
easing: tween.cubicInOut
});
};
// Animate head tilt
self.animateTilt = function (target) {
tween(self, {
headTilt: target
}, {
duration: 220,
easing: tween.cubicInOut
});
};
// Glitch effect: random pose, random offset, short duration
self.triggerGlitch = function () {
self.glitching = true;
self.glitchState = Math.floor(Math.random() * 3);
self.glitchDuration = 6 + Math.floor(Math.random() * 6); // 6-12 frames
self.glitchCooldown = 30 + Math.floor(Math.random() * 60); // 0.5-1.5s
// Random pose
var jaw = Math.random() > 0.5 ? 1 : 0;
var tilt = [-1, 0, 1][Math.floor(Math.random() * 3)];
self.setPose(jaw, tilt);
// Random offset
var dx = -10 + Math.random() * 20;
var dy = -10 + Math.random() * 20;
self.setHeadOffset(dx, dy);
// (Random pupils removed)
};
// Update
self.update = function () {
// Animate jaw and tilt
self.setPose(self.jawOpen, self.headTilt);
// Glitch logic
if (self.glitching) {
self.glitchDuration--;
if (self.glitchDuration <= 0) {
self.glitching = false;
self.resetOffsets();
}
} else {
self.glitchCooldown--;
if (self.glitchCooldown <= 0) {
self.triggerGlitch();
}
}
};
// For centering
self.baseX = 0;
self.baseY = 0;
return self;
});
// Button class
var MenuButton = Container.expand(function () {
var self = Container.call(this);
var bg = self.attachAsset('buttonRect', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0
});
bg.alpha = 0.0;
self.label = new Text2('', {
size: 80,
fill: 0xFFFFFF
});
self.label.anchor.set(0.5, 0.5);
self.addChild(self.label);
self.setText = function (txt) {
self.label.setText(txt);
};
self.setActive = function (active) {
bg.alpha = 0.0;
self.label.alpha = active ? 1 : 0.7;
};
return self;
});
// VHS Static overlay class
var VHSStatic = Container.expand(function () {
var self = Container.call(this);
var staticNode = self.attachAsset('vhsStatic', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
});
staticNode.alpha = 0.08;
// Add horizontal noise lines
var noiseLines = [];
for (var i = 0; i < 8; i++) {
var line = self.attachAsset('vhsStatic', {
anchorX: 0,
anchorY: 0,
x: 0,
y: Math.random() * 2732,
width: 2048,
height: 8,
color: 0xffffff
});
line.alpha = 0.08 + Math.random() * 0.10;
noiseLines.push(line);
}
self.update = function () {
// Animate static flicker
staticNode.alpha = 0.06 + Math.random() * 0.10;
// Animate noise lines: randomize y and alpha for each line
for (var i = 0; i < noiseLines.length; i++) {
var line = noiseLines[i];
// Move line vertically, wrap around
line.y += 32 + Math.random() * 32;
if (line.y > 2732) line.y = -8;
// Flicker alpha
line.alpha = 0.08 + Math.random() * 0.12;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Button shape
// VHS static overlay
// Animatronic nose
// Animatronic right ear
// Animatronic left ear
// Animatronic right pupil
// Animatronic left pupil
// Animatronic right eye
// Animatronic left eye
// Animatronic jaw
// Animatronic body (main head)
// Game state
var STATE_MENU = 0;
var STATE_PLAY = 1;
var STATE_NIGHTEND = 2;
var state = STATE_MENU;
// Night and hour
var currentNight = 1;
var currentHour = 12;
// Animatronic
var animatronic = new Animatronic();
// Kuklanın tüm parçalarını biraz küçült ve daha yukarı taşı
var animatronicScale = 1.25; // daha küçük
// Head asset is 700px wide, 500px tall, so center based on that
animatronic.baseX = 2048 / 2 - 700 * animatronicScale / 2;
// Daha yukarı taşı: 420 yerine 700 px yukarıda
animatronic.baseY = 2732 - 500 * animatronicScale - 700;
animatronic.x = animatronic.baseX;
animatronic.y = animatronic.baseY;
animatronic.scaleX = animatronicScale;
animatronic.scaleY = animatronicScale;
game.addChild(animatronic);
// VHS static overlay
var vhsStatic = new VHSStatic();
game.addChild(vhsStatic);
// Menu UI
var titleText = new Text2('', {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0);
titleText.x = 2048 / 2;
titleText.y = 220;
// Set initial title text to English regardless of language
titleText.setText('FNAF : FINISH THE NIGHT');
var btnNewGame = new MenuButton();
btnNewGame.x = 2048 / 2;
btnNewGame.y = 600;
btnNewGame.setText('YENİ OYUN');
var btnContinue = new MenuButton();
btnContinue.x = 2048 / 2;
btnContinue.y = 800;
btnContinue.setText('DEVAM ET');
// Leaderboard button
var btnLeaderboard = new MenuButton();
// Move to left side, but not in the top left 100x100 area (avoid platform menu)
// Place at x=400, y=1000 (moved right from 200 to 400)
btnLeaderboard.x = 400;
btnLeaderboard.y = 1000;
btnLeaderboard.setText('SKOR TABLOSU');
// Language select button (now below continue)
var btnLang = new MenuButton();
btnLang.x = 2048 / 2;
// Calculate vertical gap between continue and new game buttons
var menuButtonGap = btnContinue.y - btnNewGame.y;
// Place language button the same gap below continue button
btnLang.y = btnContinue.y + menuButtonGap;
btnLang.setText('DİL: Türkçe');
var continueNightText = new Text2('', {
size: 38,
fill: 0xFFFFFF
});
continueNightText.anchor.set(0, 0.5);
continueNightText.x = btnContinue.x + 380;
continueNightText.y = btnContinue.y;
// Leaderboard UI
var leaderboardText = new Text2('', {
size: 60,
fill: 0xFFFF00
});
leaderboardText.anchor.set(0.5, 0);
leaderboardText.x = 2048 / 2;
leaderboardText.y = 300;
leaderboardText.visible = false;
// Leaderboard close button
var btnLeaderboardClose = new MenuButton();
btnLeaderboardClose.x = 2048 / 2;
btnLeaderboardClose.y = 2200;
btnLeaderboardClose.setText('KAPAT');
btnLeaderboardClose.visible = false;
// Menu selection
var menuSelected = 0; // 0: new game, 1: continue
// Night info UI
var nightText = new Text2('', {
size: 110,
fill: 0xFFFFFF
});
nightText.anchor.set(0.5, 0.5);
nightText.x = 2048 / 2;
nightText.y = 400;
nightText.alpha = 0;
var hourText = new Text2('', {
size: 90,
fill: 0xFFFFFF
});
hourText.anchor.set(0.5, 0.5);
hourText.x = 2048 / 2;
hourText.y = 540;
hourText.alpha = 0;
// Test: End night button
var btnEndNight = new MenuButton();
btnEndNight.x = 2048 / 2;
btnEndNight.y = 1200;
btnEndNight.setText('GECEYİ BİTİR');
btnEndNight.visible = false;
// 6:00 screen
var sixText = new Text2('06:00', {
size: 180,
fill: 0xFFFFFF
});
sixText.anchor.set(0.5, 0.5);
sixText.x = 2048 / 2;
sixText.y = 700;
sixText.alpha = 0;
// Add menu UI to game
game.addChild(titleText);
game.addChild(btnNewGame);
game.addChild(btnContinue);
game.addChild(btnLeaderboard);
game.addChild(btnLang);
game.addChild(continueNightText);
game.addChild(leaderboardText);
game.addChild(btnLeaderboardClose);
// Leaderboard storage setup
var leaderboard = storage; // Use storage as leaderboard for getTop/submit
// Leaderboard button logic
btnLeaderboard.down = function (x, y, obj) {
// Show leaderboard UI, but do NOT auto-close after click
titleText.visible = false;
btnNewGame.visible = false;
btnContinue.visible = false;
btnLeaderboard.visible = false;
btnLang.visible = false;
continueNightText.visible = false;
leaderboardText.visible = true;
btnLeaderboardClose.visible = true;
// Fetch and show leaderboard (sadece en yüksek skor gösterilecek)
var text = languages[currentLangIndex].code === 'en' ? 'LEADERBOARD\n' : 'SKOR TABLOSU\n';
var leaderboardFlat = storage.leaderboardEntries || [];
if (leaderboardFlat.length < 2 || typeof leaderboardFlat[1] !== "number" || leaderboardFlat[1] === 0) {
// No score yet, show "Gece içinde" or "Night in progress"
text += languages[currentLangIndex].code === 'en' ? 'Night in progress' : 'Gece içinde';
} else {
var name = typeof leaderboardFlat[0] === "string" ? leaderboardFlat[0] : "Anonim";
var score = leaderboardFlat[1];
text += '1. ' + name + ' - ' + score + '\n';
}
leaderboardText.setText(text);
// Do not close leaderboard automatically; user must press KAPAT
// (No code here to auto-close or hide leaderboard)
};
// Leaderboard close button logic
btnLeaderboardClose.down = function (x, y, obj) {
leaderboardText.visible = false;
btnLeaderboardClose.visible = false;
showMenu();
};
// Add night info and test UI
game.addChild(nightText);
game.addChild(hourText);
game.addChild(btnEndNight);
game.addChild(sixText);
// Hide all except menu
function showMenu() {
state = STATE_MENU;
titleText.visible = true;
btnNewGame.visible = true;
btnLang.visible = true;
btnContinue.visible = true;
btnLeaderboard.visible = true;
continueNightText.visible = true;
nightText.visible = false;
hourText.visible = false;
btnEndNight.visible = false;
sixText.visible = false;
menuSelected = 0;
btnNewGame.setActive(true);
btnContinue.setActive(false);
updateContinueNight();
// Set menu button texts to correct language
if (languages[currentLangIndex].code === 'en') {
// titleText.setText('FNAF : FINISH THE NIGHT');
btnNewGame.setText('NEW GAME');
btnContinue.setText('CONTINUE');
btnEndNight.setText('FINISH NIGHT');
} else {
// titleText.setText('FNAF : GECEYİ BİTİR');
btnNewGame.setText('YENİ OYUN');
btnContinue.setText('DEVAM ET');
btnEndNight.setText('GECEYİ BİTİR');
}
// Do not change titleText here; always English
// Show animatronic in menu
animatronic.visible = true;
// Show VHS static overlay in menu
vhsStatic.visible = true;
// Play looping menu music
LK.playMusic('musicId', {
loop: true
});
}
function showNight() {
state = STATE_PLAY;
titleText.visible = false;
btnNewGame.visible = false;
btnLang.visible = false;
btnContinue.visible = false;
continueNightText.visible = false;
btnLeaderboard.visible = false;
nightText.visible = true;
hourText.visible = true;
btnEndNight.visible = true;
sixText.visible = false;
// Hide VHS static overlay during gameplay
vhsStatic.visible = false;
// Stop menu music
LK.stopMusic();
// Set night and hour text
if (languages[currentLangIndex].code === 'en') {
nightText.setText('NIGHT ' + currentNight);
} else {
nightText.setText('GECE ' + currentNight);
}
hourText.setText(currentHour + ':00');
nightText.alpha = 0;
hourText.alpha = 0;
// Animate in
tween(nightText, {
alpha: 1
}, {
duration: 400,
easing: tween.cubicOut
});
tween(hourText, {
alpha: 1
}, {
duration: 400,
easing: tween.cubicOut
});
// Animatronic: look at player, jaw closed
animatronic.animateJaw(0);
animatronic.animateTilt(0);
// Hide animatronic during gameplay
animatronic.visible = false;
}
function showNightEnd() {
state = STATE_NIGHTEND;
titleText.visible = false;
btnNewGame.visible = false;
btnLang.visible = false;
btnContinue.visible = false;
continueNightText.visible = false;
btnLeaderboard.visible = false;
nightText.visible = false;
hourText.visible = false;
btnEndNight.visible = false;
sixText.visible = true;
sixText.alpha = 0;
// Hide VHS static overlay during night end
vhsStatic.visible = false;
// Stop menu music
LK.stopMusic();
tween(sixText, {
alpha: 1
}, {
duration: 600,
easing: tween.cubicOut
});
// Animatronic: jaw open, head tilt
animatronic.animateJaw(1);
animatronic.animateTilt(1);
// Hide animatronic in night end
animatronic.visible = false;
// Skoru leaderboard'a gönder (en yüksek gece)
// Sadece hesabın en yüksek skorunu sakla
var leaderboardFlat = storage.leaderboardEntries || [];
var maxScore = 0;
for (var i = 0; i < leaderboardFlat.length; i += 2) {
var score = typeof leaderboardFlat[i + 1] === "number" ? leaderboardFlat[i + 1] : 0;
if (score > maxScore) maxScore = score;
}
var newScore = currentNight - 1;
if (newScore > maxScore) {
// Replace with new high score
storage.leaderboardEntries = ['Anonim', newScore];
} else if (leaderboardFlat.length === 0) {
// No previous score, store this one
storage.leaderboardEntries = ['Anonim', newScore];
} else {
// Keep the previous high score
storage.leaderboardEntries = ['Anonim', maxScore];
}
// Geceyi geçince geceyi yükselt
currentNight += 1;
// Reduce waiting period for btnEndNight: -120ms per night until 6, then 40% reduction per night, min 500ms
if (currentNight <= 7) {
btnEndNightWaitPeriod = Math.max(500, btnEndNightWaitPeriod - 120);
} else {
btnEndNightWaitPeriod = Math.max(500, Math.floor(btnEndNightWaitPeriod * 0.6));
}
}
// Update continue night text
function updateContinueNight() {
continueNightText.setText('gece ' + currentNight);
}
// Menu button touch logic
btnNewGame.down = function (x, y, obj) {
menuSelected = 0;
btnNewGame.setActive(true);
btnContinue.setActive(false);
// Start new game
currentNight = 1;
currentHour = 12;
showNight();
};
// Language selection logic
var languages = [{
code: 'tr',
label: 'Türkçe'
}, {
code: 'en',
label: 'English'
}];
var currentLangIndex = 0;
btnLang.down = function (x, y, obj) {
currentLangIndex = (currentLangIndex + 1) % languages.length;
btnLang.setText('DİL: ' + languages[currentLangIndex].label);
// Update menu button texts based on language
if (languages[currentLangIndex].code === 'en') {
// titleText.setText('FNAF : FINISH THE NIGHT');
btnNewGame.setText('NEW GAME');
btnContinue.setText('CONTINUE');
btnEndNight.setText('FINISH NIGHT');
} else {
// titleText.setText('FNAF : GECEYİ BİTİR');
btnNewGame.setText('YENİ OYUN');
btnContinue.setText('DEVAM ET');
btnEndNight.setText('GECEYİ BİTİR');
}
// Do not change titleText here; always English
// Here you could add logic to update all UI text if you implement localization
};
btnContinue.down = function (x, y, obj) {
menuSelected = 1;
btnNewGame.setActive(false);
btnContinue.setActive(true);
// Continue game
currentHour = 12;
showNight();
};
// Track waiting state and timer for btnEndNight
var btnEndNightPressCount = 0;
var btnEndNightWaitTimeout = null;
var btnEndNightWaiting = false;
// Waiting period for btnEndNight (in ms), decreases each night, min 500ms
var btnEndNightWaitPeriod = 1200;
btnEndNight.down = function (x, y, obj) {
if (!btnEndNightWaiting) {
// First press: start waiting period
btnEndNightWaiting = true;
btnEndNightPressCount = 1;
// Start a timer (decreasing period)
btnEndNightWaitTimeout = LK.setTimeout(function () {
// If timer expires and no second press, trigger jump scare/game over
if (btnEndNightWaiting && btnEndNightPressCount === 1) {
// Play jump scare sound
var jumpscareSound = LK.getSound('jumpscare');
if (jumpscareSound) {
jumpscareSound.play();
} else {
// Defensive: always try to play jumpscare sound
var jumpscareSound2 = LK.getSound('jumpscare');
if (jumpscareSound2) jumpscareSound2.play();
}
// Flash screen red for 1 second to indicate death
LK.effects.flashScreen(0xff0000, 1000);
// Show animatronic jumpscare in the center of the screen
var jumpscareAnim = new Animatronic();
jumpscareAnim.baseX = 2048 / 2 - 700 * animatronicScale / 2;
jumpscareAnim.baseY = 2732 / 2 - 500 * animatronicScale / 2 - 100;
jumpscareAnim.x = jumpscareAnim.baseX;
jumpscareAnim.y = jumpscareAnim.baseY;
jumpscareAnim.scaleX = animatronicScale * 1.25;
jumpscareAnim.scaleY = animatronicScale * 1.25;
jumpscareAnim.visible = true;
game.addChild(jumpscareAnim);
// Animate jaw open and head forward for jumpscare
jumpscareAnim.animateJaw(1);
jumpscareAnim.animateTilt(0);
// Show localized game over text in the center of the screen
var gameOverText = new Text2(languages[currentLangIndex].code === 'en' ? 'GAME OVER' : 'OYUN BİTTİ', {
size: 220,
fill: 0xFF0000
});
gameOverText.anchor.set(0.5, 0.5);
gameOverText.x = 2048 / 2;
gameOverText.y = 2732 / 2 + 400;
game.addChild(gameOverText);
// After 1.2s, remove jumpscare and text, then return to menu (no extra 'Game Over'/'Oyun Bitti' text)
LK.setTimeout(function () {
if (gameOverText && gameOverText.parent) {
gameOverText.parent.removeChild(gameOverText);
}
if (jumpscareAnim && jumpscareAnim.parent) {
jumpscareAnim.parent.removeChild(jumpscareAnim);
}
showMenu();
// Reset for next night
currentNight = 1; // Gece sıfırla (reset nights on death)
btnEndNightPressCount = 0;
btnEndNightWaiting = false;
btnEndNightWaitTimeout = null;
}, 1200);
}
// Reset waiting state if not already reset
btnEndNightWaiting = false;
btnEndNightWaitTimeout = null;
}, 1200);
} else if (btnEndNightWaiting && btnEndNightPressCount === 1) {
// Second press during waiting: pass the night
btnEndNightPressCount = 2;
// Cancel the jump scare timer
if (btnEndNightWaitTimeout !== null) {
LK.clearTimeout(btnEndNightWaitTimeout);
btnEndNightWaitTimeout = null;
}
btnEndNightWaiting = false;
// End night, show 6:00
showNightEnd();
// After 2s, return to menu
LK.setTimeout(function () {
showMenu();
// Reset for next night
btnEndNightPressCount = 0;
}, 2000);
}
};
// Touch navigation for menu (disable all except button areas)
game.down = function (x, y, obj) {
// Only allow button interactions, do nothing here
return;
};
// Touch up: disable all except button areas
game.up = function (x, y, obj) {
// Only allow button interactions, do nothing here
return;
};
// Animate animatronic idle (jaw open/close, head tilt)
var animTimer = 0;
function animatronicIdleAnim() {
if (state !== STATE_MENU && state !== STATE_PLAY) return;
animTimer++;
if (animTimer % 90 === 0) {
// Open jaw
animatronic.animateJaw(1);
} else if (animTimer % 90 === 30) {
// Close jaw
animatronic.animateJaw(0);
}
if (animTimer % 180 === 0) {
// Tilt head randomly
var tilt = [-1, 0, 1][Math.floor(Math.random() * 3)];
animatronic.animateTilt(tilt);
}
}
// VHS static overlay always on top
game.children.sort(function (a, b) {
if (a === vhsStatic) return 1;
if (b === vhsStatic) return -1;
return 0;
});
// Main update
game.update = function () {
animatronic.update();
vhsStatic.update();
animatronicIdleAnim();
};
// Start at menu
showMenu();