THE LAST WATCH
by LunarPanda23426 lines23.1 KB
<!DOCTYPE html>
<html lang="he" dir="rtl">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<title>THE LAST WATCH</title>
<style>
:root{--green:#a5ffc1;--red:#ff354d;--gold:#f0c77b;--panel:#101714}
*{box-sizing:border-box}
html,body{margin:0;width:100%;height:100%;overflow:hidden;background:#020403;color:#e8eee9;font-family:Arial,sans-serif}
button{font:inherit;color:#f4f6f2;background:linear-gradient(#29352e,#101510);border:1px solid #68796b;border-radius:5px;padding:9px 12px;cursor:pointer;touch-action:manipulation}
button:active{transform:scale(.97)}
button:disabled{opacity:.35}
#game{position:relative;width:100%;height:100vh;height:100dvh;min-height:0;overflow:hidden;background:#030605}
#room{position:absolute;inset:0;overflow:hidden;background:radial-gradient(ellipse at 50% 38%,#354038 0,#151d18 44%,#020403 100%)}
.wall{position:absolute;left:13%;right:13%;top:0;height:65%;background:linear-gradient(90deg,#111814,#29332b 50%,#101612);clip-path:polygon(8% 0,92% 0,100% 100%,0 100%)}
.poster{position:absolute;top:15%;width:13%;height:19%;border:5px solid #161d17;background:linear-gradient(140deg,#444c3d,#101510);display:grid;place-items:center;text-align:center;color:#b6c3a6;font-size:clamp(9px,1.4vw,16px);font-weight:bold;box-shadow:0 0 20px #000}
.p1{left:23%}.p2{right:23%}
.floor{position:absolute;bottom:0;left:0;right:0;height:37%;background:linear-gradient(#151c17,#030504);clip-path:polygon(20% 0,80% 0,100% 100%,0 100%)}
.desk{position:absolute;left:17%;right:17%;bottom:-5%;height:31%;background:linear-gradient(#444e42,#242c25 22%,#080b09 55%);clip-path:polygon(6% 0,94% 0,100% 100%,0 100%);border-top:5px solid #64715b}
.monitor{position:absolute;bottom:22%;left:39%;width:22%;height:20%;background:linear-gradient(145deg,#1a2b24,#050a07);border:5px solid #080b09;box-shadow:0 0 18px #8bffc31a}
.monitor:after{content:"SECURITY SYSTEM";position:absolute;inset:0;display:grid;place-items:center;color:#7b9d84;font-size:clamp(7px,1vw,12px);letter-spacing:2px}
.fan{position:absolute;bottom:24%;left:47%;width:6%;aspect-ratio:1;border:3px solid #5b6557;border-radius:50%;animation:spin 2.8s linear infinite}
.fan:before{content:"";position:absolute;inset:10%;background:conic-gradient(transparent 0 10%,#87917d 10% 25%,transparent 25% 43%,#87917d 43% 58%,transparent 58% 76%,#87917d 76% 90%,transparent 90%);border-radius:50%}
@keyframes spin{to{transform:rotate(360deg)}}
.side{position:absolute;top:15%;height:58%;width:17%;display:flex;align-items:stretch;gap:5px;direction:ltr}
.side.west{left:0}.side.east{right:0}
.door{position:relative;width:58%;height:82%;align-self:center;background:linear-gradient(90deg,#050806,#202820,#080b09);border:5px solid #343e34;box-shadow:inset 0 0 18px #000}
.door.closed:after{content:"";position:absolute;inset:0;background:repeating-linear-gradient(0deg,#141c16 0 30px,#354035 31px 34px);border:3px solid #78806a;box-shadow:0 0 18px #000}
.window{position:relative;align-self:center;width:36%;height:44%;background:#020503;border:4px solid #4b5747;overflow:hidden;box-shadow:inset 0 0 20px #000}
.window:before{content:"";position:absolute;inset:0;background:linear-gradient(90deg,#080d09,#000);opacity:.85}
.window.lit{background:radial-gradient(ellipse,#d7dcad,#737b5a 38%,#151b12 85%);box-shadow:0 0 32px #c7d59b88}
.window.lit:before{opacity:.08}
.window .shadow{position:absolute;bottom:-8%;left:16%;width:70%;height:90%;background:#050705;clip-path:polygon(25% 0,75% 0,100% 35%,88% 100%,8% 100%,0 40%)}
.window.lit .shadow{background:#151b14}
.eye{position:absolute;top:27%;width:13%;height:7%;background:#e8f1a5;box-shadow:0 0 10px #efffa2}
.eye.a{left:34%}.eye.b{left:59%}
#leftCreature,#rightCreature{position:absolute;top:23%;height:45%;width:13%;display:none;z-index:5;filter:drop-shadow(0 0 18px #000)}
#leftCreature{left:2%}#rightCreature{right:2%}
#leftCreature.show,#rightCreature.show{display:block}
.monsterHead{position:absolute;top:0;left:8%;width:84%;height:58%;background:radial-gradient(ellipse at 50% 25%,#6c7560,#242b22 70%);border:4px solid #090c08;border-radius:45% 45% 30% 30%}
.monsterHead:before,.monsterHead:after{content:"";position:absolute;top:-14%;width:28%;height:28%;background:#353e30;clip-path:polygon(50% 0,100% 100%,0 80%)}
.monsterHead:before{left:0}.monsterHead:after{right:0}
.monsterEyes{position:absolute;top:32%;left:16%;right:16%;display:flex;justify-content:space-between}
.monsterEyes i{width:23%;height:10px;background:#ff3434;box-shadow:0 0 12px red}
.monsterMouth{position:absolute;bottom:10%;left:20%;right:20%;height:20%;border:3px solid #050605;background:repeating-linear-gradient(90deg,#d5d0ac 0 5px,#121612 6px 9px)}
.monsterBody{position:absolute;top:52%;left:20%;width:60%;height:55%;background:linear-gradient(90deg,#111610,#4c5746,#111610);border:3px solid #090b08}
#hud{position:absolute;top:8px;left:8px;right:8px;z-index:12;display:flex;justify-content:space-between;align-items:flex-start;gap:7px;pointer-events:none}
.hudbox{background:#050906dc;border:1px solid #4b5b4b;padding:7px 10px;min-width:0;font-size:clamp(10px,1.5vw,14px)}
#powerbar{height:7px;width:clamp(65px,12vw,140px);background:#29332a;margin-top:5px}
#powerfill{height:100%;width:100%;background:var(--green);transition:width .2s}
#usage{color:var(--gold);white-space:nowrap}
#status{color:var(--green);font-weight:bold}
#controls{position:absolute;bottom:10px;left:50%;transform:translateX(-50%);display:flex;justify-content:center;gap:7px;z-index:15;width:min(94%,650px)}
.control{flex:1;max-width:150px;min-width:0;min-height:45px;font-size:clamp(10px,1.7vw,14px);font-weight:bold}
.control.active{border-color:var(--green);background:linear-gradient(#466147,#17241a);box-shadow:0 0 12px #8dffad33}
#cameraToggle{position:absolute;bottom:72px;left:50%;transform:translateX(-50%);z-index:15;min-width:180px}
#cameras{position:absolute;inset:7% 4% 16%;z-index:20;background:#060a08f5;border:4px solid #52604f;padding:10px;display:none;flex-direction:column;gap:8px}
#cameras.open{display:flex}
#camTop{display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap}
#camTitle{color:var(--green);font-weight:bold;font-size:clamp(12px,2vw,19px)}
#camFeed{position:relative;flex:1;min-height:0;overflow:hidden;border:2px solid #38463a;background:radial-gradient(ellipse,#2d352c,#070a08 80%)}
#camFeed:after{content:"";pointer-events:none;position:absolute;inset:0;background:repeating-linear-gradient(0deg,transparent 0 3px,#fff1 4px),linear-gradient(90deg,#0006,transparent 25%,transparent 75%,#0006)}
#camArt{position:absolute;inset:0;display:grid;place-items:center;text-align:center;color:#7d907b;font-size:clamp(20px,5vw,55px);text-shadow:0 0 18px #a4ffb7}
#camDesc{position:absolute;bottom:8px;left:8px;right:8px;color:#dce7da;background:#000b;padding:7px;font-size:clamp(10px,1.5vw,14px);z-index:2}
#camButtons{display:flex;flex-wrap:wrap;gap:5px;justify-content:center}
.cam{padding:7px 10px;min-height:36px;font-size:12px}
.cam.active{border:2px solid var(--green);color:var(--green)}
#overlay,#ending,#scare{position:absolute;inset:0;z-index:40;display:flex;align-items:center;justify-content:center;background:#000e;padding:15px}
.menu,.endcard{width:min(540px,100%);max-height:92%;overflow:auto;background:linear-gradient(145deg,#17221a,#060907);border:2px solid #53664e;padding:clamp(18px,4vw,32px);text-align:center;box-shadow:0 0 45px #000}
.logo{font-size:clamp(25px,6vw,45px);font-weight:900;letter-spacing:3px;color:#c3d3b8;text-shadow:0 0 20px #b9ffbd33}
.subtitle{color:var(--gold);letter-spacing:2px;margin:8px}
.menu p,.endcard p{line-height:1.65;color:#c4cec3;font-size:14px}
.primary{background:linear-gradient(#57784e,#243d27);border:1px solid #b5d6a4;padding:13px 22px;font-weight:bold;margin:8px}
.note{font-size:11px!important;color:#859384!important}
#ending{display:none}
#scare{display:none;background:#020100;z-index:60;animation:flash .1s infinite}
#scare.show{display:flex}
.scareFace{position:relative;width:min(75vw,440px);aspect-ratio:1;border-radius:45% 45% 35% 35%;background:radial-gradient(ellipse,#a4a88a,#404735 60%,#050705 80%);border:12px solid #080a06;box-shadow:0 0 70px #f00}
.scareFace:before{content:"";position:absolute;top:13%;left:10%;right:10%;height:23%;background:#030403;clip-path:polygon(0 0,100% 0,80% 100%,20% 100%)}
.scareEyes{position:absolute;top:30%;left:17%;right:17%;display:flex;justify-content:space-between}
.scareEyes i{width:25%;height:clamp(15px,5vw,36px);background:#ff1717;box-shadow:0 0 28px red}
.scareMouth{position:absolute;left:18%;right:18%;bottom:12%;height:25%;border:8px solid #080a06;background:repeating-linear-gradient(90deg,#e5dfc4 0 12px,#090a07 13px 18px)}
@keyframes flash{0%,100%{filter:brightness(1)}50%{filter:brightness(.45)}}
#blackout{position:absolute;inset:0;z-index:30;background:#000;display:none;align-items:center;justify-content:center;text-align:center;padding:20px}
#blackout.show{display:flex}
#blackoutText{color:#a8b0a1;font-size:clamp(17px,4vw,30px);line-height:1.8}
#rareText{font-size:11px;color:#7b8678}
@media(max-width:550px){
.side{width:23%;top:19%;height:52%}.door{width:59%;height:78%;border-width:3px}.window{width:35%;height:39%;border-width:3px}
.wall{left:15%;right:15%;height:60%}.poster{top:21%;width:15%;height:15%}.p1{left:25%}.p2{right:25%}
.desk{left:15%;right:15%;height:27%}.monitor{bottom:18%;height:18%}.fan{bottom:20%}
#controls{bottom:5px;gap:4px;width:98%}.control{padding:6px 3px;min-height:42px}
#cameraToggle{bottom:56px;min-width:150px;padding:7px}
#cameras{inset:5% 2% 13%;padding:6px;gap:5px}
.cam{padding:6px 8px;min-height:32px}
}
@media(max-height:500px){
#hud{top:3px;left:4px;right:4px}.hudbox{padding:4px 7px}
.side{top:13%;height:57%}.desk{height:27%}
#controls{bottom:3px}.control{min-height:34px;padding:4px}
#cameraToggle{bottom:43px;padding:5px}
#cameras{inset:4% 4% 12%}
}
</style>
</head>
<body>
<div id="game">
<div id="room">
<div class="wall"></div>
<div class="poster p1">โ
<br>CELEBRATE<br>TONIGHT</div>
<div class="poster p2">โซ<br>THE LAST<br>SHOW</div>
<div class="floor"></div>
<div class="side west">
<div class="door" id="leftDoor"></div>
<div class="window" id="leftWindow"><div class="shadow"></div><i class="eye a"></i><i class="eye b"></i></div>
</div>
<div class="side east">
<div class="window" id="rightWindow"><div class="shadow"></div><i class="eye a"></i><i class="eye b"></i></div>
<div class="door" id="rightDoor"></div>
</div>
<div id="leftCreature"><div class="monsterHead"><div class="monsterEyes"><i></i><i></i></div><div class="monsterMouth"></div></div><div class="monsterBody"></div></div>
<div id="rightCreature"><div class="monsterHead"><div class="monsterEyes"><i></i><i></i></div><div class="monsterMouth"></div></div><div class="monsterBody"></div></div>
<div class="desk"></div><div class="monitor"></div><div class="fan"></div>
</div>
<div id="hud">
<div class="hudbox"><div>POWER <b id="power">100</b>%</div><div id="powerbar"><div id="powerfill"></div></div></div>
<div class="hudbox"><div id="nightLabel">NIGHT 1</div><div id="hourLabel">12 AM</div></div>
<div class="hudbox"><div id="usage">USAGE โฎ</div><div id="status">SYSTEM NORMAL</div></div>
</div>
<button id="cameraToggle">โฃ ืคืชืืืช ืืฆืืืืช</button>
<div id="controls">
<button class="control" id="lLight">โ ืืืจ ืฉืืื</button>
<button class="control" id="lDoor">โฅ ืืืช ืฉืืื</button>
<button class="control" id="rDoor">ืืืช ืืืื โฅ</button>
<button class="control" id="rLight">ืืืจ ืืืื โ</button>
</div>
<div id="cameras">
<div id="camTop"><div id="camTitle">CAM 1A โ SHOW STAGE</div><button id="closeCam">โ ืืืจื ืืืฉืจื</button></div>
<div id="camFeed"><div id="camArt">โ</div><div id="camDesc">ืืชืืื ื ืจืืขืฉืช. ืืืงื ืืช ืืืืจืื ืืืืืจืืช.</div></div>
<div id="camButtons">
<button class="cam active" data-cam="1A">1A ืืื</button>
<button class="cam" data-cam="1B">1B ืืืื</button>
<button class="cam" data-cam="1C">1C ืืืกื</button>
<button class="cam" data-cam="2A">2A ืืกืืจืื ืฉืืื</button>
<button class="cam" data-cam="2B">2B ืืกืืจืื ืืืื</button>
<button class="cam" data-cam="3">3 ืืืจ ืืกืคืงื</button>
<button class="cam" data-cam="4A">4A ืคืื ื ืฉืืื</button>
<button class="cam" data-cam="4B">4B ืคืื ื ืืืื</button>
</div>
</div>
<div id="blackout"><div id="blackoutText">ืืืฉืื ื ืืชืง...<br><span style="font-size:.65em">ืืฉืื ืื ืืืืฉื.</span></div></div>
<div id="scare"><div class="scareFace"><div class="scareEyes"><i></i><i></i></div><div class="scareMouth"></div></div></div>
<div id="overlay">
<div class="menu">
<div class="logo">THE LAST WATCH</div>
<div class="subtitle">NIGHT SECURITY ยท SURVIVE UNTIL 6 AM</div>
<p>ืืชื ืฉืืืจืื ืขื ืืืื ืืืคืขืืช ื ืืืฉ. ืืืงื ืืฆืืืืช, ืืืืื ื ืืฆืืืืื ืืืฉืชืืฉื ืืืืจืืช ืืืืืชืืช ืจืง ืืฉืฆืจืื.</p>
<p><b>ืืืื ืจืืฉืื ืงื ืืืืืื.</b><br>ืืื ืืืื ืืืฉ ืืกืื ื ืขืืื ืืืืจืื. ืืืคืืฆืช ืืืืืจื ืืืคืืขื ืจืง ืืืืืืช 4โ5. ืืฉืืื ืื: ืืฉ ืืฉืื ืฉืืืื ืืืื ืื ืชืจืื ืืืฉืืง ืจืืื.</p>
<button class="primary" id="start">ืืชืื ืืืื 1</button>
<p class="note">WASD ืื ื ืืจืฉ. ืืคืฉืจ ืืฉืืง ืขื ืืืคืชืืจืื ืื ืขื ืืืงืืืช: Q/A ืฉืืื, E/D ืืืื, ืจืืื ืืืฆืืืืช.</p>
</div>
</div>
<div id="ending"><div class="endcard"><div class="logo" id="endTitle">6 AM</div><p id="endText"></p><button class="primary" id="nextNight">ืืืฉื ืืืืื ืืื</button><button id="restart">ืืชืื ืืืืฉ</button></div></div>
</div>
<script>
(()=>{
const $=id=>document.getElementById(id);
let night=1,running=false,ended=false,power=100,elapsed=0,last=0,hour=0;
let camOpen=false,outage=false,selectedCam='1A',blackoutTimer=0,rareChecked=false;
let doors={left:false,right:false},lights={left:false,right:false};
let audio=null,scareTimer=0,nightStartPower=100;
const cameraNames={
'1A':'SHOW STAGE','1B':'DINING AREA','1C':'SUPPLY STORAGE',
'2A':'WEST HALL','2B':'EAST HALL','3':'SUPPLY ROOM',
'4A':'WEST CORNER','4B':'EAST CORNER'
};
const cameraDescriptions={
'1A':'ืืื ืืฉื ื. ืืืืืืื ืื ืืขื.',
'1B':'ืฉืืืื ืืช ืืืืกืืืช ืืคืืืื.',
'1C':'ืืืกื ืืฉืื ืขื ืฆืขืฆืืขืื ืฉืืืจืื.',
'2A':'ืืืกืืจืื ืฉืืืืื ืืืืช ืืฉืืืืืช.',
'2B':'ืืืกืืจืื ืฉืืืืื ืืืืช ืืืื ืืช.',
'3':'ืืจืืืื, ืืืคืื ืืจืขืฉ ืืืฉ.',
'4A':'ืืคืื ื ืืงืจืืื ืืื ืืกื ืืฉืืืืืช.',
'4B':'ืืคืื ื ืืงืจืืื ืืื ืืกื ืืืื ืืช.'
};
const enemies=[
{name:'THE WATCHER',side:'left',path:['1A','1B','3','2A','4A'],pos:0,t:0,door:false,activeFrom:1,base:34,attack:8},
{name:'THE GRINNER',side:'right',path:['1A','1B','2B','4B'],pos:0,t:0,door:false,activeFrom:2,base:40,attack:9},
{name:'THE RUNNER',side:'left',path:['1C','3','2A','4A'],pos:0,t:0,door:false,activeFrom:4,base:27,attack:5}
];
const rareMonster={name:'THE UNSEEN',checked:false};
function beep(freq=220,dur=.08,type='square',vol=.025){
try{
audio=audio||new(window.AudioContext||window.webkitAudioContext)();
if(audio.state==='suspended')audio.resume();
const o=audio.createOscillator(),g=audio.createGain();
o.type=type;o.frequency.value=freq;g.gain.value=vol;
o.connect(g);g.connect(audio.destination);o.start();
g.gain.exponentialRampToValueAtTime(.001,audio.currentTime+dur);o.stop(audio.currentTime+dur);
}catch(e){}
}
function status(s,c='var(--green)'){$('status').textContent=s;$('status').style.color=c}
function difficulty(){
// Only changes between nights, never between hours.
return [0.12,0.27,0.44,0.68,0.9][night-1]||0.9;
}
function resetEnemies(){
enemies.forEach(e=>{
e.pos=0;e.t=0;e.door=false;
e.rate=e.base*(1-difficulty()*.48);
});
}
function render(){
$('power').textContent=Math.ceil(power);
$('powerfill').style.width=Math.max(0,power)+'%';
$('powerfill').style.background=power<20?'var(--red)':power<45?'var(--gold)':'var(--green)';
const usage=1+Number(doors.left)+Number(doors.right)+Number(lights.left)+Number(lights.right)+Number(camOpen);
$('usage').textContent='USAGE '+'โฎ'.repeat(Math.min(usage,6));
$('leftDoor').classList.toggle('closed',doors.left);
$('rightDoor').classList.toggle('closed',doors.right);
$('leftWindow').classList.toggle('lit',lights.left&&!outage);
$('rightWindow').classList.toggle('lit',lights.right&&!outage);
$('lDoor').classList.toggle('active',doors.left);
$('rDoor').classList.toggle('active',doors.right);
$('lLight').classList.toggle('active',lights.left);
$('rLight').classList.toggle('active',lights.right);
$('nightLabel').textContent='NIGHT '+night;
$('hourLabel').textContent=(hour===0?'12':hour)+' AM';
$('cameraToggle').disabled=outage;
}
function renderCamera(){
$('camTitle').textContent='CAM '+selectedCam+' โ '+cameraNames[selectedCam];
let visible=enemies.filter(e=>e.pos<e.path.length&&e.path[e.pos]===selectedCam&&e.activeFrom<=night);
let art='โ';
if(visible.length){
art=visible.map(e=>'โ').join(' ');
$('camDesc').textContent='ืชื ืืขื ื ืจืืืช ืืืืจ. ืืืงื ืืช ืืืกืืจืื ืืช ืืืช ืืื ืืกืืช.';
}else{
$('camDesc').textContent=cameraDescriptions[selectedCam]+' ืืื ืชื ืืขื ืืจืืจื.';
}
if(selectedCam==='1A')art='โฌ';
if(selectedCam==='1B')art='โค';
if(selectedCam==='1C')art='โง';
if(selectedCam==='3')art='โฆ';
if(visible.length)art='โ โ';
$('camArt').textContent=art;
$('camArt').style.color=visible.length?'#e6d3a1':'#718574';
document.querySelectorAll('.cam').forEach(b=>b.classList.toggle('active',b.dataset.cam===selectedCam));
}
function openCams(){
if(!running||outage)return;
camOpen=!camOpen;
$('cameras').classList.toggle('open',camOpen);
$('cameraToggle').textContent=camOpen?'โฃ ืืฆืืืืช ืคืชืืืืช':'โฃ ืคืชืืืช ืืฆืืืืช';
if(camOpen)renderCamera();
beep(camOpen?650:330,.08);
render();
}
function toggleDoor(side){
if(!running||outage||camOpen)return;
doors[side]=!doors[side];beep(doors[side]?100:180,.1,'square',.03);render();
}
function toggleLight(side){
if(!running||outage||camOpen)return;
lights[side]=!lights[side];beep(lights[side]?450:260,.06,'triangle',.02);render();
}
function scare(rare=false){
if(ended)return;
ended=true;running=false;camOpen=false;
$('cameras').classList.remove('open');
$('scare').classList.add('show');
if(rare){
$('endTitle').textContent='THE UNSEEN';
$('endText').textContent='ืืื ืืื ืืชืื ืืืฉืจื. ืื ืฉืืขืชื ืืืชื ืืืืข.';
}else{
$('endTitle').textContent='SHIFT TERMINATED';
$('endText').textContent='ืืืคืืฆืช ื ืื ืกื ืืืฉืจื. ื ืกื ืืขืงืื ืืืจื ืืืฆืืืืช ืืืกืืืจ ืืช ืืืืช ืืืื.';
}
beep(rare?42:70,.9,'sawtooth',.14);
setTimeout(()=>{
$('scare').classList.remove('show');
$('ending').style.display='flex';
$('nextNight').style.display='none';
},rare?1900:1500);
}
function winNight(){
if(ended)return;
ended=true;running=false;camOpen=false;
$('cameras').classList.remove('open');
$('ending').style.display='flex';
$('endTitle').textContent='6 AM โ SURVIVED';
$('endText').textContent='ืฉืจืืชื ืืช ืืืื '+night+'! ืืืฉืื ืฉื ืฉืืจ: '+Math.ceil(power)+'%.';
$('nextNight').style.display=night<5?'inline-block':'none';
$('nextNight').textContent=night<5?'ืืืฉื ืืืืื '+(night+1):'ืกืืืืชื ืืช ืื ืืืืืืช!';
if(night===5)$('endText').textContent+=' ืกืืืืชื ืืช ืื ืืืฉืช ืืืืืืช.';
beep(660,.3,'sine',.04);
}
function beginOutage(){
if(outage)return;
outage=true;power=0;
doors={left:false,right:false};lights={left:false,right:false};
camOpen=false;$('cameras').classList.remove('open');
$('cameraToggle').textContent='โฃ ืืฆืืืืช ืืืืืืช';
$('blackout').classList.add('show');
status('POWER OUT','var(--red)');
blackoutTimer=0;
beep(55,.65,'sawtooth',.06);
render();
}
function checkRareEvent(){
// Extremely rare: about 1 in 250 starts, and never more than once per night.
if(rareChecked)return;
rareChecked=true;
if(Math.random()<0.004){
status('...', '#888');
setTimeout(()=>{if(running)scare(true)},1800);
}
}
function start(){
power=100;elapsed=0;hour=0;last=performance.now();
camOpen=false;outage=false;ended=false;rareChecked=false;blackoutTimer=0;
doors={left:false,right:false};lights={left:false,right:false};
resetEnemies();
$('overlay').style.display='none';$('ending').style.display='none';
$('scare').classList.remove('show');$('blackout').classList.remove('show');
$('cameras').classList.remove('open');$('cameraToggle').textContent='โฃ ืคืชืืืช ืืฆืืืืช';
$('nextNight').style.display='inline-block';
status('SYSTEM NORMAL');
running=true;checkRareEvent();render();
requestAnimationFrame(loop);
}
function loop(now){
if(!running)return;
const dt=Math.min((now-last)/1000,.15);last=now;elapsed+=dt;
// All nights have the same length. Difficulty increases only when starting a new night.
const nightLength=210;
hour=Math.min(6,Math.floor(elapsed/(nightLength/6)));
if(!outage){
const drain=(0.035+Number(doors.left)*.10+Number(doors.right)*.10+
Number(lights.left)*.07+Number(lights.right)*.07+Number(camOpen)*.065);
power-=drain*dt*(1.4+difficulty()*.12);
if(power<=0)beginOutage();
}
if(outage){
blackoutTimer+=dt;
if(blackoutTimer>=(night>=4?9:12)){
scare(false);return;
}
}else{
enemies.forEach(e=>{
if(!running||ended||e.activeFrom>night)return;
e.t+=dt;
if(e.door){
// A closed door makes the threat retreat after a short wait.
if(doors[e.side]){
e.t=0;e.door=false;e.pos=Math.max(0,e.pos-2);
beep(120,.08,'triangle',.02);
}else if(e.t>e.attack){
scare(false);
}
return;
}
if(e.t>=e.rate){
e.t=0;
// Watching its current room slows most enemies, but does not freeze them.
if(camOpen&&e.path[e.pos]===selectedCam&&e.name!=='THE RUNNER'){
e.t=-e.rate*.22;return;
}
const chance=.48+difficulty()*.18;
if(Math.random()<chance){
if(e.pos<e.path.length-1)e.pos++;
if(e.pos===e.path.length-1){
e.door=true;e.t=0;
status('MOTION AT '+e.side.toUpperCase()+' DOOR','var(--gold)');
beep(105,.14,'triangle',.03);
}
}
}
});
}
if(hour>=6){winNight();return}
if(power<18&&!outage)status('LOW POWER','var(--red)');
render();
if(camOpen)renderCamera();
requestAnimationFrame(loop);
}
$('start').onclick=()=>start();
$('restart').onclick=()=>{night=1;start()};
$('nextNight').onclick=()=>{
if(night<5){night++;start()}
else{night=1;$('ending').style.display='none';$('overlay').style.display='flex'}
};
$('lDoor').onclick=()=>toggleDoor('left');
$('rDoor').onclick=()=>toggleDoor('right');
$('lLight').onclick=()=>toggleLight('left');
$('rLight').onclick=()=>toggleLight('right');
$('cameraToggle').onclick=openCams;
$('closeCam').onclick=openCams;
document.querySelectorAll('.cam').forEach(b=>b.onclick=()=>{
selectedCam=b.dataset.cam;renderCamera();beep(420,.04,'sine',.015);
});
document.addEventListener('keydown',e=>{
if(e.repeat)return;
const k=e.key.toLowerCase();
if(k==='q')toggleDoor('left');
if(k==='e')toggleDoor('right');
if(k==='a')toggleLight('left');
if(k==='d')toggleLight('right');
if(k===' '||k==='c'){e.preventDefault();openCams()}
if(k==='escape'&&camOpen)openCams();
});
render();
})();
</script>
</body>
</html>
Game Source: THE LAST WATCH
Creator: LunarPanda23
Libraries: none
Complexity: complex (426 lines, 23.1 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: the-last-watch-lunarpanda23" to link back to the original. Then publish at arcadelab.ai/publish.