Soda5601 commited on
Commit
c673a50
·
verified ·
1 Parent(s): 88a14a4

make mobile friendly - Follow Up Deployment

Browse files
Files changed (1) hide show
  1. index.html +637 -541
index.html CHANGED
@@ -3,632 +3,728 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Anti-Zombie Venter - Threat Department</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
- @keyframes flicker {
11
- 0% { opacity: 1; }
12
- 25% { opacity: 0.8; }
13
- 50% { opacity: 0.6; }
14
- 75% { opacity: 0.8; }
15
- 100% { opacity: 1; }
 
 
16
  }
17
- .flicker {
18
- animation: flicker 2s infinite;
 
 
 
19
  }
20
- .camera-feed {
21
- background: linear-gradient(rgba(0,0,0,0.7), rgba(0,0,0,0.7)), url('https://images.unsplash.com/photo-1518709268805-4e9042af9f23?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2048&q=80');
22
- background-size: cover;
23
- background-position: center;
24
- }
25
- .jumpscare {
26
- position: fixed;
27
  top: 0;
28
  left: 0;
29
  width: 100%;
30
  height: 100%;
31
- background-color: black;
32
- z-index: 100;
33
- display: flex;
34
- justify-content: center;
35
- align-items: center;
36
- opacity: 0;
37
  pointer-events: none;
38
- transition: opacity 0.1s;
39
  }
40
- .jumpscare img {
41
- width: 100%;
42
- height: 100%;
43
- object-fit: cover;
44
  }
45
- .mutant-presence {
46
- position: absolute;
47
- transition: all 0.5s;
48
- opacity: 0;
49
  }
50
- .mutant-presence.visible {
51
- opacity: 1;
 
 
 
52
  }
53
- .power-bar {
54
- transition: width 0.5s;
 
55
  }
56
- .serum-progress {
57
- transition: width 1s;
 
 
 
 
 
 
 
 
 
 
 
58
  }
59
- </style>
60
- </head>
61
- <body class="bg-gray-900 text-white font-mono overflow-hidden">
62
- <!-- Jumpscare Screen -->
63
- <div class="jumpscare" id="jumpscare">
64
- <img src="" alt="Jumpscare" id="jumpscare-image">
65
- </div>
66
 
67
- <!-- Main Game Container -->
68
- <div class="container mx-auto px-4 py-8 relative" id="game-container">
69
- <!-- Header -->
70
- <header class="flex justify-between items-center mb-6 border-b border-red-700 pb-4">
71
- <h1 class="text-3xl font-bold text-red-500 flicker">THREAT DEPARTMENT</h1>
72
- <div class="text-right">
73
- <p class="text-yellow-400">NIGHT <span id="night-number">1</span></p>
74
- <p class="text-sm text-gray-400">Anti-Zombie Venter System</p>
75
- </div>
76
- </header>
 
77
 
78
- <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
79
- <!-- Camera Select Section -->
80
- <div class="bg-gray-800 p-4 rounded-lg border border-gray-700">
81
- <h2 class="text-xl font-bold text-red-400 mb-4 border-b border-gray-700 pb-2">CAM SELECT</h2>
82
- <div class="grid grid-cols-2 gap-3">
83
- <button class="cam-btn bg-gray-700 hover:bg-gray-600 py-2 px-3 rounded text-sm" data-cam="1">CAM 1: Main Hall</button>
84
- <button class="cam-btn bg-gray-700 hover:bg-gray-600 py-2 px-3 rounded text-sm" data-cam="2">CAM 2: East Corridor</button>
85
- <button class="cam-btn bg-gray-700 hover:bg-gray-600 py-2 px-3 rounded text-sm" data-cam="3">CAM 3: West Corridor</button>
86
- <button class="cam-btn bg-gray-700 hover:bg-gray-600 py-2 px-3 rounded text-sm" data-cam="4">CAM 4: Storage Room</button>
87
- <button class="cam-btn bg-gray-700 hover:bg-gray-600 py-2 px-3 rounded text-sm" data-cam="5">CAM 5: Lab Entrance</button>
88
- <button class="cam-btn bg-gray-700 hover:bg-gray-600 py-2 px-3 rounded text-sm" data-cam="6">CAM 6: Ventilation</button>
89
- <button class="cam-btn bg-gray-700 hover:bg-gray-600 py-2 px-3 rounded text-sm" data-cam="7">CAM 7: Serum Storage</button>
90
- <button class="cam-btn bg-gray-700 hover:bg-gray-600 py-2 px-3 rounded text-sm" data-cam="8">CAM 8: Office Hall</button>
91
- </div>
92
- </div>
93
 
94
- <!-- Camera Feed Section -->
95
- <div class="bg-gray-800 p-4 rounded-lg border border-gray-700 lg:col-span-2">
96
- <div class="flex justify-between items-center mb-4 border-b border-gray-700 pb-2">
97
- <h2 class="text-xl font-bold text-red-400">CAM FEED</h2>
98
- <div class="text-sm text-yellow-400" id="current-cam">CAM 1: Main Hall</div>
99
- </div>
100
- <div class="camera-feed h-64 md:h-96 rounded-lg relative overflow-hidden" id="camera-feed">
101
- <!-- Mutants will appear here -->
102
- <div class="mutant-presence" id="mutant-1">
103
- <img src="https://cdn.pixabay.com/photo/2023/10/15/11/03/zombie-8317034_640.png" alt="Mutant 1" class="h-24 absolute bottom-0 right-4">
104
- </div>
105
- <div class="mutant-presence" id="mutant-2">
106
- <img src="https://cdn.pixabay.com/photo/2023/10/15/11/03/zombie-8317035_640.png" alt="Mutant 2" class="h-24 absolute bottom-0 left-4">
107
- </div>
108
- <div class="mutant-presence" id="mutant-3">
109
- <img src="https://cdn.pixabay.com/photo/2023/10/15/11/03/zombie-8317036_640.png" alt="Mutant 3" class="h-24 absolute bottom-0 right-10">
110
- </div>
111
- <div class="mutant-presence" id="mutant-4">
112
- <img src="https://cdn.pixabay.com/photo/2023/10/15/11/03/zombie-8317037_640.png" alt="Mutant 4" class="h-24 absolute bottom-0 left-10">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  </div>
114
  </div>
115
- <div class="mt-4 flex justify-between items-center">
116
- <button class="bg-red-700 hover:bg-red-600 py-2 px-4 rounded flex items-center" id="serum-btn">
117
- <i class="fas fa-syringe mr-2"></i> DELIVER SERUM (<span id="serum-count">3</span>)
118
- </button>
119
- <div class="text-xs text-gray-400">Serum progress: <span id="serum-percent">0</span>%</div>
120
- </div>
121
- <div class="w-full bg-gray-700 h-2 mt-2 rounded">
122
- <div class="bg-green-500 h-2 rounded serum-progress" id="serum-progress" style="width: 0%"></div>
123
  </div>
124
  </div>
