defaultdolphin commited on
Commit
1208f75
·
verified ·
1 Parent(s): 2fbee35

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +850 -19
index.html CHANGED
@@ -1,19 +1,850 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Subspace Continuum: Zone Warfare</title>
7
+ <style>
8
+ :root {
9
+ --primary: #00ffcc;
10
+ --danger: #ff3366;
11
+ --bg: #0a0a12;
12
+ --ui-bg: rgba(10, 10, 18, 0.85);
13
+ --font-main: 'Courier New', Courier, monospace;
14
+ }
15
+
16
+ * {
17
+ box-sizing: border-box;
18
+ user-select: none;
19
+ }
20
+
21
+ body {
22
+ margin: 0;
23
+ overflow: hidden;
24
+ background-color: var(--bg);
25
+ font-family: var(--font-main);
26
+ color: white;
27
+ height: 100vh;
28
+ width: 100vw;
29
+ }
30
+
31
+ /* Game Container */
32
+ #game-container {
33
+ position: relative;
34
+ width: 100%;
35
+ height: 100%;
36
+ }
37
+
38
+ canvas {
39
+ display: block;
40
+ width: 100%;
41
+ height: 100%;
42
+ }
43
+
44
+ /* UI Overlays */
45
+ .overlay {
46
+ position: absolute;
47
+ top: 0;
48
+ left: 0;
49
+ width: 100%;
50
+ height: 100%;
51
+ display: flex;
52
+ flex-direction: column;
53
+ justify-content: center;
54
+ align-items: center;
55
+ background: rgba(0, 0, 0, 0.7);
56
+ backdrop-filter: blur(5px);
57
+ z-index: 10;
58
+ transition: opacity 0.3s;
59
+ }
60
+
61
+ .hidden {
62
+ opacity: 0;
63
+ pointer-events: none;
64
+ z-index: -1;
65
+ }
66
+
67
+ /* Main Menu */
68
+ h1 {
69
+ font-size: 3rem;
70
+ text-transform: uppercase;
71
+ letter-spacing: 5px;
72
+ text-shadow: 0 0 20px var(--primary);
73
+ margin-bottom: 10px;
74
+ text-align: center;
75
+ }
76
+
77
+ .zone-grid {
78
+ display: grid;
79
+ grid-template-columns: repeat(2, 1fr);
80
+ gap: 20px;
81
+ margin-top: 30px;
82
+ }
83
+
84
+ .zone-card {
85
+ background: rgba(255, 255, 255, 0.05);
86
+ border: 1px solid rgba(255, 255, 255, 0.1);
87
+ padding: 20px;
88
+ width: 200px;
89
+ text-align: center;
90
+ cursor: pointer;
91
+ transition: all 0.2s;
92
+ border-radius: 8px;
93
+ }
94
+
95
+ .zone-card:hover {
96
+ transform: translateY(-5px);
97
+ background: rgba(255, 255, 255, 0.1);
98
+ border-color: var(--primary);
99
+ box-shadow: 0 0 15px rgba(0, 255, 204, 0.3);
100
+ }
101
+
102
+ .zone-title {
103
+ font-weight: bold;
104
+ font-size: 1.2rem;
105
+ margin-bottom: 5px;
106
+ display: block;
107
+ }
108
+
109
+ .zone-desc {
110
+ font-size: 0.8rem;
111
+ color: #aaa;
112
+ }
113
+
114
+ /* HUD */
115
+ #hud {
116
+ position: absolute;
117
+ top: 0;
118
+ left: 0;
119
+ width: 100%;
120
+ padding: 20px;
121
+ display: flex;
122
+ justify-content: space-between;
123
+ pointer-events: none;
124
+ z-index: 5;
125
+ }
126
+
127
+ .hud-panel {
128
+ background: var(--ui-bg);
129
+ padding: 10px 20px;
130
+ border-radius: 4px;
131
+ border-left: 3px solid var(--primary);
132
+ font-size: 1.2rem;
133
+ text-shadow: 1px 1px 0 #000;
134
+ }
135
+
136
+ .hud-right {
137
+ text-align: right;
138
+ border-left: none;
139
+ border-right: 3px solid var(--primary);
140
+ }
141
+
142
+ #zone-indicator {
143
+ position: absolute;
144
+ top: 80px;
145
+ left: 20px;
146
+ font-size: 0.9rem;
147
+ color: #888;
148
+ text-transform: uppercase;
149
+ letter-spacing: 2px;
150
+ }
151
+
152
+ /* Chat Simulation */
153
+ #chat-box {
154
+ position: absolute;
155
+ bottom: 20px;
156
+ left: 20px;
157
+ width: 300px;
158
+ height: 150px;
159
+ overflow: hidden;
160
+ display: flex;
161
+ flex-direction: column;
162
+ justify-content: flex-end;
163
+ pointer-events: none;
164
+ mask-image: linear-gradient(to bottom, transparent, black 20%);
165
+ }
166
+
167
+ .chat-msg {
168
+ background: rgba(0,0,0,0.5);
169
+ padding: 4px 8px;
170
+ margin-bottom: 2px;
171
+ font-size: 0.8rem;
172
+ border-radius: 2px;
173
+ }
174
+
175
+ .chat-name { color: var(--primary); font-weight: bold; }
176
+ .chat-text { color: #eee; }
177
+
178
+ /* Controller Hint */
179
+ #controller-hint {
180
+ position: absolute;
181
+ bottom: 20px;
182
+ right: 20px;
183
+ font-size: 0.8rem;
184
+ color: #666;
185
+ display: flex;
186
+ align-items: center;
187
+ gap: 10px;
188
+ }
189
+
190
+ .icon {
191
+ width: 20px;
192
+ height: 20px;
193
+ background: #333;
194
+ border-radius: 50%;
195
+ display: inline-block;
196
+ }
197
+
198
+ /* Branding */
199
+ .branding {
200
+ position: absolute;
201
+ top: 10px;
202
+ right: 10px;
203
+ z-index: 100;
204
+ }
205
+ .branding a {
206
+ color: rgba(255,255,255,0.5);
207
+ text-decoration: none;
208
+ font-size: 0.8rem;
209
+ transition: color 0.2s;
210
+ }
211
+ .branding a:hover { color: white; }
212
+
213
+ /* Responsive */
214
+ @media (max-width: 768px) {
215
+ .zone-grid { grid-template-columns: 1fr; }
216
+ h1 { font-size: 2rem; }
217
+ #hud { flex-direction: column; gap: 10px; }
218
+ .hud-right { border-right: none; border-bottom: 3px solid var(--primary); }
219
+ }
220
+ </style>
221
+ <!-- Icons -->
222
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
223
+ </head>
224
+ <body>
225
+
226
+ <div id="game-container">
227
+ <canvas id="gameCanvas"></canvas>
228
+
229
+ <!-- Branding -->
230
+ <div class="branding">
231
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">Built with anycoder</a>
232
+ </div>
233
+
234
+ <!-- Main Menu -->
235
+ <div id="menu-overlay" class="overlay">
236
+ <h1>Subspace Continuum</h1>
237
+ <p>Choose Your Zone</p>
238
+
239
+ <div class="zone-grid">
240
+ <div class="zone-card" onclick="startGame('green')">
241
+ <span class="zone-title" style="color:#4caf50">Green Zone</span>
242
+ <span class="zone-desc">Standard Physics<br>Low Threat</span>
243
+ </div>
244
+ <div class="zone-card" onclick="startGame('ice')">
245
+ <span class="zone-title" style="color:#00bcd4">Ice Fields</span>
246
+ <span class="zone-desc">Low Friction<br>Slippery Combat</span>
247
+ </div>
248
+ <div class="zone-card" onclick="startGame('war')">
249
+ <span class="zone-title" style="color:#f44336">War Zone</span>
250
+ <span class="zone-desc">High Friction<br>Aggressive AI</span>
251
+ </div>
252
+ <div class="zone-card" onclick="startGame('chaos')">
253
+ <span class="zone-title" style="color:#9c27b0">Chaos Sector</span>
254
+ <span class="zone-desc">Zero Gravity<br>Erratic Enemies</span>
255
+ </div>
256
+ </div>
257
+
258
+ <p style="margin-top: 30px; font-size: 0.8rem; color: #888;">
259
+ Controls: WASD/Arrows to Move &bull; Space to Shoot<br>
260
+ Controller: Left Stick to Move &bull; A/Cross to Shoot
261
+ </p>
262
+ </div>
263
+
264
+ <!-- HUD -->
265
+ <div id="hud" class="hidden">
266
+ <div class="hud-panel">
267
+ <div>SCORE: <span id="score-display">0</span></div>
268
+ <div style="font-size: 0.8em; color: #aaa;">KILLS: <span id="kills-display">0</span></div>
269
+ </div>
270
+ <div id="zone-indicator">Current Zone: <span id="zone-name-display">GREEN</span></div>
271
+ <div class="hud-panel hud-right">
272
+ <div style="color: var(--danger)">HP: <span id="hp-display">100</span>%</div>
273
+ <div>ENERGY: <span id="energy-display">100</span>%</div>
274
+ </div>
275
+ </div>
276
+
277
+ <!-- Chat Simulation -->
278
+ <div id="chat-box" class="hidden"></div>
279
+
280
+ <!-- Controller Status -->
281
+ <div id="controller-hint">
282
+ <i class="fas fa-gamepad"></i> <span id="controller-status">No Controller Detected</span>
283
+ </div>
284
+ </div>
285
+
286
+ <script>
287
+ /**
288
+ * SUBSPACE CONTINUUM CLONE
289
+ * Single File Implementation
290
+ */
291
+
292
+ // --- Configuration & Constants ---
293
+ const CANVAS = document.getElementById('gameCanvas');
294
+ const CTX = CANVAS.getContext('2d');
295
+ const UI = {
296
+ menu: document.getElementById('menu-overlay'),
297
+ hud: document.getElementById('hud'),
298
+ chat: document.getElementById('chat-box'),
299
+ score: document.getElementById('score-display'),
300
+ kills: document.getElementById('kills-display'),
301
+ hp: document.getElementById('hp-display'),
302
+ energy: document.getElementById('energy-display'),
303
+ zoneName: document.getElementById('zone-name-display'),
304
+ ctrlStatus: document.getElementById('controller-status')
305
+ };
306
+
307
+ const ZONES = {
308
+ green: { name: 'GREEN', color: '#1a2f1a', grid: '#2d4a2d', friction: 0.92, botCount: 5, botAggro: 0.01 },
309
+ ice: { name: 'ICE', color: '#0f1f2f', grid: '#1a3a5a', friction: 0.98, botCount: 8, botAggro: 0.02 },
310
+ war: { name: 'WAR', color: '#2f0f0f', grid: '#5a1a1a', friction: 0.85, botCount: 15, botAggro: 0.05 },
311
+ chaos: { name: 'CHAOS', color: '#1f0f2f', grid: '#3a1a5a', friction: 0.995, botCount: 10, botAggro: 0.03 }
312
+ };
313
+
314
+ let GAME_STATE = 'MENU'; // MENU, PLAYING, GAMEOVER
315
+ let CURRENT_ZONE = 'green';
316
+ let LAST_TIME = 0;
317
+ let GAMEPAD_INDEX = null;
318
+
319
+ // --- Game Entities ---
320
+
321
+ class Entity {
322
+ constructor(x, y, radius, color) {
323
+ this.x = x;
324
+ this.y = y;
325
+ this.radius = radius;
326
+ this.color = color;
327
+ this.vx = 0;
328
+ this.vy = 0;
329
+ this.angle = 0;
330
+ this.dead = false;
331
+ }
332
+
333
+ update(dt) {
334
+ // Apply velocity
335
+ this.x += this.vx;
336
+ this.y += this.vy;
337
+
338
+ // Screen Wrap (Subspace style)
339
+ if (this.x < -this.radius) this.x = CANVAS.width + this.radius;
340
+ if (this.x > CANVAS.width + this.radius) this.x = -this.radius;
341
+ if (this.y < -this.radius) this.y = CANVAS.height + this.radius;
342
+ if (this.y > CANVAS.height + this.radius) this.y = -this.radius;
343
+ }
344
+
345
+ draw(ctx) {
346
+ ctx.beginPath();
347
+ ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
348
+ ctx.fillStyle = this.color;
349
+ ctx.fill();
350
+ }
351
+ }
352
+
353
+ class Ship extends Entity {
354
+ constructor(x, y, isPlayer = false, name = "Bot") {
355
+ super(x, y, 12, isPlayer ? '#00ffcc' : '#ff4444');
356
+ this.isPlayer = isPlayer;
357
+ this.name = name;
358
+ this.hp = 100;
359
+ this.maxHp = 100;
360
+ this.energy = 100;
361
+ this.score = 0;
362
+ this.kills = 0;
363
+ this.reloadTime = 0;
364
+ this.thrusting = false;
365
+
366
+ // Physics overrides per zone handled in main loop
367
+ }
368
+
369
+ thrust(force) {
370
+ this.thrusting = true;
371
+ this.vx += Math.cos(this.angle) * force;
372
+ this.vy += Math.sin(this.angle) * force;
373
+ }
374
+
375
+ shoot() {
376
+ if (this.reloadTime <= 0 && this.energy >= 5) {
377
+ this.energy -= 5;
378
+ this.reloadTime = 15; // Frames
379
+
380
+ // Spawn bullet
381
+ const bVx = Math.cos(this.angle) * 12 + this.vx * 0.5;
382
+ const bVy = Math.sin(this.angle) * 12 + this.vy * 0.5;
383
+ const bullet = new Bullet(this.x, this.y, this.angle, bVx, bVy, this.isPlayer);
384
+ bullets.push(bullet);
385
+ return true;
386
+ }
387
+ return false;
388
+ }
389
+
390
+ update(dt) {
391
+ super.update(dt);
392
+
393
+ // Friction
394
+ const zoneData = ZONES[CURRENT_ZONE];
395
+ this.vx *= zoneData.friction;
396
+ this.vy *= zoneData.friction;
397
+
398
+ // Cap speed
399
+ const speed = Math.sqrt(this.vx*this.vx + this.vy*this.vy);
400
+ const maxSpeed = 8;
401
+ if (speed > maxSpeed) {
402
+ const ratio = maxSpeed / speed;
403
+ this.vx *= ratio;
404
+ this.vy *= ratio;
405
+ }
406
+
407
+ if (this.reloadTime > 0) this.reloadTime--;
408
+ if (this.energy < 100) this.energy += 0.2;
409
+
410
+ // Death check
411
+ if (this.hp <= 0) {
412
+ this.dead = true;
413
+ createExplosion(this.x, this.y, this.color);
414
+ if (!this.isPlayer) {
415
+ // Player killed bot
416
+ player.kills++;
417
+ player.score += 100;
418
+ spawnPrize(this.x, this.y);
419
+ addChatMessage("System", `${this.name} was destroyed.`);
420
+ } else {
421
+ // Player died
422
+ addChatMessage("System", "You were destroyed! Respawn in 3s...");
423
+ setTimeout(() => respawnPlayer(), 3000);
424
+ }
425
+ }
426
+ }
427
+
428
+ draw(ctx) {
429
+ ctx.save();
430
+ ctx.translate(this.x, this.y);
431
+ ctx.rotate(this.angle);
432
+
433
+ // Draw Ship Body
434
+ ctx.beginPath();
435
+ ctx.moveTo(15, 0);
436
+ ctx.lineTo(-10, 10);
437
+ ctx.lineTo(-5, 0);
438
+ ctx.lineTo(-10, -10);
439
+ ctx.closePath();
440
+
441
+ ctx.fillStyle = this.color;
442
+ ctx.fill();
443
+
444
+ // Engine Glow
445
+ if (this.thrusting) {
446
+ ctx.beginPath();
447
+ ctx.moveTo(-8, 0);
448
+ ctx.lineTo(-18, 0);
449
+ ctx.strokeStyle = '#ffaa00';
450
+ ctx.lineWidth = 4;
451
+ ctx.stroke();
452
+ this.thrusting = false; // Reset for next frame
453
+ }
454
+
455
+ // Name Tag
456
+ if (!this.isPlayer) {
457
+ ctx.rotate(-this.angle); // Reset rotation for text
458
+ ctx.fillStyle = 'white';
459
+ ctx.font = '10px Arial';
460
+ ctx.textAlign = 'center';
461
+ ctx.fillText(this.name, 0, -20);
462
+ }
463
+
464
+ ctx.restore();
465
+ }
466
+ }
467
+
468
+ class Bullet extends Entity {
469
+ constructor(x, y, angle, vx, vy, isPlayerBullet) {
470
+ super(x, y, 3, isPlayerBullet ? '#ffff00' : '#ff8800');
471
+ this.vx = vx;
472
+ this.vy = vy;
473
+ this.isPlayerBullet = isPlayerBullet;
474
+ this.life = 60; // Frames
475
+ }
476
+
477
+ update(dt) {
478
+ super.update(dt);
479
+ this.life--;
480
+ if (this.life <= 0) this.dead = true;
481
+ }
482
+
483
+ draw(ctx) {
484
+ ctx.beginPath();
485
+ ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
486
+ ctx.fillStyle = this.color;
487
+ ctx.fill();
488
+ // Glow
489
+ ctx.shadowBlur = 5;
490
+ ctx.shadowColor = this.color;
491
+ ctx.fill();
492
+ ctx.shadowBlur = 0;
493
+ }
494
+ }
495
+
496
+ class Prize extends Entity {
497
+ constructor(x, y, type) {
498
+ super(x, y, 6, type === 'green' ? '#00ff00' : '#ffd700');
499
+ this.type = type; // green = health, gold = energy
500
+ this.bobOffset = Math.random() * Math.PI * 2;
501
+ }
502
+
503
+ draw(ctx) {
504
+ const bob = Math.sin(Date.now() / 200 + this.bobOffset) * 2;
505
+ ctx.beginPath();
506
+ ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
507
+ ctx.fillStyle = this.color;
508
+ ctx.fill();
509
+
510
+ ctx.fillStyle = 'white';
511
+ ctx.font = '10px Arial';
512
+ ctx.textAlign = 'center';
513
+ ctx.textBaseline = 'middle';
514
+ ctx.fillText(this.type === 'green' ? '+' : '⚡', this.x, this.y + bob);
515
+ }
516
+ }
517
+
518
+ class Particle extends Entity {
519
+ constructor(x, y, color) {
520
+ super(x, y, Math.random() * 3 + 1, color);
521
+ const angle = Math.random() * Math.PI * 2;
522
+ const speed = Math.random() * 3;
523
+ this.vx = Math.cos(angle) * speed;
524
+ this.vy = Math.sin(angle) * speed;
525
+ this.life = 30;
526
+ }
527
+ update(dt) {
528
+ super.update(dt);
529
+ this.life--;
530
+ if(this.life <= 0) this.dead = true;
531
+ }
532
+ draw(ctx) {
533
+ ctx.globalAlpha = this.life / 30;
534
+ super.draw(ctx);
535
+ ctx.globalAlpha = 1;
536
+ }
537
+ }
538
+
539
+ // --- Global State ---
540
+ let player;
541
+ let bots = [];
542
+ let bullets = [];
543
+ let prizes = [];
544
+ let particles = [];
545
+ let chatMessages = [];
546
+
547
+ // --- Input Handling ---
548
+ const keys = {};
549
+
550
+ window.addEventListener('keydown', e => keys[e.code] = true);
551
+ window.addEventListener('keyup', e => keys[e.code] = false);
552
+
553
+ // Gamepad Polling
554
+ function handleGamepad() {
555
+ const gamepads = navigator.getGamepads();
556
+ if (!gamepads[0]) {
557
+ UI.ctrlStatus.innerText = "No Controller";
558
+ UI.ctrlStatus.style.color = "#666";
559
+ GAMEPAD_INDEX = null;
560
+ return;
561
+ }
562
+
563
+ const gp = gamepads[0];
564
+ if (gp) {
565
+ UI.ctrlStatus.innerText = "Controller Active";
566
+ UI.ctrlStatus.style.color = "#00ffcc";
567
+ GAMEPAD_INDEX = 0;
568
+
569
+ // Deadzone
570
+ const deadzone = 0.1;
571
+ let lx = gp.axes[0];
572
+ let ly = gp.axes[1];
573
+
574
+ if (Math.abs(lx) < deadzone) lx = 0;
575
+ if (Math.abs(ly) < deadzone) ly = 0;
576
+
577
+ // Movement (Rotate based on stick, Thrust if pushed)
578
+ if (lx !== 0 || ly !== 0) {
579
+ player.angle = Math.atan2(ly, lx);
580
+ // Calculate magnitude for thrust
581
+ const mag = Math.sqrt(lx*lx + ly*ly);
582
+ if (mag > 0.2) player.thrust(0.3);
583
+ }
584
+
585
+ // Shoot (Button 0 usually A/Cross)
586
+ if (gp.buttons[0].pressed) {
587
+ player.shoot();
588
+ }
589
+ }
590
+ }
591
+
592
+ // --- Game Logic Functions ---
593
+
594
+ function initGame(zoneKey) {
595
+ CURRENT_ZONE = zoneKey;
596
+ const zoneData = ZONES[zoneKey];
597
+
598
+ // Reset Arrays
599
+ bots = [];
600
+ bullets = [];
601
+ prizes = [];
602
+ particles = [];
603
+
604
+ // Create Player
605
+ player = new Ship(CANVAS.width/2, CANVAS.height/2, true, "You");
606
+
607
+ // Create Bots
608
+ for(let i=0; i<zoneData.botCount; i++) {
609
+ spawnBot();
610
+ }
611
+
612
+ // UI Updates
613
+ UI.zoneName.innerText = zoneData.name;
614
+ UI.menu.classList.add('hidden');
615
+ UI.hud.classList.remove('hidden');
616
+ UI.chat.classList.remove('hidden');
617
+
618
+ GAME_STATE = 'PLAYING';
619
+ requestAnimationFrame(gameLoop);
620
+
621
+ // Start Chat Simulation
622
+ setInterval(simulateChat, 4000);
623
+ }
624
+
625
+ function spawnBot() {
626
+ const names = ["Viper", "Wraith", "Nova", "Echo", "Razor", "Spectre", "Jinx", "Blade"];
627
+ const name = names[Math.floor(Math.random() * names.length)] + Math.floor(Math.random()*99);
628
+ const x = Math.random() * CANVAS.width;
629
+ const y = Math.random() * CANVAS.height;
630
+ bots.push(new Ship(x, y, false, name));
631
+ }
632
+
633
+ function spawnPrize(x, y) {
634
+ const type = Math.random() > 0.5 ? 'green' : 'gold';
635
+ prizes.push(new Prize(x, y, type));
636
+ }
637
+
638
+ function createExplosion(x, y, color) {
639
+ for(let i=0; i<15; i++) {
640
+ particles.push(new Particle(x, y, color));
641
+ }
642
+ }
643
+
644
+ function respawnPlayer() {
645
+ player.x = CANVAS.width/2;
646
+ player.y = CANVAS.height/2;
647
+ player.vx = 0;
648
+ player.vy = 0;
649
+ player.hp = 100;
650
+ player.energy = 100;
651
+ player.dead = false;
652
+ }
653
+
654
+ function checkCollisions() {
655
+ // Bullets vs Ships
656
+ bullets.forEach(b => {
657
+ if (b.dead) return;
658
+
659
+ // Check Player
660
+ if (b.isPlayerBullet) {
661
+ bots.forEach(bot => {
662
+ if (!bot.dead && dist(b, bot) < bot.radius + b.radius) {
663
+ b.dead = true;
664
+ bot.hp -= 10;
665
+ createExplosion(b.x, b.y, '#fff');
666
+ }
667
+ });
668
+ } else {
669
+ // Bot Bullet vs Player
670
+ if (!player.dead && dist(b, player) < player.radius + b.radius) {
671
+ b.dead = true;
672
+ player.hp -= 5;
673
+ createExplosion(b.x, b.y, '#f00');
674
+ }
675
+ }
676
+ });
677
+
678
+ // Player vs Prizes
679
+ prizes.forEach((p, index) => {
680
+ if (dist(player, p) < player.radius + p.radius) {
681
+ prizes.splice(index, 1);
682
+ if (p.type === 'green') player.hp = Math.min(player.hp + 20, 100);
683
+ if (p.type === 'gold') player.energy = 100;
684
+ }
685
+ });
686
+ }
687
+
688
+ function dist(e1, e2) {
689
+ return Math.sqrt((e1.x - e2.x)**2 + (e1.y - e2.y)**2);
690
+ }
691
+
692
+ // --- AI Logic ---
693
+ function updateBots() {
694
+ bots.forEach(bot => {
695
+ if (bot.dead) return;
696
+
697
+ const dToPlayer = dist(bot, player);
698
+
699
+ // Simple State Machine
700
+ if (dToPlayer < 300 && !player.dead) {
701
+ // Chase Player
702
+ bot.angle = Math.atan2(player.y - bot.y, player.x - bot.x);
703
+ bot.thrust(0.2);
704
+
705
+ // Shoot if aligned
706
+ const angleDiff = Math.abs(bot.angle - Math.atan2(player.y - bot.y, player.x - bot.x));
707
+ if (angleDiff < 0.5) bot.shoot();
708
+ } else {
709
+ // Wander
710
+ if (Math.random() < 0.02) bot.angle += (Math.random() - 0.5);
711
+ bot.thrust(0.1);
712
+
713
+ // Random shoot
714
+ if (Math.random() < ZONES[CURRENT_ZONE].botAggro) bot.shoot();
715
+ }
716
+
717
+ // Bot Physics (Simplified)
718
+ bot.vx *= ZONES[CURRENT_ZONE].friction;
719
+ bot.vy *= ZONES[CURRENT_ZONE].friction;
720
+ bot.x += bot.vx;
721
+ bot.y += bot.vy;
722
+
723
+ // Wrap
724
+ if (bot.x < 0) bot.x = CANVAS.width;
725
+ if (bot.x > CANVAS.width) bot.x = 0;
726
+ if (bot.y < 0) bot.y = CANVAS.height;
727
+ if (bot.y > CANVAS.height) bot.y = 0;
728
+
729
+ if (bot.hp <= 0) bot.dead = true;
730
+ });
731
+
732
+ // Respawn bots
733
+ bots = bots.filter(b => !b.dead);
734
+ if (bots.length < ZONES[CURRENT_ZONE].botCount) {
735
+ if (Math.random() < 0.01) spawnBot();
736
+ }
737
+ }
738
+
739
+ // --- Chat Simulation ---
740
+ const CHAT_PHRASES = [
741
+ "Lag?", "Nice shot!", "Anyone want to team?", "Where are the prizes?",
742
+ "Campers...", "GG", "brb", "Is this zone dead?", "Warbird incoming!"
743
+ ];
744
+ const BOT_NAMES = ["Viper", "Wraith", "Nova", "Echo", "Razor"];
745
+
746
+ function simulateChat() {
747
+ if (GAME_STATE !== 'PLAYING') return;
748
+ if (Math.random() > 0.3) return; // 30% chance to chat
749
+
750
+ const name = BOT_NAMES[Math.floor(Math.random() * BOT_NAMES.length)];
751
+ const text = CHAT_PHRASES[Math.floor(Math.random() * CHAT_PHRASES.length)];
752
+ addChatMessage(name, text);
753
+ }
754
+
755
+ function addChatMessage(name, text) {
756
+ const div = document.createElement('div');
757
+ div.className = 'chat-msg';
758
+ div.innerHTML = `<span class="chat-name">${name}:</span> <span class="chat-text">${text}</span>`;
759
+ UI.chat.appendChild(div);
760
+
761
+ // Keep only last 6 messages
762
+ if (UI.chat.children.length > 6) {
763
+ UI.chat.removeChild(UI.chat.firstChild);
764
+ }
765
+ }
766
+
767
+ // --- Main Loop ---
768
+
769
+ function gameLoop(timestamp) {
770
+ if (GAME_STATE !== 'PLAYING') return;
771
+
772
+ const dt = timestamp - LAST_TIME;
773
+ LAST_TIME = timestamp;
774
+
775
+ // Clear Canvas
776
+ CTX.fillStyle = ZONES[CURRENT_ZONE].color;
777
+ CTX.fillRect(0, 0, CANVAS.width, CANVAS.height);
778
+
779
+ // Draw Grid
780
+ CTX.strokeStyle = ZONES[CURRENT_ZONE].grid;
781
+ CTX.lineWidth = 1;
782
+ CTX.beginPath();
783
+ for (let x = 0; x < CANVAS.width; x += 50) {
784
+ CTX.moveTo(x, 0);
785
+ CTX.lineTo(x, CANVAS.height);
786
+ }
787
+ for (let y = 0; y < CANVAS.height; y += 50) {
788
+ CTX.moveTo(0, y);
789
+ CTX.lineTo(CANVAS.width, y);
790
+ }
791
+ CTX.stroke();
792
+
793
+ // Handle Input (Keyboard)
794
+ if (!GAMEPAD_INDEX) {
795
+ if (keys['ArrowUp'] || keys['KeyW']) { player.thrust(0.3); }
796
+ if (keys['ArrowDown'] || keys['KeyS']) { player.thrust(-0.1); } // Reverse
797
+ if (keys['ArrowLeft'] || keys['KeyA']) { player.angle -= 0.08; }
798
+ if (keys['ArrowRight'] || keys['KeyD']) { player.angle += 0.08; }
799
+ if (keys['Space']) { player.shoot(); }
800
+ } else {
801
+ handleGamepad();
802
+ }
803
+
804
+ // Update Entities
805
+ if (!player.dead) player.update(dt);
806
+ updateBots();
807
+
808
+ bullets.forEach(b => b.update(dt));
809
+ bullets = bullets.filter(b => !b.dead);
810
+
811
+ prizes.forEach(p => p.draw(CTX)); // Prizes don't move, just draw
812
+
813
+ particles.forEach(p => p.update(dt));
814
+ particles = particles.filter(p => !p.dead);
815
+ particles.forEach(p => p.draw(CTX));
816
+
817
+ checkCollisions();
818
+
819
+ // Draw Entities
820
+ prizes.forEach(p => p.draw(CTX));
821
+ bots.forEach(b => b.draw(CTX));
822
+ bullets.forEach(b => b.draw(CTX));
823
+ if (!player.dead) player.draw(CTX);
824
+
825
+ // Update HUD
826
+ UI.score.innerText = player.score;
827
+ UI.kills.innerText = player.kills;
828
+ UI.hp.innerText = Math.floor(player.hp);
829
+ UI.energy.innerText = Math.floor(player.energy);
830
+
831
+ // HP Color
832
+ UI.hp.parentElement.style.color = player.hp < 30 ? 'red' : 'var(--danger)';
833
+
834
+ requestAnimationFrame(gameLoop);
835
+ }
836
+
837
+ // --- Initialization ---
838
+ function resize() {
839
+ CANVAS.width = window.innerWidth;
840
+ CANVAS.height = window.innerHeight;
841
+ }
842
+ window.addEventListener('resize', resize);
843
+ resize();
844
+
845
+ // Expose start function to HTML
846
+ window.startGame = initGame;
847
+
848
+ </script>
849
+ </body>
850
+ </html>