125
- </div>
126
-
127
- <!-- Office Controls Section -->
128
- <div class="mt-6 bg-gray-800 p-4 rounded-lg border border-gray-700">
129
- <h2 class="text-xl font-bold text-red-400 mb-4 border-b border-gray-700 pb-2">OFFICE CONTROLS</h2>
130
- <div class="grid grid-cols-1 md:grid-cols-3 gap-4">
131
- <div>
132
- <h3 class="text-lg font-bold text-yellow-400 mb-2">DOOR CONTROLS</h3>
133
- <div class="flex space-x-4">
134
- <div>
135
- <button class="door-btn bg-gray-700 hover:bg-gray-600 py-2 px-4 rounded flex items-center mb-2" data-door="left">
136
- <i class="fas fa-door-closed mr-2" id="left-door-icon"></i> LEFT DOOR
137
- </button>
138
- <div class="text-xs text-center">Power: <span id="left-door-power">100</span>%</div>
139
- </div>
140
- <div>
141
- <button class="door-btn bg-gray-700 hover:bg-gray-600 py-2 px-4 rounded flex items-center mb-2" data-door="right">
142
- <i class="fas fa-door-closed mr-2" id="right-door-icon"></i> RIGHT DOOR
143
- </button>
144
- <div class="text-xs text-center">Power: <span id="right-door-power">100</span>%</div>
145
- </div>
146
- </div>
147
  </div>
148
-
149
- <div>
150
- <h3 class="text-lg font-bold text-yellow-400 mb-2">VENT CONTROLS</h3>
151
- <div class="flex space-x-4">
152
- <div>
153
- <button class="vent-btn bg-gray-700 hover:bg-gray-600 py-2 px-4 rounded flex items-center mb-2" data-vent="left">
154
- <i class="fas fa-fan mr-2" id="left-vent-icon"></i> LEFT VENT
155
- </button>
156
- <div class="text-xs text-center">Power: <span id="left-vent-power">100</span>%</div>
157
- </div>
158
- <div>
159
- <button class="vent-btn bg-gray-700 hover:bg-gray-600 py-2 px-4 rounded flex items-center mb-2" data-vent="right">
160
- <i class="fas fa-fan mr-2" id="right-vent-icon"></i> RIGHT VENT
161
- </button>
162
- <div class="text-xs text-center">Power: <span id="right-vent-power">100</span>%</div>
163
- </div>
164
- </div>
165
  </div>
166
-
167
- <div>
168
- <h3 class="text-lg font-bold text-yellow-400 mb-2">SYSTEM STATUS</h3>
169
- <div class="mb-2">
170
- <div class="flex justify-between text-sm mb-1">
171
- <span>POWER</span>
172
- <span id="power-percent">100%</span>
173
- </div>
174
- <div class="w-full bg-gray-700 h-4 rounded">
175
- <div class="bg-blue-500 h-4 rounded power-bar" id="power-bar" style="width: 100%"></div>
176
- </div>
177
- </div>
178
- <div class="text-sm">
179
- <div class="flex justify-between">
180
- <span>Time:</span>
181
- <span id="game-time">12:00 AM</span>
182
- </div>
183
- <div class="flex justify-between">
184
- <span>Serum:</span>
185
- <span id="serum-status">Ready</span>
186
- </div>
187
- <div class="flex justify-between">
188
- <span>Threat Level:</span>
189
- <span id="threat-level">Low</span>
190
- </div>
191
  </div>
192
  </div>
193
  </div>
194
- </div>
195
 
196
- <!-- Audio elements -->
197
- <audio id="camera-sound" src="https://www.soundjay.com/mechanical/sounds/camera-shutter-click-01.mp3" preload="auto"></audio>
198
- <audio id="door-sound" src="https://www.soundjay.com/mechanical/sounds/door-creak-1.mp3" preload="auto"></audio>
199
- <audio id="vent-sound" src="https://www.soundjay.com/mechanical/sounds/fan-01.mp3" preload="auto"></audio>
200
- <audio id="serum-sound" src="https://www.soundjay.com/mechanical/sounds/beep-07.mp3" preload="auto"></audio>
201
- <audio id="jumpscare-sound" src="https://www.soundjay.com/human/sounds/scream-06.mp3" preload="auto"></audio>
202
- <audio id="static-sound" src="https://www.soundjay.com/communication/sounds/radio-static-1.mp3" preload="auto" loop></audio>
 
 
203
  </div>
204
 
205
  <script>
206
- // Game State
207
- const gameState = {
208
- currentCam: 1,
209
- power: 100,
210
- leftDoor: true,
211
- rightDoor: true,
212
- leftVent: false,
213
- rightVent: false,
214
- serumCount: 3,
215
- serumProgress: 0,
216
- night: 1,
217
- time: 0, // 0-6 hours (0-360 minutes)
218
- gameOver: false,
219
- mutants: {
220
- 1: { name: "Necro", location: 8, aggression: 1, fakeMoves: 0 },
221
- 2: { name: "Venom", location: 8, aggression: 2, fakeMoves: 0 },
222
- 3: { name: "Fester", location: 8, aggression: 3, fakeMoves: 0 },
223
- 4: { name: "Rot", location: 8, aggression: 4, fakeMoves: 0 }
224
- },
225
- mutantLocations: {
226
- 1: "Main Hall",
227
- 2: "East Corridor",
228
- 3: "West Corridor",
229
- 4: "Storage Room",
230
- 5: "Lab Entrance",
231
- 6: "Ventilation",
232
- 7: "Serum Storage",
233
- 8: "Office Hall"
234
- }
235
- };
236
-
237
- // DOM Elements
238
- const elements = {
239
- gameContainer: document.getElementById('game-container'),
240
- jumpscare: document.getElementById('jumpscare'),
241
- jumpscareImage: document.getElementById('jumpscare-image'),
242
- currentCamDisplay: document.getElementById('current-cam'),
243
- cameraFeed: document.getElementById('camera-feed'),
244
- powerBar: document.getElementById('power-bar'),
245
- powerPercent: document.getElementById('power-percent'),
246
- leftDoorIcon: document.getElementById('left-door-icon'),
247
- rightDoorIcon: document.getElementById('right-door-icon'),
248
- leftVentIcon: document.getElementById('left-vent-icon'),
249
- rightVentIcon: document.getElementById('right-vent-icon'),
250
- leftDoorPower: document.getElementById('left-door-power'),
251
- rightDoorPower: document.getElementById('right-door-power'),
252
- leftVentPower: document.getElementById('left-vent-power'),
253
- rightVentPower: document.getElementById('right-vent-power'),
254
- serumCount: document.getElementById('serum-count'),
255
- serumProgress: document.getElementById('serum-progress'),
256
- serumPercent: document.getElementById('serum-percent'),
257
- serumStatus: document.getElementById('serum-status'),
258
- gameTime: document.getElementById('game-time'),
259
- threatLevel: document.getElementById('threat-level'),
260
- nightNumber: document.getElementById('night-number'),
261
- // Audio elements
262
- cameraSound: document.getElementById('camera-sound'),
263
- doorSound: document.getElementById('door-sound'),
264
- ventSound: document.getElementById('vent-sound'),
265
- serumSound: document.getElementById('serum-sound'),
266
- jumpscareSound: document.getElementById('jumpscare-sound'),
267
- staticSound: document.getElementById('static-sound')
268
  };
269
-
270
- // Initialize game
271
  function initGame() {
272
- // Set up event listeners
273
- document.querySelectorAll('.cam-btn').forEach(btn => {
274
- btn.addEventListener('click', () => switchCamera(parseInt(btn.dataset.cam)));
 
 
 
 
 
 
 
275
  });
276
-
277
- document.querySelectorAll('.door-btn').forEach(btn => {
278
- btn.addEventListener('click', () => toggleDoor(btn.dataset.door));
 
 
 
279
  });
280
-
281
- document.querySelectorAll('.vent-btn').forEach(btn => {
282
- btn.addEventListener('click', () => toggleVent(btn.dataset.vent));
 
 
 
 
 
 
 
283
  });
284
-
285
- document.getElementById('serum-btn').addEventListener('click', deliverSerum);
286
-
287
- // Start game loop
288
- setInterval(gameLoop, 1000);
289
- setInterval(cameraStatic, 5000);
290
- setInterval(updatePower, 30000);
291
  }
292
-
293
- // Game loop
294
- function gameLoop() {
295
- if (gameState.gameOver) return;
296
-
297
- // Update time
298
- gameState.time += 1;
299
- updateTimeDisplay();
300
-
301
- // Check for mutants in office
302
- checkForAttack();
303
-
304
- // Update UI
305
- updatePowerDisplay();
306
- updateMutantVisibility();
307
- updateThreatLevel();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
  }
309
-
310
- // Camera static effect
311
- function cameraStatic() {
312
- if (Math.random() < 0.3) { // 30% chance of static
313
- elements.cameraFeed.style.backgroundImage = 'none';
314
- elements.cameraFeed.style.backgroundColor = 'black';
315
- elements.staticSound.currentTime = 0;
316
- elements.staticSound.play();
317
- setTimeout(() => {
318
- elements.cameraFeed.style.backgroundImage = 'linear-gradient(rgba(0,0,0,0.7), rgba(0,0,0,0.7)), url("https://images.unsplash.com/photo-1518709268805-4e9042af9f23?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=2048&q=80")';
319
- }, 500);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
  }
321
  }
322
-
323
- // Switch camera view
324
- function switchCamera(camNumber) {
325
- if (gameState.gameOver) return;
326
-
327
- gameState.currentCam = camNumber;
328
- elements.currentCamDisplay.textContent = `CAM ${camNumber}: ${gameState.mutantLocations[camNumber]}`;
329
 
330
- // Play camera sound
331
- elements.cameraSound.currentTime = 0;
332
- elements.cameraSound.play();
333
 
334
- // Use a bit of power
335
- gameState.power -= 0.2;
336
- if (gameState.power < 0) gameState.power = 0;
337
 
338
- updatePowerDisplay();
339
- }
340
-
341
- // Toggle door
342
- function toggleDoor(doorSide) {
343
- if (gameState.gameOver) return;
344
-
345
- // Play door sound
346
- elements.doorSound.currentTime = 0;
347
- elements.doorSound.play();
348
 
349
- if (doorSide === 'left') {
350
- gameState.leftDoor = !gameState.leftDoor;
351
- elements.leftDoorIcon.className = gameState.leftDoor ? 'fas fa-door-open mr-2' : 'fas fa-door-closed mr-2';
352
- } else {
353
- gameState.rightDoor = !gameState.rightDoor;
354
- elements.rightDoorIcon.className = gameState.rightDoor ? 'fas fa-door-open mr-2' : 'fas fa-door-closed mr-2';
355
  }
356
- }
357
-
358
- // Toggle vent
359
- function toggleVent(ventSide) {
360
- if (gameState.gameOver) return;
361
-
362
- // Play vent sound
363
- elements.ventSound.currentTime = 0;
364
- elements.ventSound.play();
365
 
366
- if (ventSide === 'left') {
367
- gameState.leftVent = !gameState.leftVent;
368
- elements.leftVentIcon.className = gameState.leftVent ? 'fas fa-fan mr-2 text-green-500' : 'fas fa-fan mr-2';
369
- } else {
370
- gameState.rightVent = !gameState.rightVent;
371
- elements.rightVentIcon.className = gameState.rightVent ? 'fas fa-fan mr-2 text-green-500' : 'fas fa-fan mr-2';
372
  }
 
373
  }
374
-
375
- // Deliver serum
376
- function deliverSerum() {
377
- if (gameState.gameOver || gameState.serumCount <= 0 || gameState.serumProgress >= 100) return;
378
-
379
- // Play serum sound
380
- elements.serumSound.currentTime = 0;
381
- elements.serumSound.play();
382
-
383
- gameState.serumCount--;
384
- gameState.serumProgress += 33;
385
-
386
- if (gameState.serumProgress >= 99) {
387
- gameState.serumProgress = 99;
388
- elements.serumStatus.textContent = "Complete";
389
- // Win condition
390
- setTimeout(() => {
391
- alert(`Congratulations! You survived Night ${gameState.night}!`);
392
- gameState.night++;
393
- elements.nightNumber.textContent = gameState.night;
394
- resetNight();
395
- }, 1000);
396
  }
397
 
398
- updateSerumDisplay();
399
- }
400
-
401
- // Check for mutant attack
402
- function checkForAttack() {
403
- Object.keys(gameState.mutants).forEach(mutantId => {
404
- const mutant = gameState.mutants[mutantId];
405
-
406
- if (mutant.location === 8) { // Office Hall
407
- // Check if door is closed
408
- if ((mutantId % 2 === 0 && !gameState.rightDoor) || (mutantId % 2 !== 0 && !gameState.leftDoor)) {
409
- // Attack!
410
- triggerJumpscare(mutantId);
411
- }
412
- }
413
- });
414
  }
415
-
416
- // Trigger jumpscare
417
- function triggerJumpscare(mutantId) {
418
- gameState.gameOver = true;
419
-
420
- // Set jumpscare image based on mutant
421
- const mutantImages = {
422
- 1: "https://cdn.pixabay.com/photo/2023/10/15/11/03/zombie-8317034_640.png",
423
- 2: "https://cdn.pixabay.com/photo/2023/10/15/11/03/zombie-8317035_640.png",
424
- 3: "https://cdn.pixabay.com/photo/2023/10/15/11/03/zombie-8317036_640.png",
425
- 4: "https://cdn.pixabay.com/photo/2023/10/15/11/03/zombie-8317037_640.png"
426
- };
427
 
428
- elements.jumpscareImage.src = mutantImages[mutantId];
 
429
 
430
- // Play sounds
431
- elements.jumpscareSound.currentTime = 0;
432
- elements.jumpscareSound.play();
433
- elements.staticSound.currentTime = 0;
434
- elements.staticSound.play();
435
 
436
- // Show jumpscare
437
- elements.jumpscare.style.opacity = "1";
 
438
 
439
- // Game over
440
- setTimeout(() => {
441
- alert(`Game Over! You were caught by ${gameState.mutants[mutantId].name} on Night ${gameState.night}.`);
442
- resetNight();
443
- }, 2000);
444
- }
445
-
446
- // Update power display
447
- function updatePowerDisplay() {
448
- elements.powerBar.style.width = `${gameState.power}%`;
449
- elements.powerPercent.textContent = `${Math.floor(gameState.power)}%`;
450
-
451
- // Low power effects
452
- if (gameState.power < 20) {
453
- elements.powerBar.classList.add('bg-red-500');
454
- elements.powerBar.classList.remove('bg-blue-500');
455
-
456
- // Random flickering
457
- if (Math.random() < 0.3) {
458
- elements.gameContainer.classList.add('opacity-50');
459
- setTimeout(() => {
460
- elements.gameContainer.classList.remove('opacity-50');
461
- }, 200);
462
- }
463
- } else {
464
- elements.powerBar.classList.remove('bg-red-500');
465
- elements.powerBar.classList.add('bg-blue-500');
466
  }
467
 
468
- // Power outage
469
- if (gameState.power <= 0) {
470
- gameState.power = 0;
471
- triggerPowerOutage();
 
472
  }
473
  }
474
-
475
- // Update time display
476
- function updateTimeDisplay() {
477
- const hours = Math.floor(gameState.time / 60);
478
- const minutes = gameState.time % 60;
479
- const ampm = hours >= 6 ? 'PM' : 'AM';
480
- const displayHours = hours % 12 || 12;
481
-
482
- elements.gameTime.textContent = `${displayHours}:${minutes < 10 ? '0' + minutes : minutes} ${ampm}`;
483
-
484
- // Night completion
485
- if (gameState.time >= 360) {
486
- alert(`Congratulations! You survived Night ${gameState.night}!`);
487
- gameState.night++;
488
- elements.nightNumber.textContent = gameState.night;
489
- resetNight();
490
  }
491
  }
492
-
493
- // Update mutant visibility
494
- function updateMutantVisibility() {
495
- // Hide all mutants first
496
- document.querySelectorAll('.mutant-presence').forEach(el => {
497
- el.classList.remove('visible');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
498
  });
499
 
500
- // Show mutants in current camera view
501
- Object.keys(gameState.mutants).forEach(mutantId => {
502
- const mutant = gameState.mutants[mutantId];
503
- if (mutant.location === gameState.currentCam) {
504
- const mutantEl = document.getElementById(`mutant-${mutantId}`);
505
- mutantEl.classList.add('visible');
 
 
 
 
 
 
 
 
 
 
506
 
507
- // Show fake movements
508
- if (mutant.fakeMoves > 0) {
509
- mutantEl.style.transform = `translateX(${Math.random() * 20 - 10}px)`;
510
  }
511
  }
 
 
 
 
512
  });
513
  }
514
-
515
- // Update threat level
516
- function updateThreatLevel() {
517
- let threatScore = 0;
518
 
519
- Object.keys(gameState.mutants).forEach(mutantId => {
520
- const mutant = gameState.mutants[mutantId];
521
- threatScore += mutant.location * mutant.aggression;
522
- });
 
 
 
523
 
524
- threatScore = threatScore / 10 + (gameState.time / 60);
525
-
526
- if (threatScore < 5) {
527
- elements.threatLevel.textContent = "Low";
528
- elements.threatLevel.className = "text-green-500";
529
- } else if (threatScore < 10) {
530
- elements.threatLevel.textContent = "Medium";
531
- elements.threatLevel.className = "text-yellow-500";
532
- } else if (threatScore < 20) {
533
- elements.threatLevel.textContent = "High";
534
- elements.threatLevel.className = "text-orange-500";
535
- } else {
536
- elements.threatLevel.textContent = "Extreme";
537
- elements.threatLevel.className = "text-red-500";
538
- }
539
  }
540
-
541
- // Update serum display
542
- function updateSerumDisplay() {
543
- elements.serumCount.textContent = gameState.serumCount;
544
- elements.serumProgress.style.width = `${gameState.serumProgress}%`;
545
- elements.serumPercent.textContent = Math.floor(gameState.serumProgress);
546
-
547
- if (gameState.serumProgress >= 100) {
548
- elements.serumStatus.textContent = "Complete";
549
- elements.serumStatus.className = "text-green-500";
550
- } else if (gameState.serumCount <= 0) {
551
- elements.serumStatus.textContent = "Depleted";
552
- elements.serumStatus.className = "text-red-500";
553
  } else {
554
- elements.serumStatus.textContent = "Ready";
555
- elements.serumStatus.className = "text-yellow-500";
556
  }
557
  }
558
-
559
- // Update power consumption
560
- function updatePower() {
561
- // Base power drain
562
- gameState.power -= 2;
563
 
564
- // Base power drain only
 
 
565
 
566
- if (gameState.power < 0) gameState.power = 0;
 
567
 
568
- updatePowerDisplay();
 
 
569
  }
570
-
571
- // Trigger power outage
572
- function triggerPowerOutage() {
573
- elements.staticSound.currentTime = 0;
574
- elements.staticSound.play();
575
 
576
- // Disable all systems
577
- gameState.leftDoor = false;
578
- gameState.rightDoor = false;
579
- gameState.leftVent = false;
580
- gameState.rightVent = false;
 
 
 
 
581
 
582
- // Update UI
583
- elements.leftDoorIcon.className = 'fas fa-door-open mr-2';
584
- elements.rightDoorIcon.className = 'fas fa-door-open mr-2';
585
- elements.leftVentIcon.className = 'fas fa-fan mr-2';
586
- elements.rightVentIcon.className = 'fas fa-fan mr-2';
587
-
588
- // Game over soon if mutants are nearby
589
- setTimeout(() => {
590
- if (!gameState.gameOver) {
591
- triggerJumpscare(Math.floor(Math.random() * 4) + 1);
592
- }
593
- }, 5000);
594
  }
595
-
596
- // Reset for new night
597
- function resetNight() {
598
- gameState.power = 100;
599
- gameState.leftDoor = false;
600
- gameState.rightDoor = false;
601
- gameState.leftVent = false;
602
- gameState.rightVent = false;
603
- gameState.serumCount = 3;
604
- gameState.serumProgress = 0;
605
- gameState.time = 0;
606
- gameState.gameOver = false;
607
-
608
- // Reset mutants
609
- Object.keys(gameState.mutants).forEach(mutantId => {
610
- gameState.mutants[mutantId].location = 1;
611
- gameState.mutants[mutantId].fakeMoves = 0;
612
- });
613
 
614
  // Reset UI
615
- elements.jumpscare.style.opacity = "0";
616
- elements.staticSound.pause();
617
- elements.leftDoorIcon.className = 'fas fa-door-open mr-2';
618
- elements.rightDoorIcon.className = 'fas fa-door-open mr-2';
619
- elements.leftVentIcon.className = 'fas fa-fan mr-2';
620
- elements.rightVentIcon.className = 'fas fa-fan mr-2';
621
- elements.currentCamDisplay.textContent = 'CAM 1: Main Hall';
622
- gameState.currentCam = 1;
623
-
624
- updatePowerDisplay();
625
- updateSerumDisplay();
626
- updateTimeDisplay();
627
- updateMutantVisibility();
 
 
 
 
 
 
 
 
628
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
629
 
630
- // Initialize game when page loads
631
- window.onload = initGame;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
632
  </script>
633
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Soda5601/zb" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
634
  </html>
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>FNAF: Slenderman's Forest</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/7.2.4/pixi.min.js"></script>
9
  <style>
10
+ @import url('https://fonts.googleapis.com/css2?family=Creepster&family=Press+Start+2P&display=swap');
11
+
12
+ body {
13
+ margin: 0;
14
+ padding: 0;
15
+ overflow: hidden;
16
+ background-color: #000;
17
+ font-family: 'Press Start 2P', cursive;
18
  }
19
+
20
+ #game-container {
21
+ position: relative;
22
+ width: 100vw;
23
+ height: 100vh;
24
  }
25
+
26
+ #ui-overlay {
27
+ position: absolute;
 
 
 
 
28
  top: 0;
29
  left: 0;
30
  width: 100%;
31
  height: 100%;
 
 
 
 
 
 
32
  pointer-events: none;
33
+ z-index: 10;
34
  }
35
+
36
+ .creepy-font {
37
+ font-family: 'Creepster', cursive;
 
38
  }
39
+
40
+ .pulse {
41
+ animation: pulse 2s infinite;
 
42
  }
43
+
44
+ @keyframes pulse {
45
+ 0% { opacity: 0.7; }
46
+ 50% { opacity: 1; }
47
+ 100% { opacity: 0.7; }
48
  }
49
+
50
+ .shake {
51
+ animation: shake 0.5s infinite;
52
  }
53
+
54
+ @keyframes shake {
55
+ 0% { transform: translate(1px, 1px) rotate(0deg); }
56
+ 10% { transform: translate(-1px, -2px) rotate(-1deg); }
57
+ 20% { transform: translate(-3px, 0px) rotate(1deg); }
58
+ 30% { transform: translate(3px, 2px) rotate(0deg); }
59
+ 40% { transform: translate(1px, -1px) rotate(1deg); }
60
+ 50% { transform: translate(-1px, 2px) rotate(-1deg); }
61
+ 60% { transform: translate(-3px, 1px) rotate(0deg); }
62
+ 70% { transform: translate(3px, 1px) rotate(-1deg); }
63
+ 80% { transform: translate(-1px, -1px) rotate(1deg); }
64
+ 90% { transform: translate(1px, 2px) rotate(0deg); }
65
+ 100% { transform: translate(1px, -2px) rotate(-1deg); }
66
  }
 
 
 
 
 
 
 
67
 
68
+ /* Mobile controls */
69
+ #mobile-controls {
70
+ position: absolute;
71
+ bottom: 20px;
72
+ left: 0;
73
+ right: 0;
74
+ display: none;
75
+ justify-content: space-between;
76
+ padding: 0 20px;
77
+ z-index: 20;
78
+ }
79
 
80
+ .mobile-btn {
81
+ width: 60px;
82
+ height: 60px;
83
+ background-color: rgba(0, 0, 0, 0.5);
84
+ border-radius: 50%;
85
+ display: flex;
86
+ align-items: center;
87
+ justify-content: center;
88
+ color: white;
89
+ font-size: 24px;
90
+ user-select: none;
91
+ touch-action: manipulation;
92
+ }
 
 
93
 
94
+ #joystick {
95
+ position: absolute;
96
+ width: 100px;
97
+ height: 100px;
98
+ background-color: rgba(0, 0, 0, 0.3);
99
+ border-radius: 50%;
100
+ left: 30px;
101
+ bottom: 30px;
102
+ display: none;
103
+ z-index: 20;
104
+ }
105
+
106
+ #joystick-knob {
107
+ width: 40px;
108
+ height: 40px;
109
+ background-color: rgba(255, 255, 255, 0.7);
110
+ border-radius: 50%;
111
+ position: absolute;
112
+ top: 30px;
113
+ left: 30px;
114
+ }
115
+
116
+ @media (max-width: 768px) {
117
+ #mobile-controls {
118
+ display: flex;
119
+ }
120
+ #joystick {
121
+ display: block;
122
+ }
123
+ .text-sm {
124
+ font-size: 0.7rem;
125
+ }
126
+ #start-screen h1 {
127
+ font-size: 2rem;
128
+ }
129
+ #start-screen p {
130
+ font-size: 0.9rem;
131
+ }
132
+ }
133
+ </style>
134
+ </head>
135
+ <body class="bg-black text-white">
136
+ <div id="game-container">
137
+ <div id="ui-overlay" class="flex flex-col justify-between p-4">
138
+ <!-- Top UI -->
139
+ <div class="flex justify-between items-start">
140
+ <div class="bg-black bg-opacity-70 p-2 rounded-lg">
141
+ <div class="text-red-500 text-sm">POWER: <span id="power-level">100</span>%</div>
142
+ <div class="h-2 w-32 bg-gray-800 mt-1">
143
+ <div id="power-bar" class="h-full bg-red-600" style="width: 100%;"></div>
144
  </div>
145
  </div>
146
+
147
+ <div class="bg-black bg-opacity-70 p-2 rounded-lg">
148
+ <div class="text-yellow-400 text-sm">PAGES: <span id="pages-collected">0</span>/8</div>
 
 
 
 
 
149
  </div>
150
  </div>
151
+
152
+ <!-- Center UI -->
153
+ <div class="flex flex-col items-center">
154
+ <div id="warning-message" class="bg-black bg-opacity-80 p-4 rounded-lg text-red-500 text-xl creepy-font pulse hidden">
155
+ WARNING: HE IS NEAR!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  </div>
157
+ <div id="game-over" class="bg-black bg-opacity-90 p-6 rounded-lg text-center max-w-md hidden">
158
+ <h2 class="text-red-600 text-3xl mb-4 creepy-font shake">GAME OVER</h2>
159
+ <p class="mb-4">Slenderman got you...</p>
160
+ <button id="restart-btn" class="bg-red-700 hover:bg-red-600 text-white px-4 py-2 rounded-lg pointer-events-auto">
161
+ TRY AGAIN
162
+ </button>
 
 
 
 
 
 
 
 
 
 
 
163
  </div>
164
+ </div>
165
+
166
+ <!-- Bottom UI -->
167
+ <div class="flex justify-center">
168
+ <div id="start-screen" class="bg-black bg-opacity-90 p-8 rounded-lg text-center max-w-md">
169
+ <h1 class="text-4xl mb-6 text-red-600 creepy-font">FNAF: SLENDERMAN'S FOREST</h1>
170
+ <p class="mb-6">Collect all 8 pages before Slenderman finds you!</p>
171
+ <button id="start-btn" class="bg-green-700 hover:bg-green-600 text-white px-6 py-3 rounded-lg text-lg pointer-events-auto">
172
+ START GAME
173
+ </button>
174
+ <div class="mt-4 text-xs text-gray-400">
175
+ <p>Use WASD to move</p>
176
+ <p>Hold SHIFT to run (consumes power)</p>
177
+ <p>Look away when you see Slenderman!</p>
 
 
 
 
 
 
 
 
 
 
 
178
  </div>
179
  </div>
180
  </div>
 
181
 
182
+ <!-- Mobile Controls -->
183
+ <div id="mobile-controls">
184
+ <div class="mobile-btn" id="mobile-shift">RUN</div>
185
+ <div class="mobile-btn" id="mobile-look">LOOK</div>
186
+ </div>
187
+ <div id="joystick">
188
+ <div id="joystick-knob"></div>
189
+ </div>
190
+ </div>
191
  </div>
192
 
193
  <script>
194
+ // Game variables
195
+ let app;
196
+ let player;
197
+ let slenderman;
198
+ let pages = [];
199
+ let collectedPages = 0;
200
+ let power = 100;
201
+ let gameStarted = false;
202
+ let slendermanActive = false;
203
+ let slendermanVisible = false;
204
+ let slendermanDistance = 100;
205
+ let slendermanSpawnTimer = null;
206
+ let powerDrainTimer = null;
207
+ let gameOver = false;
208
+
209
+ // Load textures from online sources
210
+ const textures = {
211
+ player: "https://opengameart.org/sites/default/files/Green-Cap-Character-16x18.png",
212
+ slenderman: "https://opengameart.org/sites/default/files/slenderman.png",
213
+ page: "https://opengameart.org/sites/default/files/parchment_0.png",
214
+ forest1: "https://opengameart.org/sites/default/files/forest_background_0.png",
215
+ forest2: "https://opengameart.org/sites/default/files/forest_background2.png",
216
+ forest3: "https://opengameart.org/sites/default/files/forest_background3.png",
217
+ forest4: "https://opengameart.org/sites/default/files/forest_background4.png"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218
  };
219
+
220
+ // Initialize the game
221
  function initGame() {
222
+ // Setup mobile controls if needed
223
+ setupMobileControls();
224
+
225
+ // Create Pixi application
226
+ app = new PIXI.Application({
227
+ width: window.innerWidth,
228
+ height: window.innerHeight,
229
+ backgroundColor: 0x000000,
230
+ resolution: window.devicePixelRatio || 1,
231
+ autoDensity: true
232
  });
233
+
234
+ document.getElementById('game-container').appendChild(app.view);
235
+
236
+ // Setup viewport and scaling
237
+ window.addEventListener('resize', () => {
238
+ app.renderer.resize(window.innerWidth, window.innerHeight);
239
  });
240
+
241
+ // Load assets
242
+ PIXI.Assets.addBundle('gameAssets', {
243
+ player: textures.player,
244
+ slenderman: textures.slenderman,
245
+ page: textures.page,
246
+ forest1: textures.forest1,
247
+ forest2: textures.forest2,
248
+ forest3: textures.forest3,
249
+ forest4: textures.forest4
250
  });
251
+
252
+ PIXI.Assets.loadBundle('gameAssets').then(setupGame);
 
 
 
 
 
253
  }
254
+
255
+ // Setup game elements after assets are loaded
256
+ function setupGame(assets) {
257
+ // Create forest background (randomly select one)
258
+ const forestTextures = [
259
+ assets.forest1,
260
+ assets.forest2,
261
+ assets.forest3,
262
+ assets.forest4
263
+ ];
264
+
265
+ const bgTexture = forestTextures[Math.floor(Math.random() * forestTextures.length)];
266
+ const background = new PIXI.Sprite(bgTexture);
267
+ background.width = app.screen.width;
268
+ background.height = app.screen.height;
269
+ app.stage.addChild(background);
270
+
271
+ // Create player
272
+ player = new PIXI.Sprite(assets.player);
273
+ player.anchor.set(0.5);
274
+ player.width = 50;
275
+ player.height = 100;
276
+ player.x = app.screen.width / 2;
277
+ player.y = app.screen.height / 2;
278
+ app.stage.addChild(player);
279
+
280
+ // Create pages
281
+ createPages(assets.page);
282
+
283
+ // Setup keyboard controls
284
+ setupControls();
285
+
286
+ // Hide start screen
287
+ document.getElementById('start-screen').classList.add('hidden');
288
+
289
+ // Start game systems
290
+ startGameSystems();
291
  }
292
+
293
+ // Create collectible pages
294
+ function createPages(pageTexture) {
295
+ for (let i = 0; i < 8; i++) {
296
+ const page = new PIXI.Sprite(pageTexture);
297
+ page.anchor.set(0.5);
298
+ page.width = 30;
299
+ page.height = 40;
300
+ page.x = Math.random() * (app.screen.width - 100) + 50;
301
+ page.y = Math.random() * (app.screen.height - 100) + 50;
302
+ page.interactive = true;
303
+ page.buttonMode = true;
304
+ page.on('pointerdown', () => collectPage(page));
305
+
306
+ // Add glow effect
307
+ const glow = new PIXI.filters.GlowFilter({
308
+ distance: 10,
309
+ outerStrength: 2,
310
+ innerStrength: 1,
311
+ color: 0xffff00
312
+ });
313
+ page.filters = [glow];
314
+
315
+ app.stage.addChild(page);
316
+ pages.push(page);
317
  }
318
  }
319
+
320
+ // Collect a page
321
+ function collectPage(page) {
322
+ if (gameOver) return;
 
 
 
323
 
324
+ // Remove page from game
325
+ app.stage.removeChild(page);
326
+ pages = pages.filter(p => p !== page);
327
 
328
+ // Update UI
329
+ collectedPages++;
330
+ document.getElementById('pages-collected').textContent = collectedPages;
331
 
332
+ // Play sound
333
+ playSound('https://www.soundjay.com/buttons/sounds/button-09.mp3');
 
 
 
 
 
 
 
 
334
 
335
+ // Check win condition
336
+ if (collectedPages === 8) {
337
+ winGame();
 
 
 
338
  }
 
 
 
 
 
 
 
 
 
339
 
340
+ // Increase Slenderman spawn chance after collecting pages
341
+ if (slendermanSpawnTimer) {
342
+ clearTimeout(slendermanSpawnTimer);
 
 
 
343
  }
344
+ slendermanSpawnTimer = setTimeout(spawnSlenderman, 10000 - (collectedPages * 1000));
345
  }
346
+
347
+ // Spawn Slenderman
348
+ function spawnSlenderman(assets) {
349
+ if (gameOver || slendermanActive) return;
350
+
351
+ slendermanActive = true;
352
+ slendermanDistance = 100;
353
+
354
+ // Create Slenderman sprite if not exists
355
+ if (!slenderman) {
356
+ slenderman = new PIXI.Sprite(PIXI.Assets.get('slenderman'));
357
+ slenderman.anchor.set(0.5);
358
+ slenderman.width = 80;
359
+ slenderman.height = 200;
360
+ slenderman.visible = false;
361
+ slenderman.filters = [new PIXI.filters.AlphaFilter(0)];
362
+ app.stage.addChild(slenderman);
 
 
 
 
 
363
  }
364
 
365
+ // Position Slenderman randomly around player
366
+ const angle = Math.random() * Math.PI * 2;
367
+ const distance = 300 + Math.random() * 200;
368
+ slenderman.x = player.x + Math.cos(angle) * distance;
369
+ slenderman.y = player.y + Math.sin(angle) * distance;
370
+
371
+ // Start Slenderman behavior
372
+ updateSlenderman();
373
+
374
+ // Show warning
375
+ document.getElementById('warning-message').classList.remove('hidden');
376
+ playSound('https://www.soundjay.com/human/sounds/scream-03.mp3');
 
 
 
 
377
  }
378
+
379
+ // Update Slenderman position and behavior
380
+ function updateSlenderman() {
381
+ if (!slendermanActive || gameOver) return;
 
 
 
 
 
 
 
 
382
 
383
+ // Move closer to player
384
+ slendermanDistance -= 1;
385
 
386
+ // Calculate direction to player
387
+ const dx = player.x - slenderman.x;
388
+ const dy = player.y - slenderman.y;
389
+ const distance = Math.sqrt(dx * dx + dy * dy);
 
390
 
391
+ // Normalize direction
392
+ const dirX = dx / distance;
393
+ const dirY = dy / distance;
394
 
395
+ // Move Slenderman
396
+ slenderman.x += dirX * 2;
397
+ slenderman.y += dirY * 2;
398
+
399
+ // Make Slenderman visible if player is looking away
400
+ const playerAngle = player.rotation;
401
+ const angleToSlenderman = Math.atan2(dy, dx);
402
+ const angleDiff = Math.abs(playerAngle - angleToSlenderman);
403
+
404
+ slendermanVisible = angleDiff > Math.PI / 2;
405
+ slenderman.visible = slendermanVisible;
406
+
407
+ // Update alpha based on distance
408
+ const alpha = Math.min(1, 1.5 - (distance / 400));
409
+ slenderman.filters[0].alpha = alpha;
410
+
411
+ // Check if Slenderman caught the player
412
+ if (distance < 50 && slendermanVisible) {
413
+ endGame();
414
+ return;
 
 
 
 
 
 
 
415
  }
416
 
417
+ // Continue updating or despawn
418
+ if (distance > 800 || Math.random() < 0.01) {
419
+ despawnSlenderman();
420
+ } else {
421
+ requestAnimationFrame(updateSlenderman);
422
  }
423
  }
424
+
425
+ // Despawn Slenderman
426
+ function despawnSlenderman() {
427
+ slendermanActive = false;
428
+ if (slenderman) {
429
+ slenderman.visible = false;
430
+ }
431
+ document.getElementById('warning-message').classList.add('hidden');
432
+
433
+ // Schedule next spawn
434
+ if (!gameOver) {
435
+ slendermanSpawnTimer = setTimeout(spawnSlenderman, 15000 - (collectedPages * 1000));
 
 
 
 
436
  }
437
  }
438
+
439
+ // Setup keyboard controls
440
+ function setupControls() {
441
+ const keys = {
442
+ w: false,
443
+ a: false,
444
+ s: false,
445
+ d: false,
446
+ shift: false
447
+ };
448
+
449
+ // Key down event
450
+ window.addEventListener('keydown', (e) => {
451
+ if (gameOver || !gameStarted) return;
452
+
453
+ switch (e.key.toLowerCase()) {
454
+ case 'w': keys.w = true; break;
455
+ case 'a': keys.a = true; break;
456
+ case 's': keys.s = true; break;
457
+ case 'd': keys.d = true; break;
458
+ case 'shift': keys.shift = true; break;
459
+ }
460
+ });
461
+
462
+ // Key up event
463
+ window.addEventListener('keyup', (e) => {
464
+ switch (e.key.toLowerCase()) {
465
+ case 'w': keys.w = false; break;
466
+ case 'a': keys.a = false; break;
467
+ case 's': keys.s = false; break;
468
+ case 'd': keys.d = false; break;
469
+ case 'shift': keys.shift = false; break;
470
+ }
471
+ });
472
+
473
+ // Mouse movement for rotation
474
+ window.addEventListener('mousemove', (e) => {
475
+ if (gameOver || !gameStarted) return;
476
+
477
+ const rect = app.view.getBoundingClientRect();
478
+ const mouseX = e.clientX - rect.left;
479
+ const mouseY = e.clientY - rect.top;
480
+
481
+ const dx = mouseX - player.x;
482
+ const dy = mouseY - player.y;
483
+
484
+ player.rotation = Math.atan2(dy, dx);
485
  });
486
 
487
+ // Game loop for movement
488
+ app.ticker.add(() => {
489
+ if (gameOver || !gameStarted) return;
490
+
491
+ const currentKeys = isMobile ? mobileKeys : keys;
492
+ const speed = currentKeys.shift && power > 0 ? 5 : 2;
493
+
494
+ if (currentKeys.w) player.y -= speed;
495
+ if (currentKeys.a) player.x -= speed;
496
+ if (currentKeys.s) player.y += speed;
497
+ if (currentKeys.d) player.x += speed;
498
+
499
+ // Drain power when running
500
+ if (currentKeys.shift && (currentKeys.w || currentKeys.a || currentKeys.s || currentKeys.d)) {
501
+ power = Math.max(0, power - 0.1);
502
+ updatePowerUI();
503
 
504
+ if (power === 0) {
505
+ playSound('https://assets.mixkit.co/sfx/preview/mixkit-negative-interface-beep-218.mp3');
 
506
  }
507
  }
508
+
509
+ // Keep player in bounds
510
+ player.x = Math.max(20, Math.min(app.screen.width - 20, player.x));
511
+ player.y = Math.max(20, Math.min(app.screen.height - 20, player.y));
512
  });
513
  }
514
+
515
+ // Start game systems
516
+ function startGameSystems() {
517
+ gameStarted = true;
518
 
519
+ // Start power regeneration
520
+ powerDrainTimer = setInterval(() => {
521
+ if (power < 100 && !gameOver) {
522
+ power = Math.min(100, power + 0.05);
523
+ updatePowerUI();
524
+ }
525
+ }, 100);
526
 
527
+ // Initial Slenderman spawn
528
+ slendermanSpawnTimer = setTimeout(spawnSlenderman, 15000);
 
 
 
 
 
 
 
 
 
 
 
 
 
529
  }
530
+
531
+ // Update power UI
532
+ function updatePowerUI() {
533
+ document.getElementById('power-level').textContent = Math.floor(power);
534
+ document.getElementById('power-bar').style.width = `${power}%`;
535
+
536
+ if (power < 20) {
537
+ document.getElementById('power-bar').classList.add('bg-red-700');
538
+ document.getElementById('power-bar').classList.remove('bg-red-600');
 
 
 
 
539
  } else {
540
+ document.getElementById('power-bar').classList.add('bg-red-600');
541
+ document.getElementById('power-bar').classList.remove('bg-red-700');
542
  }
543
  }
544
+
545
+ // End game (caught by Slenderman)
546
+ function endGame() {
547
+ gameOver = true;
548
+ slendermanActive = false;
549
 
550
+ // Show game over screen
551
+ document.getElementById('game-over').classList.remove('hidden');
552
+ document.getElementById('warning-message').classList.add('hidden');
553
 
554
+ // Play scary sound
555
+ playSound('https://www.soundjay.com/human/sounds/scream-06.mp3');
556
 
557
+ // Stop timers
558
+ clearInterval(powerDrainTimer);
559
+ clearTimeout(slendermanSpawnTimer);
560
  }
561
+
562
+ // Win game (collected all pages)
563
+ function winGame() {
564
+ gameOver = true;
565
+ slendermanActive = false;
566
 
567
+ // Show win message
568
+ document.getElementById('game-over').classList.remove('hidden');
569
+ document.getElementById('game-over').innerHTML = `
570
+ <h2 class="text-green-500 text-3xl mb-4 creepy-font">YOU ESCAPED!</h2>
571
+ <p class="mb-4">You collected all 8 pages and escaped Slenderman's forest!</p>
572
+ <button id="restart-btn" class="bg-green-700 hover:bg-green-600 text-white px-4 py-2 rounded-lg pointer-events-auto">
573
+ PLAY AGAIN
574
+ </button>
575
+ `;
576
 
577
+ // Play win sound
578
+ playSound('https://www.soundjay.com/misc/sounds/magic-chime-01.mp3');
579
+
580
+ // Stop timers
581
+ clearInterval(powerDrainTimer);
582
+ clearTimeout(slendermanSpawnTimer);
583
+
584
+ // Re-bind restart button
585
+ document.getElementById('restart-btn').addEventListener('click', restartGame);
 
 
 
586
  }
587
+
588
+ // Restart game
589
+ function restartGame() {
590
+ // Reset game state
591
+ gameOver = false;
592
+ gameStarted = false;
593
+ collectedPages = 0;
594
+ power = 100;
 
 
 
 
 
 
 
 
 
 
595
 
596
  // Reset UI
597
+ document.getElementById('pages-collected').textContent = '0';
598
+ updatePowerUI();
599
+ document.getElementById('game-over').classList.add('hidden');
600
+ document.getElementById('warning-message').classList.add('hidden');
601
+ document.getElementById('start-screen').classList.remove('hidden');
602
+
603
+ // Clear game elements
604
+ if (app) {
605
+ app.stage.removeChildren();
606
+ app.destroy(true);
607
+ }
608
+
609
+ // Reinitialize game
610
+ initGame();
611
+ }
612
+
613
+ // Play sound
614
+ function playSound(url) {
615
+ const audio = new Audio(url);
616
+ audio.volume = 0.5;
617
+ audio.play().catch(e => console.log("Audio play failed:", e));
618
  }
619
+
620
+ // Initialize game when start button is clicked
621
+ document.getElementById('start-btn').addEventListener('click', () => {
622
+ initGame();
623
+ });
624
+
625
+ // Mobile touch controls
626
+ let touchStartX = 0;
627
+ let touchStartY = 0;
628
+ let isTouching = false;
629
+ let isMobile = /Mobi|Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
630
+ let mobileKeys = {
631
+ w: false,
632
+ a: false,
633
+ s: false,
634
+ d: false,
635
+ shift: false
636
+ };
637
+
638
+ // Setup mobile controls
639
+ function setupMobileControls() {
640
+ if (!isMobile) return;
641
+
642
+ const joystick = document.getElementById('joystick');
643
+ const knob = document.getElementById('joystick-knob');
644
+ const runBtn = document.getElementById('mobile-shift');
645
+ const lookBtn = document.getElementById('mobile-look');
646
+
647
+ // Joystick touch events
648
+ joystick.addEventListener('touchstart', (e) => {
649
+ e.preventDefault();
650
+ isTouching = true;
651
+ const rect = joystick.getBoundingClientRect();
652
+ touchStartX = rect.left + rect.width / 2;
653
+ touchStartY = rect.top + rect.height / 2;
654
+ updateJoystick(e.touches[0].clientX, e.touches[0].clientY);
655
+ });
656
+
657
+ document.addEventListener('touchmove', (e) => {
658
+ if (!isTouching) return;
659
+ e.preventDefault();
660
+ updateJoystick(e.touches[0].clientX, e.touches[0].clientY);
661
+ });
662
+
663
+ document.addEventListener('touchend', () => {
664
+ isTouching = false;
665
+ knob.style.transform = 'translate(30px, 30px)';
666
+ mobileKeys.w = mobileKeys.a = mobileKeys.s = mobileKeys.d = false;
667
+ });
668
+
669
+ function updateJoystick(touchX, touchY) {
670
+ const rect = joystick.getBoundingClientRect();
671
+ const centerX = rect.left + rect.width / 2;
672
+ const centerY = rect.top + rect.height / 2;
673
+ const deltaX = touchX - centerX;
674
+ const deltaY = touchY - centerY;
675
+ const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
676
+ const maxDistance = rect.width / 2;
677
+
678
+ if (distance > maxDistance) {
679
+ const angle = Math.atan2(deltaY, deltaX);
680
+ deltaX = Math.cos(angle) * maxDistance;
681
+ deltaY = Math.sin(angle) * maxDistance;
682
+ }
683
+
684
+ knob.style.transform = `translate(${deltaX + 30}px, ${deltaY + 30}px)`;
685
+
686
+ // Update movement keys
687
+ mobileKeys.w = deltaY < -20;
688
+ mobileKeys.a = deltaX < -20;
689
+ mobileKeys.s = deltaY > 20;
690
+ mobileKeys.d = deltaX > 20;
691
+ }
692
+
693
+ // Run button
694
+ runBtn.addEventListener('touchstart', () => {
695
+ mobileKeys.shift = true;
696
+ });
697
+ runBtn.addEventListener('touchend', () => {
698
+ mobileKeys.shift = false;
699
+ });
700
 
701
+ // Look button (for mobile rotation)
702
+ let lookActive = false;
703
+ lookBtn.addEventListener('touchstart', () => {
704
+ lookActive = true;
705
+ });
706
+ lookBtn.addEventListener('touchend', () => {
707
+ lookActive = false;
708
+ });
709
+
710
+ // Mobile rotation
711
+ document.addEventListener('touchmove', (e) => {
712
+ if (!lookActive || !player || gameOver || !gameStarted) return;
713
+ e.preventDefault();
714
+ const touch = e.touches[0];
715
+ const rect = app.view.getBoundingClientRect();
716
+ const mouseX = touch.clientX - rect.left;
717
+ const mouseY = touch.clientY - rect.top;
718
+
719
+ const dx = mouseX - player.x;
720
+ const dy = mouseY - player.y;
721
+
722
+ player.rotation = Math.atan2(dy, dx);
723
+ });
724
+ }
725
+
726
+ // Bind restart button
727
+ document.getElementById('restart-btn').addEventListener('click', restartGame);
728
  </script>
729
  <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Soda5601/zb" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
730
  </html>