@gamebob/axon-surge 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +24 -0
  3. package/dist/axon-surge.js +1872 -0
  4. package/dist/core/EventBus.d.ts +10 -0
  5. package/dist/core/EventBus.d.ts.map +1 -0
  6. package/dist/core/GameEngine.d.ts +52 -0
  7. package/dist/core/GameEngine.d.ts.map +1 -0
  8. package/dist/core/GameLoop.d.ts +12 -0
  9. package/dist/core/GameLoop.d.ts.map +1 -0
  10. package/dist/director/SpawnerPatterns.d.ts +13 -0
  11. package/dist/director/SpawnerPatterns.d.ts.map +1 -0
  12. package/dist/director/WaveDirector.d.ts +17 -0
  13. package/dist/director/WaveDirector.d.ts.map +1 -0
  14. package/dist/entities/CoreEntity.d.ts +15 -0
  15. package/dist/entities/CoreEntity.d.ts.map +1 -0
  16. package/dist/entities/EnemyEntity.d.ts +30 -0
  17. package/dist/entities/EnemyEntity.d.ts.map +1 -0
  18. package/dist/factory/EntityFactory.d.ts +7 -0
  19. package/dist/factory/EntityFactory.d.ts.map +1 -0
  20. package/dist/i18n/I18nService.d.ts +9 -0
  21. package/dist/i18n/I18nService.d.ts.map +1 -0
  22. package/dist/i18n/locales.d.ts +22 -0
  23. package/dist/i18n/locales.d.ts.map +1 -0
  24. package/dist/index.d.ts +15 -0
  25. package/dist/index.d.ts.map +1 -0
  26. package/dist/input/InputManager.d.ts +17 -0
  27. package/dist/input/InputManager.d.ts.map +1 -0
  28. package/dist/physics/PhysicsEngine.d.ts +21 -0
  29. package/dist/physics/PhysicsEngine.d.ts.map +1 -0
  30. package/dist/physics/SpatialHash.d.ts +15 -0
  31. package/dist/physics/SpatialHash.d.ts.map +1 -0
  32. package/dist/platform/browser-platform.d.ts +25 -0
  33. package/dist/platform/browser-platform.d.ts.map +1 -0
  34. package/dist/platform/platform.d.ts +29 -0
  35. package/dist/platform/platform.d.ts.map +1 -0
  36. package/dist/pool/EnemyPool.d.ts +8 -0
  37. package/dist/pool/EnemyPool.d.ts.map +1 -0
  38. package/dist/pool/ObjectPool.d.ts +10 -0
  39. package/dist/pool/ObjectPool.d.ts.map +1 -0
  40. package/dist/render/CanvasRenderer.d.ts +24 -0
  41. package/dist/render/CanvasRenderer.d.ts.map +1 -0
  42. package/dist/render/JuiceEffects.d.ts +15 -0
  43. package/dist/render/JuiceEffects.d.ts.map +1 -0
  44. package/dist/strategies/FragmentClusterStrategy.d.ts +5 -0
  45. package/dist/strategies/FragmentClusterStrategy.d.ts.map +1 -0
  46. package/dist/strategies/GravityParasiteStrategy.d.ts +5 -0
  47. package/dist/strategies/GravityParasiteStrategy.d.ts.map +1 -0
  48. package/dist/strategies/ImpactStrategy.d.ts +20 -0
  49. package/dist/strategies/ImpactStrategy.d.ts.map +1 -0
  50. package/dist/strategies/PiercingCellStrategy.d.ts +5 -0
  51. package/dist/strategies/PiercingCellStrategy.d.ts.map +1 -0
  52. package/dist/strategies/ToxicSporeStrategy.d.ts +5 -0
  53. package/dist/strategies/ToxicSporeStrategy.d.ts.map +1 -0
  54. package/dist/styles.css +1 -0
  55. package/dist/theme/ThemeManager.d.ts +27 -0
  56. package/dist/theme/ThemeManager.d.ts.map +1 -0
  57. package/dist/types/game.d.ts +72 -0
  58. package/dist/types/game.d.ts.map +1 -0
  59. package/dist/ui/HUDOverlay.d.ts +15 -0
  60. package/dist/ui/HUDOverlay.d.ts.map +1 -0
  61. package/dist/ui/OnboardingTutorial.d.ts +14 -0
  62. package/dist/ui/OnboardingTutorial.d.ts.map +1 -0
  63. package/dist/ui/ProgressBar.d.ts +14 -0
  64. package/dist/ui/ProgressBar.d.ts.map +1 -0
  65. package/dist/ui/SettingsModal.d.ts +20 -0
  66. package/dist/ui/SettingsModal.d.ts.map +1 -0
  67. package/dist/ui/StartMenu.d.ts +11 -0
  68. package/dist/ui/StartMenu.d.ts.map +1 -0
  69. package/package.json +30 -0
@@ -0,0 +1,1872 @@
1
+ class G {
2
+ listeners = /* @__PURE__ */ new Map();
3
+ on(t, i) {
4
+ return this.listeners.has(t) || this.listeners.set(t, /* @__PURE__ */ new Set()), this.listeners.get(t).add(i), () => this.off(t, i);
5
+ }
6
+ off(t, i) {
7
+ const e = this.listeners.get(t);
8
+ e && e.delete(i);
9
+ }
10
+ emit(t, i) {
11
+ const e = this.listeners.get(t);
12
+ e && e.forEach((s) => s(i));
13
+ }
14
+ clear() {
15
+ this.listeners.clear();
16
+ }
17
+ }
18
+ class B {
19
+ animationFrameId = null;
20
+ lastTime = 0;
21
+ isRunning = !1;
22
+ updateCallback;
23
+ renderCallback;
24
+ constructor(t, i) {
25
+ this.updateCallback = t, this.renderCallback = i;
26
+ }
27
+ start() {
28
+ this.isRunning || (this.isRunning = !0, this.lastTime = performance.now(), this.tick = this.tick.bind(this), this.animationFrameId = requestAnimationFrame(this.tick));
29
+ }
30
+ stop() {
31
+ this.isRunning = !1, this.animationFrameId !== null && (cancelAnimationFrame(this.animationFrameId), this.animationFrameId = null);
32
+ }
33
+ tick(t) {
34
+ if (!this.isRunning) return;
35
+ const i = Math.min((t - this.lastTime) / 1e3, 0.1);
36
+ this.lastTime = t, this.updateCallback(i), this.renderCallback(), this.animationFrameId = requestAnimationFrame(this.tick);
37
+ }
38
+ }
39
+ class U {
40
+ position;
41
+ radius = 44;
42
+ integrity = 3;
43
+ maxIntegrity = 3;
44
+ pulsePhase = 0;
45
+ organicSeed;
46
+ constructor(t, i) {
47
+ this.position = { x: t, y: i }, this.organicSeed = Math.random() * 100;
48
+ }
49
+ update(t) {
50
+ this.pulsePhase += t * 2.8;
51
+ }
52
+ getMembraneRadius(t) {
53
+ const i = Math.sin(t * 5 + this.pulsePhase * 1.5 + this.organicSeed) * 5, e = Math.cos(t * 3 - this.pulsePhase * 2.2) * 3, s = Math.sin(t * 7 + this.pulsePhase * 3.1) * 2;
54
+ return this.radius + i + e + s;
55
+ }
56
+ takeDamage() {
57
+ return this.integrity > 0 ? (this.integrity -= 1, !0) : !1;
58
+ }
59
+ reset(t, i) {
60
+ this.position = { x: t, y: i }, this.integrity = this.maxIntegrity, this.pulsePhase = 0;
61
+ }
62
+ }
63
+ class P {
64
+ id;
65
+ position = { x: 0, y: 0 };
66
+ velocity = { x: 0, y: 0 };
67
+ radius = 20;
68
+ type = "piercer";
69
+ active = !1;
70
+ isGrabbed = !1;
71
+ isThrown = !1;
72
+ wasManipulated = !1;
73
+ rotation = 0;
74
+ color = "#ff2a5f";
75
+ strategy = null;
76
+ hitRadiusPadding = 0.5;
77
+ isDying = !1;
78
+ deathType = "none";
79
+ deathTimer = 0;
80
+ maxDeathTimer = 0.4;
81
+ sliceAngle = 0;
82
+ constructor(t) {
83
+ this.id = t;
84
+ }
85
+ getHitRadius() {
86
+ return this.radius * (1 + this.hitRadiusPadding);
87
+ }
88
+ triggerDissolveDeath() {
89
+ this.isDying || (this.isDying = !0, this.deathType = "dissolve", this.deathTimer = 0, this.maxDeathTimer = 0.45, this.velocity = { x: 0, y: 0 });
90
+ }
91
+ triggerSliceDeath(t) {
92
+ this.isDying || (this.isDying = !0, this.deathType = "sliced", this.deathTimer = 0, this.maxDeathTimer = 0.35, this.sliceAngle = t, this.velocity = { x: 0, y: 0 });
93
+ }
94
+ update(t) {
95
+ if (this.active) {
96
+ if (this.isDying) {
97
+ this.deathTimer += t, this.deathTimer >= this.maxDeathTimer && (this.active = !1, this.isDying = !1);
98
+ return;
99
+ }
100
+ this.isGrabbed || (this.position.x += this.velocity.x * t, this.position.y += this.velocity.y * t, (this.velocity.x !== 0 || this.velocity.y !== 0) && (this.rotation = Math.atan2(this.velocity.y, this.velocity.x)));
101
+ }
102
+ }
103
+ reset() {
104
+ this.active = !1, this.isGrabbed = !1, this.isThrown = !1, this.wasManipulated = !1, this.isDying = !1, this.deathType = "none", this.deathTimer = 0, this.sliceAngle = 0, this.position = { x: 0, y: 0 }, this.velocity = { x: 0, y: 0 }, this.rotation = 0, this.strategy = null;
105
+ }
106
+ }
107
+ class H {
108
+ pointerPosition = { x: 0, y: 0 };
109
+ isPointerDown = !1;
110
+ grabbedEnemy = null;
111
+ dragStart = null;
112
+ pointerHistory = [];
113
+ canvas;
114
+ constructor(t) {
115
+ this.canvas = t, this.bindEvents();
116
+ }
117
+ updatePointerPos(t, i) {
118
+ const e = this.canvas.getBoundingClientRect(), s = performance.now() / 1e3;
119
+ this.pointerPosition = {
120
+ x: t - e.left,
121
+ y: i - e.top
122
+ }, this.pointerHistory.push({
123
+ x: this.pointerPosition.x,
124
+ y: this.pointerPosition.y,
125
+ time: s
126
+ });
127
+ const a = s - 0.08;
128
+ this.pointerHistory = this.pointerHistory.filter((c) => c.time >= a), this.grabbedEnemy && (this.grabbedEnemy.position = { ...this.pointerPosition });
129
+ }
130
+ bindEvents() {
131
+ this.canvas.addEventListener("mousemove", (t) => {
132
+ this.updatePointerPos(t.clientX, t.clientY);
133
+ }), this.canvas.addEventListener("mousedown", (t) => {
134
+ t.button === 0 && (this.isPointerDown = !0, this.pointerHistory = [], this.updatePointerPos(t.clientX, t.clientY));
135
+ }), this.canvas.addEventListener("mouseup", (t) => {
136
+ t.button === 0 && (this.isPointerDown = !1);
137
+ }), this.canvas.addEventListener("touchstart", (t) => {
138
+ if (t.touches.length > 0) {
139
+ const i = t.touches[0];
140
+ this.isPointerDown = !0, this.pointerHistory = [], this.updatePointerPos(i.clientX, i.clientY);
141
+ }
142
+ }, { passive: !0 }), this.canvas.addEventListener("touchmove", (t) => {
143
+ if (t.touches.length > 0) {
144
+ const i = t.touches[0];
145
+ this.updatePointerPos(i.clientX, i.clientY);
146
+ }
147
+ }, { passive: !0 }), this.canvas.addEventListener("touchend", () => {
148
+ this.isPointerDown = !1;
149
+ }), this.canvas.addEventListener("touchcancel", () => {
150
+ this.isPointerDown = !1;
151
+ }), this.canvas.addEventListener("contextmenu", (t) => {
152
+ t.preventDefault();
153
+ });
154
+ }
155
+ tryGrab(t) {
156
+ if (this.grabbedEnemy) return this.grabbedEnemy;
157
+ for (const i of t) {
158
+ if (!i.active || i.isGrabbed || i.isThrown || i.wasManipulated) continue;
159
+ const e = this.pointerPosition.x - i.position.x, s = this.pointerPosition.y - i.position.y;
160
+ if (Math.hypot(e, s) <= i.getHitRadius())
161
+ return i.isGrabbed = !0, this.grabbedEnemy = i, this.dragStart = { ...this.pointerPosition }, this.pointerHistory = [], i;
162
+ }
163
+ return null;
164
+ }
165
+ releaseAndThrow() {
166
+ if (!this.grabbedEnemy) return null;
167
+ const t = this.grabbedEnemy;
168
+ t.isGrabbed = !1, t.isThrown = !0, t.wasManipulated = !0;
169
+ const e = performance.now() / 1e3 - 0.08, s = this.pointerHistory.filter((n) => n.time >= e);
170
+ let a = 0, c = 0;
171
+ if (s.length >= 2) {
172
+ const n = s[0], o = s[s.length - 1], r = Math.max(0.01, o.time - n.time);
173
+ a = (o.x - n.x) / r, c = (o.y - n.y) / r;
174
+ }
175
+ const h = Math.hypot(a, c);
176
+ if (h > 30) {
177
+ const o = Math.min(h * 1.15, 2500), r = Math.atan2(c, a);
178
+ t.velocity = {
179
+ x: Math.cos(r) * o,
180
+ y: Math.sin(r) * o
181
+ };
182
+ } else if (this.dragStart) {
183
+ const n = t.position.x - this.dragStart.x, o = t.position.y - this.dragStart.y, r = Math.hypot(n, o);
184
+ if (r > 5) {
185
+ const l = Math.atan2(o, n), p = Math.min(r * 4, 600);
186
+ t.velocity = {
187
+ x: Math.cos(l) * p,
188
+ y: Math.sin(l) * p
189
+ };
190
+ } else
191
+ t.velocity = { x: 0, y: 0 }, t.isThrown = !1;
192
+ }
193
+ return this.grabbedEnemy = null, this.dragStart = null, this.pointerHistory = [], t;
194
+ }
195
+ reset() {
196
+ this.grabbedEnemy = null, this.dragStart = null, this.pointerHistory = [], this.isPointerDown = !1;
197
+ }
198
+ }
199
+ class K {
200
+ cellSize;
201
+ grid = /* @__PURE__ */ new Map();
202
+ constructor(t = 100) {
203
+ this.cellSize = t;
204
+ }
205
+ clear() {
206
+ this.grid.clear();
207
+ }
208
+ insert(t) {
209
+ const i = Math.floor((t.position.x - t.radius) / this.cellSize), e = Math.floor((t.position.x + t.radius) / this.cellSize), s = Math.floor((t.position.y - t.radius) / this.cellSize), a = Math.floor((t.position.y + t.radius) / this.cellSize);
210
+ for (let c = i; c <= e; c++)
211
+ for (let h = s; h <= a; h++) {
212
+ const n = `${c}:${h}`;
213
+ this.grid.has(n) || this.grid.set(n, /* @__PURE__ */ new Set()), this.grid.get(n).add(t);
214
+ }
215
+ }
216
+ getNearby(t, i) {
217
+ const e = /* @__PURE__ */ new Set(), s = Math.floor((t.x - i) / this.cellSize), a = Math.floor((t.x + i) / this.cellSize), c = Math.floor((t.y - i) / this.cellSize), h = Math.floor((t.y + i) / this.cellSize);
218
+ for (let n = s; n <= a; n++)
219
+ for (let o = c; o <= h; o++) {
220
+ const r = `${n}:${o}`, l = this.grid.get(r);
221
+ l && l.forEach((p) => e.add(p));
222
+ }
223
+ return e;
224
+ }
225
+ }
226
+ class F {
227
+ hitstopTime = 0;
228
+ shakeTime = 0;
229
+ shakeDuration = 0.14;
230
+ shakeIntensity = 0;
231
+ shakeVector = { x: 0, y: 0 };
232
+ flashAlpha = 0;
233
+ triggerHitstop(t = 0.06) {
234
+ this.hitstopTime = t;
235
+ }
236
+ triggerFlash(t = 0.4) {
237
+ this.flashAlpha = t;
238
+ }
239
+ triggerScreenShake(t, i = 1) {
240
+ const s = 10 + Math.min(i * 3, 30), a = Math.hypot(t.x, t.y) || 1;
241
+ this.shakeVector = {
242
+ x: t.x / a * s,
243
+ y: t.y / a * s
244
+ }, this.shakeIntensity = s, this.shakeTime = this.shakeDuration;
245
+ }
246
+ update(t, i, e) {
247
+ this.hitstopTime > 0 && (this.hitstopTime -= t), this.shakeTime > 0 && (this.shakeTime -= t), this.flashAlpha > 0 && (this.flashAlpha = Math.max(0, this.flashAlpha - t * 4));
248
+ for (let s = i.length - 1; s >= 0; s--) {
249
+ const a = i[s];
250
+ a && (a.lifetime += t, a.position.x += a.velocity.x * t, a.position.y += a.velocity.y * t, a.alpha = 1 - a.lifetime / a.maxLifetime, a.lifetime >= a.maxLifetime && i.splice(s, 1));
251
+ }
252
+ for (let s = e.length - 1; s >= 0; s--) {
253
+ const a = e[s];
254
+ a && (a.lifetime += t, a.position.x += a.velocity.x * t, a.position.y += a.velocity.y * t, a.alpha = 1 - a.lifetime / a.maxLifetime, a.lifetime >= a.maxLifetime && e.splice(s, 1));
255
+ }
256
+ }
257
+ getShakeOffset() {
258
+ if (this.shakeTime <= 0) return { x: 0, y: 0 };
259
+ const t = this.shakeTime / this.shakeDuration;
260
+ return {
261
+ x: (Math.random() * 2 - 1) * this.shakeVector.x * t,
262
+ y: (Math.random() * 2 - 1) * this.shakeVector.y * t
263
+ };
264
+ }
265
+ }
266
+ const I = {
267
+ es: {
268
+ title: "AXON SURGE",
269
+ startButton: "INICIAR ENLACE",
270
+ waveLabel: "NIVEL",
271
+ scoreLabel: "PUNTAJE",
272
+ settingsTitle: "CONFIGURACION",
273
+ languageLabel: "IDIOMA",
274
+ themeLabel: "TEMA VISUAL",
275
+ hapticsLabel: "VIBRACION / HAPTICOS",
276
+ hapticsOn: "ACTIVADO",
277
+ hapticsOff: "DESACTIVADO",
278
+ creditsJam: "Desarrollado para Mini Jam 216: Axon Surge",
279
+ closeButton: "CERRAR",
280
+ grabInstruction: "MANTÉN PULSADO PARA AGARRAR UN ENEMIGO",
281
+ throwInstruction: "ARRASTRA Y SUELTA PARA LANZARLO",
282
+ comboText: "¡MULTIKILL x{combo}!"
283
+ },
284
+ en: {
285
+ title: "AXON SURGE",
286
+ startButton: "START LINK",
287
+ waveLabel: "LEVEL",
288
+ scoreLabel: "SCORE",
289
+ settingsTitle: "SETTINGS",
290
+ languageLabel: "LANGUAGE",
291
+ themeLabel: "VISUAL THEME",
292
+ hapticsLabel: "HAPTICS / VIBRATION",
293
+ hapticsOn: "ENABLED",
294
+ hapticsOff: "DISABLED",
295
+ creditsJam: "Developed for Mini Jam 216: Axon Surge",
296
+ closeButton: "CLOSE",
297
+ grabInstruction: "HOLD TO GRAB AN ENEMY",
298
+ throwInstruction: "DRAG AND RELEASE TO THROW",
299
+ comboText: "MULTIKILL x{combo}!"
300
+ },
301
+ fr: {
302
+ title: "AXON SURGE",
303
+ startButton: "DEMARRER LE LIEN",
304
+ waveLabel: "NIVEAU",
305
+ scoreLabel: "SCORE",
306
+ settingsTitle: "PARAMETRES",
307
+ languageLabel: "LANGUE",
308
+ themeLabel: "THEME VISUEL",
309
+ hapticsLabel: "RETROACTION HAPTIQUE",
310
+ hapticsOn: "ACTIVE",
311
+ hapticsOff: "DESACTIVE",
312
+ creditsJam: "Développé pour Mini Jam 216: Axon Surge",
313
+ closeButton: "FERMER",
314
+ grabInstruction: "MAINTENEZ POUR SAISIR UN ENNEMI",
315
+ throwInstruction: "GLISSEZ ET RELACHEZ POUR LANCER",
316
+ comboText: "MULTIKILL x{combo} !"
317
+ },
318
+ de: {
319
+ title: "AXON SURGE",
320
+ startButton: "LINK STARTEN",
321
+ waveLabel: "LEVEL",
322
+ scoreLabel: "PUNKTE",
323
+ settingsTitle: "EINSTELLUNGEN",
324
+ languageLabel: "SPRACHE",
325
+ themeLabel: "VISUELLES THEMA",
326
+ hapticsLabel: "HAPTISCHES FEEDBACK",
327
+ hapticsOn: "AKTIVIERT",
328
+ hapticsOff: "DEAKTIVIERT",
329
+ creditsJam: "Entwickelt für Mini Jam 216: Axon Surge",
330
+ closeButton: "SCHLIESSEN",
331
+ grabInstruction: "GEDRÜCKT HALTEN ZUM GREIFEN",
332
+ throwInstruction: "ZIEHEN UND LOSLASSEN ZUM WERFEN",
333
+ comboText: "MULTIKILL x{combo}!"
334
+ },
335
+ it: {
336
+ title: "AXON SURGE",
337
+ startButton: "AVVIA COLLEGAMENTO",
338
+ waveLabel: "LIVELLO",
339
+ scoreLabel: "PUNTEGGIO",
340
+ settingsTitle: "IMPOSTAZIONI",
341
+ languageLabel: "LINGUA",
342
+ themeLabel: "TEMA VISIVO",
343
+ hapticsLabel: "FEEDBACK TATTILE",
344
+ hapticsOn: "ATTIVATO",
345
+ hapticsOff: "DISATTIVATO",
346
+ creditsJam: "Sviluppato per Mini Jam 216: Axon Surge",
347
+ closeButton: "CHIUDI",
348
+ grabInstruction: "TIENI PREMUTO PER AFFERRARE UN NEMICO",
349
+ throwInstruction: "TRASCINA E RILASCIA PER LANCIARE",
350
+ comboText: "MULTIKILL x{combo}!"
351
+ },
352
+ pt: {
353
+ title: "AXON SURGE",
354
+ startButton: "INICIAR CONEXÃO",
355
+ waveLabel: "NÍVEL",
356
+ scoreLabel: "PONTUAÇÃO",
357
+ settingsTitle: "CONFIGURAÇÕES",
358
+ languageLabel: "IDIOMA",
359
+ themeLabel: "TEMA VISUAL",
360
+ hapticsLabel: "RESPOSTA TÁTIL",
361
+ hapticsOn: "ATIVADO",
362
+ hapticsOff: "DESATIVADO",
363
+ creditsJam: "Desenvolvido para Mini Jam 216: Axon Surge",
364
+ closeButton: "FECHAR",
365
+ grabInstruction: "SEGURE PARA AGARRAR UM INIMIGO",
366
+ throwInstruction: "ARRASTE E SOLTE PARA LANÇAR",
367
+ comboText: "MULTIKILL x{combo}!"
368
+ },
369
+ nl: {
370
+ title: "AXON SURGE",
371
+ startButton: "VERBINDING STARTEN",
372
+ waveLabel: "NIVEAU",
373
+ scoreLabel: "SCORE",
374
+ settingsTitle: "INSTELLINGEN",
375
+ languageLabel: "TAAL",
376
+ themeLabel: "VISUEEL THEMA",
377
+ hapticsLabel: "HAPTISCHE FEEDBACK",
378
+ hapticsOn: "INGESCHAKELD",
379
+ hapticsOff: "UITGESCHAKELD",
380
+ creditsJam: "Ontwikkeld voor Mini Jam 216: Axon Surge",
381
+ closeButton: "SLUITEN",
382
+ grabInstruction: "HOUD INGEDRUKT OM EEN VIJAND TE PAKKEN",
383
+ throwInstruction: "SLEEP EN LAAT LOS OM TE GOOIEN",
384
+ comboText: "MULTIKILL x{combo}!"
385
+ },
386
+ sv: {
387
+ title: "AXON SURGE",
388
+ startButton: "STARTA LÄNK",
389
+ waveLabel: "NIVÅ",
390
+ scoreLabel: "POÄNG",
391
+ settingsTitle: "INSTÄLLNINGAR",
392
+ languageLabel: "SPRÅK",
393
+ themeLabel: "VISUELLT TEMA",
394
+ hapticsLabel: "HAPTISK FEEDBACK",
395
+ hapticsOn: "AKTIVERAD",
396
+ hapticsOff: "INAKTIVERAD",
397
+ creditsJam: "Utvecklat för Mini Jam 216: Axon Surge",
398
+ closeButton: "STÄNG",
399
+ grabInstruction: "HÅLL INNE FÖR ATT GREPPA EN FIENDE",
400
+ throwInstruction: "DRA OCH SLÄPP FÖR ATT KASTA",
401
+ comboText: "MULTIKILL x{combo}!"
402
+ },
403
+ pl: {
404
+ title: "AXON SURGE",
405
+ startButton: "ROZPOCZNIJ POŁĄCZENIE",
406
+ waveLabel: "POZIOM",
407
+ scoreLabel: "WYNIK",
408
+ settingsTitle: "USTAWIENIA",
409
+ languageLabel: "JĘZYK",
410
+ themeLabel: "MOTYW WIZUALNY",
411
+ hapticsLabel: "WIBRACJE HAPTYCZNE",
412
+ hapticsOn: "WŁĄCZONE",
413
+ hapticsOff: "WYŁĄCZONE",
414
+ creditsJam: "Stworzono dla Mini Jam 216: Axon Surge",
415
+ closeButton: "ZAMKNIJ",
416
+ grabInstruction: "PRZYTRZYMAJ, ABY CHWYCIĆ WROGA",
417
+ throwInstruction: "PRZECIĄGNIJ I PUŚĆ, ABY RZUCIĆ",
418
+ comboText: "MULTIKILL x{combo}!"
419
+ },
420
+ id: {
421
+ title: "AXON SURGE",
422
+ startButton: "MULAILAH KONEKSI",
423
+ waveLabel: "TINGKAT",
424
+ scoreLabel: "SKOR",
425
+ settingsTitle: "PENGATURAN",
426
+ languageLabel: "BAHASA",
427
+ themeLabel: "TEMA VISUAL",
428
+ hapticsLabel: "UUMPAN BALIK HAPTIK",
429
+ hapticsOn: "AKTIF",
430
+ hapticsOff: "NONAKTIF",
431
+ creditsJam: "Dibuat untuk Mini Jam 216: Axon Surge",
432
+ closeButton: "TUTUP",
433
+ grabInstruction: "TAHAN UNTUK MEMEGANG MUSUH",
434
+ throwInstruction: "GESER DAN LEPAS UNTUK MELEMPAR",
435
+ comboText: "MULTIKILL x{combo}!"
436
+ },
437
+ tr: {
438
+ title: "AXON SURGE",
439
+ startButton: "BAĞLANTIYI BAŞLAT",
440
+ waveLabel: "SEVİYE",
441
+ scoreLabel: "SKOR",
442
+ settingsTitle: "AYARLAR",
443
+ languageLabel: "DİL",
444
+ themeLabel: "GÖRSEL TEMA",
445
+ hapticsLabel: "TİTREŞİM BİLDİRİMİ",
446
+ hapticsOn: "AÇIK",
447
+ hapticsOff: "KAPALI",
448
+ creditsJam: "Mini Jam 216 için geliştirildi: Axon Surge",
449
+ closeButton: "KAPAT",
450
+ grabInstruction: "DÜŞMANI YAKALAMAK İÇİN BASILI TUTUN",
451
+ throwInstruction: "FIRLATMAK İÇİN SÜRÜKLEYİP BIRAKIN",
452
+ comboText: "MULTIKILL x{combo}!"
453
+ },
454
+ ru: {
455
+ title: "AXON SURGE",
456
+ startButton: "НАЧАТЬ СВЯЗЬ",
457
+ waveLabel: "УРОВЕНЬ",
458
+ scoreLabel: "СЧЕТ",
459
+ settingsTitle: "НАСТРОЙКИ",
460
+ languageLabel: "ЯЗЫК",
461
+ themeLabel: "ВИЗУАЛЬНАЯ ТЕМА",
462
+ hapticsLabel: "ТАКТИЛЬНЫЙ ОТКЛИК",
463
+ hapticsOn: "ВКЛЮЧЕНО",
464
+ hapticsOff: "ВЫКЛЮЧЕНО",
465
+ creditsJam: "Разработано для Mini Jam 216: Axon Surge",
466
+ closeButton: "ЗАКРЫТЬ",
467
+ grabInstruction: "УДЕРЖИВАЙТЕ, ЧТОБЫ СХВАТИТЬ ВРАГА",
468
+ throwInstruction: "ПЕРЕТАЩИТЕ И ОТПУСТИТЕ ДЛЯ БРОСКА",
469
+ comboText: "МУЛЬТИКИЛЛ x{combo}!"
470
+ },
471
+ ja: {
472
+ title: "AXON SURGE",
473
+ startButton: "リンク開始",
474
+ waveLabel: "レベル",
475
+ scoreLabel: "スコア",
476
+ settingsTitle: "設定",
477
+ languageLabel: "言語",
478
+ themeLabel: "ビジュアルテーマ",
479
+ hapticsLabel: "振動フィードバック",
480
+ hapticsOn: "有効",
481
+ hapticsOff: "無効",
482
+ creditsJam: "Mini Jam 216用に開発: Axon Surge",
483
+ closeButton: "閉じる",
484
+ grabInstruction: "長押しで敵をキャッチ",
485
+ throwInstruction: "ドラッグ&リリースで投げる",
486
+ comboText: "マルチキル x{combo}!"
487
+ },
488
+ ko: {
489
+ title: "AXON SURGE",
490
+ startButton: "링크 시작",
491
+ waveLabel: "레벨",
492
+ scoreLabel: "점수",
493
+ settingsTitle: "설정",
494
+ languageLabel: "언어",
495
+ themeLabel: "비주얼 테마",
496
+ hapticsLabel: "진동 피드백",
497
+ hapticsOn: "켜짐",
498
+ hapticsOff: "꺼짐",
499
+ creditsJam: "Mini Jam 216 전용 개발: Axon Surge",
500
+ closeButton: "닫기",
501
+ grabInstruction: "길게 눌러 적 잡기",
502
+ throwInstruction: "드래그 후 놓아서 던지기",
503
+ comboText: "멀티킬 x{combo}!"
504
+ },
505
+ zh: {
506
+ title: "AXON SURGE",
507
+ startButton: "启动链接",
508
+ waveLabel: "等级",
509
+ scoreLabel: "得分",
510
+ settingsTitle: "设置",
511
+ languageLabel: "语言",
512
+ themeLabel: "视觉主题",
513
+ hapticsLabel: "触觉反馈",
514
+ hapticsOn: "已启用",
515
+ hapticsOff: "已禁用",
516
+ creditsJam: "为 Mini Jam 216 开发: Axon Surge",
517
+ closeButton: "关闭",
518
+ grabInstruction: "按住以抓住敌人",
519
+ throwInstruction: "拖动并释放以抛投",
520
+ comboText: "多重击杀 x{combo}!"
521
+ }
522
+ }, k = [
523
+ "es",
524
+ "en",
525
+ "fr",
526
+ "de",
527
+ "it",
528
+ "pt",
529
+ "nl",
530
+ "sv",
531
+ "pl",
532
+ "id",
533
+ "tr",
534
+ "ru",
535
+ "ja",
536
+ "ko",
537
+ "zh"
538
+ ];
539
+ function V(x) {
540
+ return k.includes(x);
541
+ }
542
+ const N = "axon_surge_language";
543
+ class J {
544
+ currentLanguage;
545
+ constructor(t) {
546
+ if (t && I[t])
547
+ this.currentLanguage = t;
548
+ else {
549
+ let i = "es";
550
+ try {
551
+ const e = localStorage.getItem(N);
552
+ e && V(e) && (i = e);
553
+ } catch {
554
+ }
555
+ this.currentLanguage = i;
556
+ }
557
+ }
558
+ setLanguage(t) {
559
+ if (I[t]) {
560
+ this.currentLanguage = t;
561
+ try {
562
+ localStorage.setItem(N, t);
563
+ } catch {
564
+ }
565
+ }
566
+ }
567
+ getLanguage() {
568
+ return this.currentLanguage;
569
+ }
570
+ translate(t, i) {
571
+ let s = (I[this.currentLanguage] || I.es)[t] || I.es[t] || String(t);
572
+ return i && Object.entries(i).forEach(([a, c]) => {
573
+ s = s.replace(`{${a}}`, String(c));
574
+ }), s;
575
+ }
576
+ }
577
+ class Y {
578
+ execute(t) {
579
+ const { thrownEnemy: i, targetEnemy: e, shockwaves: s, particles: a, floatingTexts: c } = t;
580
+ e.active = !1, s.push({
581
+ id: Math.random().toString(),
582
+ position: { ...e.position },
583
+ radius: 10,
584
+ maxRadius: 180,
585
+ color: "#ff2a5f",
586
+ alpha: 1,
587
+ lifetime: 0,
588
+ maxLifetime: 0.5
589
+ });
590
+ for (let h = 0; h < 30; h++) {
591
+ const n = Math.random() * Math.PI * 2, o = 180 + Math.random() * 320;
592
+ a.push({
593
+ id: Math.random().toString(),
594
+ position: { ...e.position },
595
+ velocity: { x: Math.cos(n) * o, y: Math.sin(n) * o },
596
+ color: "#ff2a5f",
597
+ radius: 3 + Math.random() * 4,
598
+ alpha: 1,
599
+ lifetime: 0,
600
+ maxLifetime: 0.5
601
+ });
602
+ }
603
+ c.push({
604
+ id: Math.random().toString(),
605
+ text: "PIERCING SLICE",
606
+ position: { ...e.position },
607
+ velocity: { x: 0, y: -50 },
608
+ color: "#ff2a5f",
609
+ alpha: 1,
610
+ lifetime: 0,
611
+ maxLifetime: 0.8,
612
+ size: 20
613
+ });
614
+ }
615
+ }
616
+ class W {
617
+ execute(t) {
618
+ const { thrownEnemy: i, pools: e, shockwaves: s, particles: a, floatingTexts: c, eventBus: h } = t, n = i.position;
619
+ e.push({
620
+ id: Math.random().toString(),
621
+ position: { ...n },
622
+ radius: 220,
623
+ duration: 0,
624
+ maxDuration: 7,
625
+ damage: 50
626
+ }), s.push({
627
+ id: Math.random().toString(),
628
+ position: { ...n },
629
+ radius: 10,
630
+ maxRadius: 240,
631
+ color: "#39ff14",
632
+ alpha: 1,
633
+ lifetime: 0,
634
+ maxLifetime: 0.6
635
+ });
636
+ for (let o = 0; o < 45; o++) {
637
+ const r = Math.random() * Math.PI * 2, l = 120 + Math.random() * 260;
638
+ a.push({
639
+ id: Math.random().toString(),
640
+ position: { ...n },
641
+ velocity: { x: Math.cos(r) * l, y: Math.sin(r) * l },
642
+ color: "#39ff14",
643
+ radius: 4 + Math.random() * 5,
644
+ alpha: 1,
645
+ lifetime: 0,
646
+ maxLifetime: 0.9
647
+ });
648
+ }
649
+ c.push({
650
+ id: Math.random().toString(),
651
+ text: "MASSIVE SPORE NEBULA",
652
+ position: { ...n },
653
+ velocity: { x: 0, y: -60 },
654
+ color: "#39ff14",
655
+ alpha: 1,
656
+ lifetime: 0,
657
+ maxLifetime: 1.2,
658
+ size: 26
659
+ }), i.active = !1, h.emit("onPoolCreated", { position: n });
660
+ }
661
+ }
662
+ class X {
663
+ execute(t) {
664
+ const { thrownEnemy: i, targetEnemy: e, allEnemies: s, shockwaves: a, particles: c, floatingTexts: h } = t, n = e.position;
665
+ i.active = !1, e.active = !1, a.push({
666
+ id: Math.random().toString(),
667
+ position: { ...n },
668
+ radius: 15,
669
+ maxRadius: 280,
670
+ color: "#ffd700",
671
+ alpha: 1,
672
+ lifetime: 0,
673
+ maxLifetime: 0.6
674
+ });
675
+ for (let o = 0; o < 6; o++) {
676
+ const r = o * Math.PI * 2 / 6, l = {
677
+ x: n.x + Math.cos(r) * 15,
678
+ y: n.y + Math.sin(r) * 15
679
+ }, p = L.createEnemy("micro", l, {
680
+ x: l.x + Math.cos(r) * 200,
681
+ y: l.y + Math.sin(r) * 200
682
+ });
683
+ p.isThrown = !0, s.push(p);
684
+ }
685
+ for (let o = 0; o < 35; o++) {
686
+ const r = Math.random() * Math.PI * 2, l = 200 + Math.random() * 300;
687
+ c.push({
688
+ id: Math.random().toString(),
689
+ position: { ...n },
690
+ velocity: { x: Math.cos(r) * l, y: Math.sin(r) * l },
691
+ color: "#ffd700",
692
+ radius: 4 + Math.random() * 4,
693
+ alpha: 1,
694
+ lifetime: 0,
695
+ maxLifetime: 0.6
696
+ });
697
+ }
698
+ h.push({
699
+ id: Math.random().toString(),
700
+ text: "CLUSTER DETONATION",
701
+ position: { ...n },
702
+ velocity: { x: 0, y: -60 },
703
+ color: "#ffd700",
704
+ alpha: 1,
705
+ lifetime: 0,
706
+ maxLifetime: 1,
707
+ size: 24
708
+ });
709
+ }
710
+ }
711
+ class $ {
712
+ execute(t) {
713
+ const { thrownEnemy: i, targetEnemy: e, vortices: s, shockwaves: a } = t, c = {
714
+ x: (i.position.x + e.position.x) / 2,
715
+ y: (i.position.y + e.position.y) / 2
716
+ };
717
+ s.push({
718
+ id: Math.random().toString(),
719
+ position: c,
720
+ radius: 480,
721
+ duration: 0,
722
+ maxDuration: 6,
723
+ pullForce: 3500
724
+ }), a.push({
725
+ id: Math.random().toString(),
726
+ position: c,
727
+ radius: 20,
728
+ maxRadius: 480,
729
+ color: "#9d4edd",
730
+ alpha: 1,
731
+ lifetime: 0,
732
+ maxLifetime: 0.65
733
+ }), i.triggerDissolveDeath(), e.triggerDissolveDeath();
734
+ }
735
+ }
736
+ class L {
737
+ static createEnemy(t, i, e) {
738
+ const s = `enemy_${Date.now()}_${Math.random()}`, a = new P(s);
739
+ return this.configureEnemy(a, t, i, e), a;
740
+ }
741
+ static configureEnemy(t, i, e, s) {
742
+ t.type = i, t.position = { ...e }, t.active = !0, t.isGrabbed = !1, t.isThrown = !1;
743
+ const a = s.x - e.x, c = s.y - e.y, h = Math.atan2(c, a);
744
+ let n = 70, o = 20, r = "#ff2a5f", l = null;
745
+ i === "piercer" ? (n = 95, o = 18, r = "#ff2a5f", l = new Y()) : i === "spore" ? (n = 65, o = 24, r = "#39ff14", l = new W()) : i === "cluster" ? (n = 50, o = 26, r = "#ffd700", l = new X()) : i === "parasite" ? (n = 80, o = 22, r = "#9d4edd", l = new $()) : i === "micro" && (n = 130, o = 12, r = "#ffd700"), t.radius = o, t.color = r, t.strategy = l, t.velocity = {
746
+ x: Math.cos(h) * n,
747
+ y: Math.sin(h) * n
748
+ };
749
+ }
750
+ }
751
+ class z {
752
+ spatialHash;
753
+ eventBus;
754
+ i18n;
755
+ currentThrowKills = 0;
756
+ currentThrowPos = null;
757
+ constructor(t, i) {
758
+ this.spatialHash = new K(100), this.eventBus = t, this.i18n = i;
759
+ }
760
+ update(t, i, e, s, a, c, h, n, o, r, l, p, f, g) {
761
+ this.spatialHash.clear();
762
+ for (const d of e)
763
+ d.active && !d.isDying ? (d.update(t), this.spatialHash.insert(d)) : d.active && d.isDying && d.update(t);
764
+ for (let d = c.length - 1; d >= 0; d--) {
765
+ const m = c[d];
766
+ if (!m) continue;
767
+ m.lifetime += t;
768
+ const u = m.lifetime / m.maxLifetime;
769
+ m.radius = m.maxRadius * u, m.alpha = Math.max(0, 1 - u), m.lifetime >= m.maxLifetime && c.splice(d, 1);
770
+ }
771
+ for (let d = a.length - 1; d >= 0; d--) {
772
+ const m = a[d];
773
+ if (m) {
774
+ m.duration += t;
775
+ for (const u of e) {
776
+ if (!u.active || u.isGrabbed || u.isDying || u.isThrown && u.type === "piercer") continue;
777
+ const y = m.position.x - u.position.x, v = m.position.y - u.position.y, S = Math.hypot(y, v);
778
+ if (S > 2 && S <= m.radius) {
779
+ const T = Math.pow(1 - S / m.radius, 0.7), M = m.pullForce * T, E = Math.atan2(v, y);
780
+ u.velocity.x += Math.cos(E) * M * t, u.velocity.y += Math.sin(E) * M * t, u.position.x += Math.cos(E) * M * t * 0.8, u.position.y += Math.sin(E) * M * t * 0.8;
781
+ }
782
+ }
783
+ m.duration >= m.maxDuration && a.splice(d, 1);
784
+ }
785
+ }
786
+ for (const d of e) {
787
+ if (!d.active || d.isGrabbed || d.isDying) continue;
788
+ const m = i.position.x - d.position.x, u = i.position.y - d.position.y;
789
+ if (Math.hypot(m, u) <= i.radius + d.radius) {
790
+ d.active = !1;
791
+ const v = i.takeDamage();
792
+ this.eventBus.emit("onCoreDamaged", { currentIntegrity: i.integrity }), c.push({
793
+ id: Math.random().toString(),
794
+ position: { ...i.position },
795
+ radius: 20,
796
+ maxRadius: Math.max(p, f) * 1.3,
797
+ color: "#00f0ff",
798
+ alpha: 1,
799
+ lifetime: 0,
800
+ maxLifetime: 0.8
801
+ }), o.triggerScreenShake({ x: m, y: u }, 25), o.triggerHitstop(0.15), o.triggerFlash(0.6);
802
+ for (const S of e)
803
+ if (S.active && !S.isGrabbed) {
804
+ S.triggerDissolveDeath();
805
+ for (let T = 0; T < 8; T++) {
806
+ const M = Math.random() * Math.PI * 2, E = 100 + Math.random() * 200;
807
+ h.push({
808
+ id: Math.random().toString(),
809
+ position: { ...S.position },
810
+ velocity: { x: Math.cos(M) * E, y: Math.sin(M) * E },
811
+ color: "#00f0ff",
812
+ radius: 3 + Math.random() * 3,
813
+ alpha: 1,
814
+ lifetime: 0,
815
+ maxLifetime: 0.5
816
+ });
817
+ }
818
+ }
819
+ n.push({
820
+ id: Math.random().toString(),
821
+ text: "CORE OVERLOAD PULSE!",
822
+ position: { ...i.position },
823
+ velocity: { x: 0, y: -90 },
824
+ color: "#00f0ff",
825
+ alpha: 1,
826
+ lifetime: 0,
827
+ maxLifetime: 1.5,
828
+ size: 32
829
+ }), (!v || i.integrity <= 0) && this.eventBus.emit("onGameOver", { score: l.value, wave: 1 });
830
+ break;
831
+ }
832
+ }
833
+ let b = !1;
834
+ for (const d of e) {
835
+ if (!d.active || !d.isThrown || d.isDying) continue;
836
+ if (b = !0, d.position.x < -120 || d.position.x > p + 120 || d.position.y < -120 || d.position.y > f + 120) {
837
+ d.active = !1, d.isThrown = !1;
838
+ continue;
839
+ }
840
+ const m = this.spatialHash.getNearby(d.position, d.getHitRadius() * 2);
841
+ for (const u of m) {
842
+ if (u === d || !u.active || u.isGrabbed || u.isDying) continue;
843
+ const y = u.position.x - d.position.x, v = u.position.y - d.position.y;
844
+ if (Math.hypot(y, v) <= d.getHitRadius() + u.getHitRadius()) {
845
+ this.currentThrowPos = { x: d.position.x, y: d.position.y };
846
+ const T = Math.atan2(d.velocity.y, d.velocity.x);
847
+ if (d.type === "piercer") {
848
+ this.currentThrowKills++, this.killEnemyWithChainReaction(u, T, s, a, c, h, e), o.triggerHitstop(0.05), o.triggerScreenShake({ x: y, y: v }, 7), c.push({
849
+ id: Math.random().toString(),
850
+ position: { ...u.position },
851
+ radius: 10,
852
+ maxRadius: 180,
853
+ color: "#ff2a5f",
854
+ alpha: 1,
855
+ lifetime: 0,
856
+ maxLifetime: 0.45
857
+ });
858
+ for (let M = 0; M < 16; M++) {
859
+ const E = Math.random() * Math.PI * 2, w = 150 + Math.random() * 300;
860
+ h.push({
861
+ id: Math.random().toString(),
862
+ position: { ...u.position },
863
+ velocity: { x: Math.cos(E) * w, y: Math.sin(E) * w },
864
+ color: "#ff2a5f",
865
+ radius: 3 + Math.random() * 3,
866
+ alpha: 1,
867
+ lifetime: 0,
868
+ maxLifetime: 0.4
869
+ });
870
+ }
871
+ g && g();
872
+ } else {
873
+ const M = d.type === u.type;
874
+ c.push({
875
+ id: Math.random().toString(),
876
+ position: { ...this.currentThrowPos },
877
+ radius: 15,
878
+ maxRadius: M ? 350 : 220,
879
+ color: d.color,
880
+ alpha: 1,
881
+ lifetime: 0,
882
+ maxLifetime: 0.55
883
+ });
884
+ for (let E = 0; E < 36; E++) {
885
+ const w = Math.random() * Math.PI * 2, R = 180 + Math.random() * 400;
886
+ h.push({
887
+ id: Math.random().toString(),
888
+ position: { ...this.currentThrowPos },
889
+ velocity: { x: Math.cos(w) * R, y: Math.sin(w) * R },
890
+ color: d.color,
891
+ radius: 4 + Math.random() * 5,
892
+ alpha: 1,
893
+ lifetime: 0,
894
+ maxLifetime: 0.65
895
+ });
896
+ }
897
+ M ? (this.currentThrowKills += 3, o.triggerHitstop(0.12), o.triggerFlash(0.5), o.triggerScreenShake({ x: y, y: v }, 14), n.push({
898
+ id: Math.random().toString(),
899
+ text: "COLOR SYNERGY!",
900
+ position: { ...this.currentThrowPos },
901
+ velocity: { x: 0, y: -80 },
902
+ color: d.color,
903
+ alpha: 1,
904
+ lifetime: 0,
905
+ maxLifetime: 1.2,
906
+ size: 26
907
+ }), d.type === "spore" ? (s.push({
908
+ id: Math.random().toString(),
909
+ position: { ...this.currentThrowPos },
910
+ radius: 320,
911
+ duration: 0,
912
+ maxDuration: 10,
913
+ damage: 100
914
+ }), d.triggerDissolveDeath(), u.triggerDissolveDeath()) : d.type === "parasite" ? (a.push({
915
+ id: Math.random().toString(),
916
+ position: { ...this.currentThrowPos },
917
+ radius: 580,
918
+ duration: 0,
919
+ maxDuration: 7,
920
+ pullForce: 4500
921
+ }), d.triggerDissolveDeath(), u.triggerDissolveDeath()) : (d.triggerDissolveDeath(), u.triggerDissolveDeath())) : (this.currentThrowKills += 2, o.triggerHitstop(0.08), o.triggerFlash(0.35), o.triggerScreenShake({ x: y, y: v }, 8), this.killEnemyWithChainReaction(d, T, s, a, c, h, e), this.killEnemyWithChainReaction(u, T, s, a, c, h, e)), g && g();
922
+ break;
923
+ }
924
+ }
925
+ }
926
+ }
927
+ r.value = this.currentThrowKills, !b && this.currentThrowKills > 0 && (this.currentThrowKills >= 2 && this.currentThrowPos && n.push({
928
+ id: Math.random().toString(),
929
+ text: `MULTIKILL x${this.currentThrowKills}!`,
930
+ position: { ...this.currentThrowPos },
931
+ velocity: { x: 0, y: -90 },
932
+ color: "#ff00dd",
933
+ alpha: 1,
934
+ lifetime: 0,
935
+ maxLifetime: 1.4,
936
+ size: 32
937
+ }), this.eventBus.emit("onComboUpdated", { combo: r.value }), this.currentThrowKills = 0, this.currentThrowPos = null);
938
+ for (let d = s.length - 1; d >= 0; d--) {
939
+ const m = s[d];
940
+ if (m) {
941
+ m.duration += t;
942
+ for (const u of e) {
943
+ if (!u.active || u.isGrabbed || u.isDying || u.isThrown && u.type === "piercer") continue;
944
+ const y = u.position.x - m.position.x, v = u.position.y - m.position.y;
945
+ Math.hypot(y, v) <= m.radius && (this.killEnemyWithChainReaction(u, 0, s, a, c, h, e), this.currentThrowKills++, g && g());
946
+ }
947
+ m.duration >= m.maxDuration && s.splice(d, 1);
948
+ }
949
+ }
950
+ }
951
+ killEnemyWithChainReaction(t, i, e, s, a, c, h) {
952
+ if (!(!t.active || t.isDying))
953
+ if (a.push({
954
+ id: Math.random().toString(),
955
+ position: { ...t.position },
956
+ radius: 10,
957
+ maxRadius: 180,
958
+ color: t.color,
959
+ alpha: 1,
960
+ lifetime: 0,
961
+ maxLifetime: 0.5
962
+ }), t.type === "spore")
963
+ t.triggerDissolveDeath(), e.push({
964
+ id: Math.random().toString(),
965
+ position: { ...t.position },
966
+ radius: 200,
967
+ duration: 0,
968
+ maxDuration: 6,
969
+ damage: 50
970
+ });
971
+ else if (t.type === "cluster") {
972
+ t.triggerDissolveDeath();
973
+ for (let n = 0; n < 6; n++) {
974
+ const o = n * Math.PI * 2 / 6, r = {
975
+ x: t.position.x + Math.cos(o) * 15,
976
+ y: t.position.y + Math.sin(o) * 15
977
+ }, l = L.createEnemy("micro", r, {
978
+ x: r.x + Math.cos(o) * 200,
979
+ y: r.y + Math.sin(o) * 200
980
+ });
981
+ l.isThrown = !0, h.push(l);
982
+ }
983
+ } else t.type === "parasite" ? (t.triggerDissolveDeath(), s.push({
984
+ id: Math.random().toString(),
985
+ position: { ...t.position },
986
+ radius: 450,
987
+ duration: 0,
988
+ maxDuration: 5,
989
+ pullForce: 3e3
990
+ })) : t.type === "piercer" ? t.triggerSliceDeath(i) : t.triggerDissolveDeath();
991
+ }
992
+ }
993
+ class Z {
994
+ pool = [];
995
+ constructor(t = 500) {
996
+ for (let i = 0; i < t; i++) {
997
+ const e = new P(`pool_enemy_${i}`);
998
+ this.pool.push(e);
999
+ }
1000
+ }
1001
+ get() {
1002
+ for (const i of this.pool)
1003
+ if (!i.active)
1004
+ return i.reset(), i;
1005
+ const t = new P(`fallback_enemy_${Date.now()}_${Math.random()}`);
1006
+ return this.pool.push(t), t;
1007
+ }
1008
+ resetAll() {
1009
+ for (const t of this.pool)
1010
+ t.reset();
1011
+ }
1012
+ }
1013
+ class A {
1014
+ static getOffscreenPosition(t, i) {
1015
+ const e = Math.floor(Math.random() * 4), s = 70;
1016
+ return e === 0 ? { x: Math.random() * t, y: -s } : e === 1 ? { x: t + s, y: Math.random() * i } : e === 2 ? { x: Math.random() * t, y: i + s } : { x: -s, y: Math.random() * i };
1017
+ }
1018
+ static spawnCircleOfDeath(t, i, e, s) {
1019
+ const a = [], h = Math.max(e, s) * 0.55 + 80;
1020
+ for (let n = 0; n < 18; n++) {
1021
+ const o = n * Math.PI * 2 / 18, r = {
1022
+ x: i.x + Math.cos(o) * h,
1023
+ y: i.y + Math.sin(o) * h
1024
+ }, l = t.get(), p = ["piercer", "spore", "cluster", "parasite"], f = p[n % p.length];
1025
+ L.configureEnemy(l, f, r, i), l.velocity = {
1026
+ x: Math.cos(o + Math.PI) * 55,
1027
+ y: Math.sin(o + Math.PI) * 55
1028
+ }, a.push(l);
1029
+ }
1030
+ return a;
1031
+ }
1032
+ static spawnDenseCluster(t, i, e, s) {
1033
+ const a = [], h = Math.floor(Math.random() * 4);
1034
+ let n = { x: -60, y: -60 };
1035
+ h === 0 ? n = { x: Math.random() * i, y: -80 } : h === 1 ? n = { x: i + 80, y: Math.random() * e } : h === 2 ? n = { x: Math.random() * i, y: e + 80 } : n = { x: -80, y: Math.random() * e };
1036
+ for (let o = 0; o < 14; o++) {
1037
+ const r = {
1038
+ x: (Math.random() - 0.5) * 60,
1039
+ y: (Math.random() - 0.5) * 60
1040
+ }, l = { x: n.x + r.x, y: n.y + r.y }, p = t.get();
1041
+ L.configureEnemy(p, "spore", l, s);
1042
+ const f = s.x - l.x, g = s.y - l.y, b = Math.atan2(g, f);
1043
+ p.velocity = {
1044
+ x: Math.cos(b) * (50 + Math.random() * 20),
1045
+ y: Math.sin(b) * (50 + Math.random() * 20)
1046
+ }, a.push(p);
1047
+ }
1048
+ return a;
1049
+ }
1050
+ static spawnSineSnake(t, i, e, s) {
1051
+ const a = [], h = e * 0.2 + Math.random() * e * 0.6;
1052
+ for (let n = 0; n < 12; n++) {
1053
+ const o = {
1054
+ x: -60 - n * 40,
1055
+ y: h + Math.sin(n * 0.45) * 70
1056
+ }, r = t.get();
1057
+ L.configureEnemy(r, "cluster", o, s), r.velocity = { x: 75, y: Math.cos(n * 0.45) * 30 }, a.push(r);
1058
+ }
1059
+ return a;
1060
+ }
1061
+ static spawnDoubleSpiral(t, i, e, s) {
1062
+ const a = [];
1063
+ for (let h = 0; h < 14; h++) {
1064
+ const n = h / 14, o = n * Math.PI * 4, r = 120 + n * 450, l = {
1065
+ x: i + Math.cos(o) * r,
1066
+ y: -60 + Math.sin(o) * r
1067
+ }, p = t.get();
1068
+ L.configureEnemy(p, "parasite", l, s), a.push(p);
1069
+ }
1070
+ return a;
1071
+ }
1072
+ static spawnMarchingWall(t, i, e, s) {
1073
+ const a = [], h = Math.random() > 0.5;
1074
+ for (let n = 0; n < 12; n++) {
1075
+ const o = n / 11 * e, r = {
1076
+ x: h ? -60 : i + 60,
1077
+ y: o
1078
+ }, l = t.get();
1079
+ L.configureEnemy(l, "piercer", r, s), l.velocity = {
1080
+ x: h ? 70 : -70,
1081
+ y: 0
1082
+ }, a.push(l);
1083
+ }
1084
+ return a;
1085
+ }
1086
+ static spawnCrossfireStreams(t, i, e, s) {
1087
+ const a = [];
1088
+ for (let h = 0; h < 10; h++) {
1089
+ const n = { x: -50 - h * 35, y: -50 - h * 35 }, o = t.get();
1090
+ L.configureEnemy(o, "spore", n, s), a.push(o);
1091
+ const r = { x: i + 50 + h * 35, y: e + 50 + h * 35 }, l = t.get();
1092
+ L.configureEnemy(l, "cluster", r, s), a.push(l);
1093
+ }
1094
+ return a;
1095
+ }
1096
+ }
1097
+ class _ {
1098
+ wave = 1;
1099
+ pool;
1100
+ spawnTimer = 0;
1101
+ waveTimer = 0;
1102
+ patternCooldown = 0;
1103
+ initialGracePeriod = 25;
1104
+ constructor() {
1105
+ this.pool = new Z(500);
1106
+ }
1107
+ reset() {
1108
+ this.wave = 1, this.spawnTimer = 0, this.waveTimer = 0, this.patternCooldown = 0;
1109
+ }
1110
+ update(t, i, e, s, a) {
1111
+ this.waveTimer += t, this.spawnTimer += t, this.patternCooldown += t, this.applyFlockingBehaviors(i, t, a);
1112
+ const c = Math.max(1.1, 4.2 - (this.wave - 1) * 0.25);
1113
+ if (this.waveTimer > this.initialGracePeriod && this.patternCooldown > Math.max(16 - this.wave, 8) && i.length < 35) {
1114
+ this.patternCooldown = 0;
1115
+ const n = this.spawnPatternFormation(e, s, a);
1116
+ for (const o of n)
1117
+ i.push(o);
1118
+ }
1119
+ const h = Math.min(18 + this.wave * 4, 80);
1120
+ return this.spawnTimer >= c && i.length < h ? (this.spawnTimer = 0, this.spawnSingleEnemy(e, s, a)) : null;
1121
+ }
1122
+ spawnSingleEnemy(t, i, e) {
1123
+ const s = A.getOffscreenPosition(t, i), a = Math.random();
1124
+ let c = "piercer";
1125
+ a > 0.75 ? c = "parasite" : a > 0.5 ? c = "cluster" : a > 0.25 && (c = "spore");
1126
+ const h = this.pool.get();
1127
+ return L.configureEnemy(h, c, s, e), h;
1128
+ }
1129
+ spawnPatternFormation(t, i, e) {
1130
+ const s = Math.random();
1131
+ return s < 0.25 ? A.spawnCircleOfDeath(this.pool, e, t, i) : s < 0.5 ? A.spawnDenseCluster(this.pool, t, i, e) : s < 0.75 ? A.spawnSineSnake(this.pool, t, i, e) : A.spawnMarchingWall(this.pool, t, i, e);
1132
+ }
1133
+ applyFlockingBehaviors(t, i, e) {
1134
+ for (let a = 0; a < t.length; a++) {
1135
+ const c = t[a];
1136
+ if (!c.active || c.isGrabbed || c.isThrown || c.isDying) continue;
1137
+ let h = 0, n = 0, o = 0;
1138
+ for (let f = 0; f < t.length; f++) {
1139
+ if (a === f) continue;
1140
+ const g = t[f];
1141
+ if (!g.active || g.isGrabbed || g.isDying) continue;
1142
+ const b = c.position.x - g.position.x, d = c.position.y - g.position.y, m = Math.hypot(b, d);
1143
+ m > 0 && m < 70 && (h += b / m, n += d / m, o++);
1144
+ }
1145
+ o > 0 && (h /= o, n /= o, c.velocity.x += h * 60 * i, c.velocity.y += n * 60 * i);
1146
+ const r = e.x - c.position.x, l = e.y - c.position.y, p = Math.hypot(r, l);
1147
+ if (p > 0) {
1148
+ const f = 80 + Math.min(this.wave * 4, 40);
1149
+ c.velocity.x += r / p * f * i, c.velocity.y += l / p * f * i;
1150
+ }
1151
+ }
1152
+ }
1153
+ }
1154
+ const C = {
1155
+ bioluminescent: {
1156
+ bgInner: "#081220",
1157
+ bgMid: "#050b16",
1158
+ bgOuter: "#020408",
1159
+ nebulaCyan: "rgba(0, 240, 255, 0.08)",
1160
+ nebulaMagenta: "rgba(255, 0, 221, 0.07)",
1161
+ piercerColor: "#ff2a5f",
1162
+ sporeColor: "#39ff14",
1163
+ clusterColor: "#ffd700",
1164
+ parasiteColor: "#9d4edd",
1165
+ microColor: "#ffd700",
1166
+ corePrimary: "#00f0ff",
1167
+ coreGlow: "rgba(0, 240, 255, 0.85)",
1168
+ tendrilMagenta: "#ff00dd",
1169
+ tendrilCyan: "#00ffff"
1170
+ },
1171
+ dark: {
1172
+ bgInner: "#0d0f17",
1173
+ bgMid: "#07080f",
1174
+ bgOuter: "#030407",
1175
+ nebulaCyan: "rgba(0, 180, 216, 0.08)",
1176
+ nebulaMagenta: "rgba(216, 0, 166, 0.07)",
1177
+ piercerColor: "#ef4444",
1178
+ sporeColor: "#10b981",
1179
+ clusterColor: "#f59e0b",
1180
+ parasiteColor: "#8b5cf6",
1181
+ microColor: "#f59e0b",
1182
+ corePrimary: "#00b4d8",
1183
+ coreGlow: "rgba(0, 180, 216, 0.85)",
1184
+ tendrilMagenta: "#d800a6",
1185
+ tendrilCyan: "#00b4d8"
1186
+ },
1187
+ light: {
1188
+ bgInner: "#f1f5f9",
1189
+ bgMid: "#e2e8f0",
1190
+ bgOuter: "#cbd5e1",
1191
+ nebulaCyan: "rgba(0, 119, 182, 0.12)",
1192
+ nebulaMagenta: "rgba(181, 0, 140, 0.1)",
1193
+ piercerColor: "#dc2626",
1194
+ sporeColor: "#16a34a",
1195
+ clusterColor: "#d97706",
1196
+ parasiteColor: "#7c3aed",
1197
+ microColor: "#d97706",
1198
+ corePrimary: "#0077b6",
1199
+ coreGlow: "rgba(0, 119, 182, 0.85)",
1200
+ tendrilMagenta: "#b5008c",
1201
+ tendrilCyan: "#0077b6"
1202
+ }
1203
+ }, D = "axon_surge_theme";
1204
+ class q {
1205
+ currentTheme = "bioluminescent";
1206
+ constructor(t) {
1207
+ if (t)
1208
+ this.setTheme(t);
1209
+ else {
1210
+ try {
1211
+ const i = localStorage.getItem(D);
1212
+ i && C[i] && (this.currentTheme = i);
1213
+ } catch {
1214
+ }
1215
+ this.applyThemeToDOM();
1216
+ }
1217
+ }
1218
+ setTheme(t) {
1219
+ if (C[t]) {
1220
+ this.currentTheme = t, this.applyThemeToDOM();
1221
+ try {
1222
+ localStorage.setItem(D, t);
1223
+ } catch {
1224
+ }
1225
+ }
1226
+ }
1227
+ getTheme() {
1228
+ return this.currentTheme;
1229
+ }
1230
+ getPalette() {
1231
+ return C[this.currentTheme] || C.bioluminescent;
1232
+ }
1233
+ applyThemeToDOM() {
1234
+ document.documentElement.setAttribute("data-theme", this.currentTheme);
1235
+ }
1236
+ }
1237
+ class Q {
1238
+ canvas;
1239
+ ctx;
1240
+ themeManager;
1241
+ constructor(t, i) {
1242
+ this.canvas = t, this.ctx = t.getContext("2d"), this.themeManager = i;
1243
+ }
1244
+ render(t, i, e, s, a, c, h, n, o, r) {
1245
+ if (!this.ctx) return;
1246
+ const l = this.themeManager.getPalette(), { width: p, height: f } = this.canvas, g = n.getShakeOffset();
1247
+ this.ctx.save(), this.ctx.translate(g.x, g.y), this.drawFluidCosmosBackground(p, f, t.pulsePhase, l), this.drawToxicPools(e, t.pulsePhase), this.drawGravityVortices(s, t.pulsePhase), this.drawShockwaves(a), this.drawCoreFilaments(t, l), this.drawParticles(c), this.drawOrganicEnemies(i, t.pulsePhase, l), o ? this.drawPsionicTendril(t.position, o.position, l) : t && this.drawHoverTendril(t.position, r, i, l), this.drawOrganicConsciousnessCore(t, l), this.drawFloatingTexts(h), n.flashAlpha > 0 && (this.ctx.fillStyle = `rgba(255, 255, 255, ${n.flashAlpha})`, this.ctx.fillRect(0, 0, p, f)), this.ctx.restore();
1248
+ }
1249
+ drawToxicPools(t, i) {
1250
+ if (this.ctx)
1251
+ for (const e of t) {
1252
+ const s = e.duration / e.maxDuration, a = Math.min(0.7, (1 - s) * 0.7), { x: c, y: h } = e.position;
1253
+ this.ctx.save();
1254
+ const n = this.ctx.createRadialGradient(c, h, 10, c, h, e.radius * 1.2);
1255
+ n.addColorStop(0, `rgba(57, 255, 20, ${a * 0.9})`), n.addColorStop(0.4, `rgba(16, 185, 129, ${a * 0.65})`), n.addColorStop(0.8, `rgba(5, 80, 45, ${a * 0.35})`), n.addColorStop(1, "rgba(2, 35, 15, 0)"), this.ctx.fillStyle = n, this.ctx.shadowColor = "#39ff14", this.ctx.shadowBlur = 30, this.ctx.beginPath();
1256
+ const o = 70;
1257
+ for (let r = 0; r <= o; r++) {
1258
+ const l = r * Math.PI * 2 / o, p = Math.sin(l * 5 + i * 3) * 14, f = Math.cos(l * 3 - i * 2) * 9, g = e.radius + p + f, b = c + Math.cos(l) * g, d = h + Math.sin(l) * g;
1259
+ r === 0 ? this.ctx.moveTo(b, d) : this.ctx.lineTo(b, d);
1260
+ }
1261
+ this.ctx.closePath(), this.ctx.fill(), this.ctx.strokeStyle = `rgba(57, 255, 20, ${a * 0.8})`, this.ctx.lineWidth = 2.5, this.ctx.beginPath();
1262
+ for (let r = 0; r <= o; r++) {
1263
+ const l = r * Math.PI * 2 / o, p = Math.sin(l * 6 + i * 4) * 8, f = e.radius * 0.75 + p, g = c + Math.cos(l) * f, b = h + Math.sin(l) * f;
1264
+ r === 0 ? this.ctx.moveTo(g, b) : this.ctx.lineTo(g, b);
1265
+ }
1266
+ this.ctx.closePath(), this.ctx.stroke();
1267
+ for (let r = 0; r < 6; r++) {
1268
+ const l = r * Math.PI * 0.33 + i * 1.5, p = e.radius * 0.5 * (0.3 + Math.sin(i * 2 + r) * 0.3), f = c + Math.cos(l) * p, g = h + Math.sin(l) * p, b = 3 + Math.sin(i * 3 + r) * 2;
1269
+ this.ctx.fillStyle = `rgba(255, 255, 255, ${a * 0.8})`, this.ctx.beginPath(), this.ctx.arc(f, g, Math.max(1, b), 0, Math.PI * 2), this.ctx.fill();
1270
+ }
1271
+ this.ctx.restore();
1272
+ }
1273
+ }
1274
+ drawShockwaves(t) {
1275
+ if (this.ctx)
1276
+ for (const i of t) {
1277
+ this.ctx.save(), this.ctx.globalAlpha = i.alpha;
1278
+ const e = this.ctx.createRadialGradient(
1279
+ i.position.x,
1280
+ i.position.y,
1281
+ 0,
1282
+ i.position.x,
1283
+ i.position.y,
1284
+ i.radius
1285
+ );
1286
+ e.addColorStop(0, "rgba(255, 255, 255, 0.4)"), e.addColorStop(0.7, i.color), e.addColorStop(1, "rgba(0, 0, 0, 0)"), this.ctx.fillStyle = e, this.ctx.beginPath(), this.ctx.arc(i.position.x, i.position.y, i.radius, 0, Math.PI * 2), this.ctx.fill(), this.ctx.strokeStyle = "#ffffff", this.ctx.lineWidth = 4, this.ctx.shadowColor = i.color, this.ctx.shadowBlur = 24, this.ctx.beginPath(), this.ctx.arc(i.position.x, i.position.y, i.radius, 0, Math.PI * 2), this.ctx.stroke(), this.ctx.restore();
1287
+ }
1288
+ }
1289
+ drawGravityVortices(t, i) {
1290
+ if (this.ctx)
1291
+ for (const e of t) {
1292
+ const s = Math.min(0.85, (1 - e.duration / e.maxDuration) * 0.85), a = e.radius * (1 - e.duration / e.maxDuration * 0.1), { x: c, y: h } = e.position;
1293
+ this.ctx.save();
1294
+ const n = this.ctx.createRadialGradient(c, h, 0, c, h, 60);
1295
+ n.addColorStop(0, `rgba(0, 0, 0, ${s})`), n.addColorStop(0.7, `rgba(20, 0, 40, ${s})`), n.addColorStop(1, `rgba(157, 78, 221, ${s * 0.5})`), this.ctx.fillStyle = n, this.ctx.beginPath(), this.ctx.arc(c, h, 60, 0, Math.PI * 2), this.ctx.fill(), this.ctx.strokeStyle = `rgba(157, 78, 221, ${s})`, this.ctx.lineWidth = 5, this.ctx.shadowColor = "#9d4edd", this.ctx.shadowBlur = 32;
1296
+ for (let o = 1; o <= 5; o++) {
1297
+ const r = a * o / 5, l = i * o * 2.2;
1298
+ this.ctx.beginPath(), this.ctx.arc(c, h, r, l, l + Math.PI * 1.5), this.ctx.stroke();
1299
+ }
1300
+ this.ctx.restore();
1301
+ }
1302
+ }
1303
+ drawFluidCosmosBackground(t, i, e, s) {
1304
+ if (!this.ctx) return;
1305
+ const a = this.ctx.createRadialGradient(t / 2, i / 2, 40, t / 2, i / 2, Math.max(t, i));
1306
+ a.addColorStop(0, s.bgInner), a.addColorStop(0.5, s.bgMid), a.addColorStop(1, s.bgOuter), this.ctx.fillStyle = a, this.ctx.fillRect(0, 0, t, i);
1307
+ const c = t * 0.35 + Math.sin(e * 0.3) * 60, h = i * 0.45 + Math.cos(e * 0.25) * 50, n = this.ctx.createRadialGradient(c, h, 20, c, h, 380);
1308
+ n.addColorStop(0, s.nebulaCyan), n.addColorStop(1, "rgba(0, 0, 0, 0)"), this.ctx.fillStyle = n, this.ctx.beginPath(), this.ctx.arc(c, h, 380, 0, Math.PI * 2), this.ctx.fill();
1309
+ const o = t * 0.68 + Math.cos(e * 0.35) * 50, r = i * 0.55 + Math.sin(e * 0.3) * 45, l = this.ctx.createRadialGradient(o, r, 20, o, r, 420);
1310
+ l.addColorStop(0, s.nebulaMagenta), l.addColorStop(1, "rgba(0, 0, 0, 0)"), this.ctx.fillStyle = l, this.ctx.beginPath(), this.ctx.arc(o, r, 420, 0, Math.PI * 2), this.ctx.fill();
1311
+ }
1312
+ drawCoreFilaments(t, i) {
1313
+ if (!this.ctx) return;
1314
+ const e = 12;
1315
+ this.ctx.lineWidth = 1.5, this.ctx.strokeStyle = i.nebulaCyan;
1316
+ for (let s = 0; s < e; s++) {
1317
+ const a = s * Math.PI * 2 / e + t.pulsePhase * 0.12, c = 85 + Math.sin(t.pulsePhase * 1.5 + s) * 25, h = t.position.x + Math.cos(a) * c, n = t.position.y + Math.sin(a) * c, o = t.position.x + Math.cos(a + 0.4) * 48, r = t.position.y + Math.sin(a + 0.4) * 48;
1318
+ this.ctx.beginPath(), this.ctx.moveTo(t.position.x, t.position.y), this.ctx.quadraticCurveTo(o, r, h, n), this.ctx.stroke(), this.ctx.fillStyle = i.sporeColor, this.ctx.beginPath(), this.ctx.arc(h, n, 3.5, 0, Math.PI * 2), this.ctx.fill();
1319
+ }
1320
+ }
1321
+ drawOrganicConsciousnessCore(t, i) {
1322
+ if (!this.ctx) return;
1323
+ const { x: e, y: s } = t.position;
1324
+ for (let h = 0; h < t.integrity; h++) {
1325
+ const n = t.radius + 16 + h * 12;
1326
+ this.ctx.strokeStyle = i.corePrimary, this.ctx.lineWidth = 2.2, this.ctx.shadowColor = i.corePrimary, this.ctx.shadowBlur = 12, this.ctx.beginPath();
1327
+ const o = 60;
1328
+ for (let r = 0; r <= o; r++) {
1329
+ const l = r * Math.PI * 2 / o, p = n + Math.sin(l * 4 + t.pulsePhase * 2 + h) * 3, f = e + Math.cos(l) * p, g = s + Math.sin(l) * p;
1330
+ r === 0 ? this.ctx.moveTo(f, g) : this.ctx.lineTo(f, g);
1331
+ }
1332
+ this.ctx.closePath(), this.ctx.stroke();
1333
+ }
1334
+ const a = this.ctx.createRadialGradient(e, s, 5, e, s, t.radius * 2.2);
1335
+ a.addColorStop(0, i.coreGlow), a.addColorStop(0.5, i.nebulaMagenta), a.addColorStop(1, "rgba(0, 0, 0, 0)"), this.ctx.fillStyle = a, this.ctx.beginPath(), this.ctx.arc(e, s, t.radius * 2.2, 0, Math.PI * 2), this.ctx.fill(), this.ctx.save(), this.ctx.translate(e, s), this.ctx.strokeStyle = i.corePrimary, this.ctx.lineWidth = 3, this.ctx.fillStyle = i.nebulaCyan, this.ctx.shadowColor = i.corePrimary, this.ctx.shadowBlur = 20, this.ctx.beginPath();
1336
+ const c = 80;
1337
+ for (let h = 0; h <= c; h++) {
1338
+ const n = h * Math.PI * 2 / c, o = t.getMembraneRadius(n), r = Math.cos(n) * o, l = Math.sin(n) * o;
1339
+ h === 0 ? this.ctx.moveTo(r, l) : this.ctx.lineTo(r, l);
1340
+ }
1341
+ this.ctx.closePath(), this.ctx.fill(), this.ctx.stroke(), this.ctx.fillStyle = "#ffffff", this.ctx.beginPath(), this.ctx.arc(0, 0, t.radius * 0.3, 0, Math.PI * 2), this.ctx.fill(), this.ctx.restore();
1342
+ }
1343
+ drawPsionicTendril(t, i, e) {
1344
+ if (!this.ctx) return;
1345
+ this.ctx.save();
1346
+ const s = i.x - t.x, a = i.y - t.y;
1347
+ this.ctx.strokeStyle = e.tendrilMagenta, this.ctx.lineWidth = 9, this.ctx.shadowColor = e.tendrilMagenta, this.ctx.shadowBlur = 20, this.ctx.beginPath(), this.ctx.moveTo(t.x, t.y);
1348
+ const c = (t.x + i.x) / 2 + Math.sin(Date.now() * 0.02) * 16, h = (t.y + i.y) / 2 + Math.cos(Date.now() * 0.02) * 16;
1349
+ this.ctx.quadraticCurveTo(c, h, i.x, i.y), this.ctx.stroke(), this.ctx.strokeStyle = e.tendrilCyan, this.ctx.lineWidth = 3.5, this.ctx.shadowColor = e.tendrilCyan, this.ctx.shadowBlur = 12, this.ctx.beginPath(), this.ctx.moveTo(t.x, t.y), this.ctx.lineTo(i.x, i.y), this.ctx.stroke();
1350
+ for (let n = 0; n < 6; n++) {
1351
+ const o = Math.random(), r = t.x + s * o + (Math.random() - 0.5) * 24, l = t.y + a * o + (Math.random() - 0.5) * 24;
1352
+ this.ctx.fillStyle = "#ffffff", this.ctx.beginPath(), this.ctx.arc(r, l, 2.5 + Math.random() * 2.5, 0, Math.PI * 2), this.ctx.fill();
1353
+ }
1354
+ this.ctx.restore();
1355
+ }
1356
+ drawHoverTendril(t, i, e, s) {
1357
+ if (this.ctx)
1358
+ for (const a of e) {
1359
+ if (!a.active || a.isGrabbed || a.isThrown || a.wasManipulated || a.isDying) continue;
1360
+ const c = i.x - a.position.x, h = i.y - a.position.y;
1361
+ if (Math.hypot(c, h) <= a.getHitRadius()) {
1362
+ this.ctx.strokeStyle = s.tendrilMagenta, this.ctx.lineWidth = 2.5, this.ctx.beginPath(), this.ctx.moveTo(t.x, t.y), this.ctx.lineTo(a.position.x, a.position.y), this.ctx.stroke();
1363
+ break;
1364
+ }
1365
+ }
1366
+ }
1367
+ drawOrganicEnemies(t, i, e) {
1368
+ if (this.ctx)
1369
+ for (const s of t) {
1370
+ if (!s.active) continue;
1371
+ let a = s.color;
1372
+ s.type === "piercer" ? a = e.piercerColor : s.type === "spore" ? a = e.sporeColor : s.type === "cluster" ? a = e.clusterColor : s.type === "parasite" ? a = e.parasiteColor : s.type === "micro" && (a = e.microColor);
1373
+ const { x: c, y: h } = s.position;
1374
+ if (this.ctx.save(), this.ctx.translate(c, h), s.wasManipulated && !s.isDying) {
1375
+ const n = s.radius * 1.5 + Math.sin(i * 6) * 4;
1376
+ this.ctx.strokeStyle = e.tendrilMagenta, this.ctx.lineWidth = 2.5, this.ctx.shadowColor = e.tendrilMagenta, this.ctx.shadowBlur = 18, this.ctx.beginPath(), this.ctx.arc(0, 0, n, 0, Math.PI * 2), this.ctx.stroke();
1377
+ const o = s.radius * 1.8 + Math.cos(i * 8) * 3;
1378
+ this.ctx.strokeStyle = e.tendrilCyan, this.ctx.lineWidth = 1.5, this.ctx.beginPath(), this.ctx.arc(0, 0, o, 0, Math.PI * 2), this.ctx.stroke();
1379
+ }
1380
+ if (s.isDying) {
1381
+ const n = s.deathTimer / s.maxDeathTimer, o = Math.max(0, 1 - n);
1382
+ if (this.ctx.globalAlpha = o, s.deathType === "dissolve") {
1383
+ const r = s.radius * (1 - n * 0.7);
1384
+ this.ctx.fillStyle = e.sporeColor, this.ctx.shadowColor = e.sporeColor, this.ctx.shadowBlur = 20, this.ctx.beginPath(), this.ctx.arc(0, 0, r, 0, Math.PI * 2), this.ctx.fill();
1385
+ for (let l = 0; l < 4; l++) {
1386
+ const p = l * Math.PI * 0.5 + n * 4, f = r * 0.8 * n;
1387
+ this.ctx.fillStyle = "#ffffff", this.ctx.beginPath(), this.ctx.arc(Math.cos(p) * f, Math.sin(p) * f, 3, 0, Math.PI * 2), this.ctx.fill();
1388
+ }
1389
+ this.ctx.restore();
1390
+ continue;
1391
+ } else if (s.deathType === "sliced") {
1392
+ const r = n * 24, l = s.sliceAngle + Math.PI / 2, p = Math.cos(l) * r, f = Math.sin(l) * r;
1393
+ this.ctx.shadowColor = "#ff2a5f", this.ctx.shadowBlur = 22, this.ctx.fillStyle = a, this.ctx.save(), this.ctx.translate(p, f), this.ctx.beginPath(), this.ctx.arc(0, 0, s.radius * 0.8, 0, Math.PI), this.ctx.fill(), this.ctx.restore(), this.ctx.save(), this.ctx.translate(-p, -f), this.ctx.beginPath(), this.ctx.arc(0, 0, s.radius * 0.8, Math.PI, Math.PI * 2), this.ctx.fill(), this.ctx.restore(), this.ctx.restore();
1394
+ continue;
1395
+ }
1396
+ }
1397
+ if (this.ctx.shadowColor = a, this.ctx.shadowBlur = 16, this.ctx.fillStyle = a, s.type === "piercer") {
1398
+ this.ctx.rotate(s.rotation), this.ctx.beginPath();
1399
+ const n = 12;
1400
+ for (let o = 0; o <= n; o++) {
1401
+ const r = o * Math.PI * 2 / n, l = s.radius * 1.6 + Math.sin(r * 3 + i * 4) * 3, p = s.radius * 0.6 + Math.cos(r * 2 + i * 3) * 2, f = Math.cos(r) * l, g = Math.sin(r) * p;
1402
+ o === 0 ? this.ctx.moveTo(f, g) : this.ctx.lineTo(f, g);
1403
+ }
1404
+ this.ctx.closePath(), this.ctx.fill(), this.ctx.fillStyle = "#ffffff", this.ctx.beginPath(), this.ctx.arc(4, 0, 4, 0, Math.PI * 2), this.ctx.fill();
1405
+ } else if (s.type === "spore") {
1406
+ this.ctx.beginPath();
1407
+ const n = 8;
1408
+ for (let o = 0; o < n; o++) {
1409
+ const r = o * Math.PI * 2 / n, l = s.radius + Math.sin(r * 4 + i * 3 + s.position.x) * 4, p = Math.cos(r) * l, f = Math.sin(r) * l;
1410
+ o === 0 ? this.ctx.moveTo(p, f) : this.ctx.lineTo(p, f);
1411
+ }
1412
+ this.ctx.closePath(), this.ctx.fill(), this.ctx.fillStyle = "rgba(255, 255, 255, 0.7)", this.ctx.beginPath(), this.ctx.arc(-4, -4, 5, 0, Math.PI * 2), this.ctx.arc(5, 3, 4, 0, Math.PI * 2), this.ctx.fill();
1413
+ } else if (s.type === "cluster") {
1414
+ this.ctx.beginPath();
1415
+ const n = Math.sin(i * 3) * 2;
1416
+ this.ctx.arc(0, 0, s.radius * 0.55, 0, Math.PI * 2), this.ctx.arc(-9 + n, -7, s.radius * 0.42, 0, Math.PI * 2), this.ctx.arc(9 - n, -7, s.radius * 0.42, 0, Math.PI * 2), this.ctx.arc(0, 9 + n, s.radius * 0.45, 0, Math.PI * 2), this.ctx.fill();
1417
+ } else if (s.type === "parasite") {
1418
+ this.ctx.beginPath();
1419
+ const n = 14;
1420
+ for (let o = 0; o <= n; o++) {
1421
+ const r = o * Math.PI * 2 / n, l = s.radius + Math.sin(r * 5 - i * 5) * 3, p = Math.cos(r) * l, f = Math.sin(r) * l;
1422
+ o === 0 ? this.ctx.moveTo(p, f) : this.ctx.lineTo(p, f);
1423
+ }
1424
+ this.ctx.closePath(), this.ctx.fill(), this.ctx.fillStyle = e.bgOuter, this.ctx.beginPath(), this.ctx.arc(0, 0, s.radius * 0.45, 0, Math.PI * 2), this.ctx.fill();
1425
+ } else
1426
+ this.ctx.beginPath(), this.ctx.arc(0, 0, s.radius, 0, Math.PI * 2), this.ctx.fill();
1427
+ this.ctx.restore();
1428
+ }
1429
+ }
1430
+ drawParticles(t) {
1431
+ if (this.ctx)
1432
+ for (const i of t)
1433
+ this.ctx.save(), this.ctx.globalAlpha = i.alpha, this.ctx.fillStyle = i.color, this.ctx.beginPath(), this.ctx.arc(i.position.x, i.position.y, i.radius, 0, Math.PI * 2), this.ctx.fill(), this.ctx.restore();
1434
+ }
1435
+ drawFloatingTexts(t) {
1436
+ if (this.ctx)
1437
+ for (const i of t)
1438
+ this.ctx.save(), this.ctx.globalAlpha = i.alpha, this.ctx.fillStyle = i.color, this.ctx.font = `900 ${i.size}px Orbitron, sans-serif`, this.ctx.textAlign = "center", this.ctx.shadowColor = i.color, this.ctx.shadowBlur = 12, this.ctx.fillText(i.text, i.position.x, i.position.y), this.ctx.restore();
1439
+ }
1440
+ }
1441
+ class j {
1442
+ container;
1443
+ i18n;
1444
+ waveLabelElement;
1445
+ progressSlot;
1446
+ comboElement;
1447
+ settingsButton;
1448
+ constructor(t, i, e) {
1449
+ this.i18n = i, this.container = document.createElement("div"), this.container.className = "axon-hud", this.waveLabelElement = document.createElement("div"), this.waveLabelElement.className = "axon-hud-wave", this.progressSlot = document.createElement("div"), this.progressSlot.className = "axon-hud-level-slot", this.waveLabelElement.appendChild(this.progressSlot), this.comboElement = document.createElement("div"), this.comboElement.className = "axon-hud-combo", this.settingsButton = document.createElement("button"), this.settingsButton.className = "axon-hud-settings-btn", this.settingsButton.setAttribute("aria-label", "Settings"), this.settingsButton.innerHTML = `
1450
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
1451
+ <circle cx="12" cy="12" r="3"></circle>
1452
+ <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
1453
+ </svg>
1454
+ `, this.settingsButton.addEventListener("click", e), this.renderLabels(), this.container.appendChild(this.waveLabelElement), this.container.appendChild(this.comboElement), this.container.appendChild(this.settingsButton), t.appendChild(this.container);
1455
+ }
1456
+ renderLabels() {
1457
+ let t = this.waveLabelElement.querySelector(".axon-level-title");
1458
+ t ? t.textContent = this.i18n.translate("waveLabel") : (t = document.createElement("div"), t.className = "axon-level-title", t.textContent = this.i18n.translate("waveLabel"), this.waveLabelElement.insertBefore(t, this.waveLabelElement.firstChild));
1459
+ let i = this.waveLabelElement.querySelector("#axon-wave-val");
1460
+ i || (i = document.createElement("span"), i.id = "axon-wave-val", i.textContent = "1", this.waveLabelElement.insertBefore(i, this.progressSlot)), this.comboElement.innerHTML = '<span id="axon-combo-val"></span>';
1461
+ }
1462
+ update(t, i) {
1463
+ const e = this.container.querySelector("#axon-wave-val"), s = this.container.querySelector("#axon-combo-val");
1464
+ e && (e.textContent = t.toString()), s && (i >= 2 ? (s.textContent = `x${i}`, s.style.display = "block") : s.style.display = "none");
1465
+ }
1466
+ show() {
1467
+ this.renderLabels(), this.container.style.display = "flex";
1468
+ }
1469
+ hide() {
1470
+ this.container.style.display = "none";
1471
+ }
1472
+ }
1473
+ class tt {
1474
+ container;
1475
+ i18n;
1476
+ onStartCallback;
1477
+ constructor(t, i, e) {
1478
+ this.i18n = i, this.onStartCallback = e, this.container = document.createElement("div"), this.container.className = "axon-start-menu", this.renderContent(), t.appendChild(this.container);
1479
+ }
1480
+ renderContent() {
1481
+ this.container.innerHTML = `
1482
+ <div class="axon-title-halo">
1483
+ <h1 class="axon-title">${this.i18n.translate("title")}</h1>
1484
+ <button id="axon-start-btn" class="axon-start-button">${this.i18n.translate("startButton")}</button>
1485
+ </div>
1486
+ `;
1487
+ const t = this.container.querySelector("#axon-start-btn");
1488
+ t && t.addEventListener("click", () => {
1489
+ this.hide(), this.onStartCallback();
1490
+ });
1491
+ }
1492
+ show() {
1493
+ this.renderContent(), this.container.style.display = "flex";
1494
+ }
1495
+ hide() {
1496
+ this.container.style.display = "none";
1497
+ }
1498
+ }
1499
+ class it {
1500
+ modal;
1501
+ card;
1502
+ i18n;
1503
+ themeManager;
1504
+ platform;
1505
+ onLanguageChangedCallback;
1506
+ onCloseCallback;
1507
+ hapticsEnabled = !0;
1508
+ constructor(t, i, e, s, a, c) {
1509
+ this.i18n = i, this.themeManager = e, this.platform = s, this.onLanguageChangedCallback = a, this.onCloseCallback = c;
1510
+ const h = localStorage.getItem("axon_surge_haptics");
1511
+ h !== null && (this.hapticsEnabled = h === "true"), this.modal = document.createElement("dialog"), this.modal.className = "axon-settings-modal", this.card = document.createElement("div"), this.card.className = "axon-settings-card", this.modal.appendChild(this.card), t.appendChild(this.modal), this.modal.addEventListener("close", () => {
1512
+ this.onCloseCallback && this.onCloseCallback();
1513
+ }), this.renderContent();
1514
+ }
1515
+ renderContent() {
1516
+ this.card.innerHTML = "";
1517
+ const t = document.createElement("h2");
1518
+ t.textContent = this.i18n.translate("settingsTitle");
1519
+ const i = document.createElement("div");
1520
+ i.className = "axon-setting-row";
1521
+ const e = document.createElement("span");
1522
+ e.textContent = this.i18n.translate("languageLabel");
1523
+ const s = document.createElement("div");
1524
+ s.className = "axon-select-wrapper";
1525
+ const a = document.createElement("select");
1526
+ a.className = "axon-select";
1527
+ const c = {
1528
+ es: "ESPAÑOL (ES)",
1529
+ en: "ENGLISH (EN)",
1530
+ fr: "FRANÇAIS (FR)",
1531
+ de: "DEUTSCH (DE)",
1532
+ it: "ITALIANO (IT)",
1533
+ pt: "PORTUGUÊS (PT)",
1534
+ nl: "NEDERLANDS (NL)",
1535
+ sv: "SVENSKA (SV)",
1536
+ pl: "POLSKI (PL)",
1537
+ id: "BAHASA INDONESIA (ID)",
1538
+ tr: "TÜRKÇE (TR)",
1539
+ ru: "РУССКИЙ (RU)",
1540
+ ja: "日本語 (JA)",
1541
+ ko: "한국어 (KO)",
1542
+ zh: "中文 (ZH)"
1543
+ };
1544
+ for (const u of k) {
1545
+ const y = document.createElement("option");
1546
+ y.value = u, y.textContent = c[u], this.i18n.getLanguage() === u && (y.selected = !0), a.appendChild(y);
1547
+ }
1548
+ a.addEventListener("change", () => {
1549
+ const u = a.value;
1550
+ this.i18n.setLanguage(u), this.onLanguageChangedCallback && this.onLanguageChangedCallback(u), this.renderContent();
1551
+ });
1552
+ const h = document.createElement("span");
1553
+ h.className = "axon-select-arrow", h.textContent = "▼", s.appendChild(a), s.appendChild(h), i.appendChild(e), i.appendChild(s);
1554
+ const n = document.createElement("div");
1555
+ n.className = "axon-setting-row";
1556
+ const o = document.createElement("span");
1557
+ o.textContent = this.i18n.translate("themeLabel");
1558
+ const r = document.createElement("div");
1559
+ r.className = "axon-toggle-group";
1560
+ const l = [
1561
+ { id: "bioluminescent", label: "BIO" },
1562
+ { id: "dark", label: "DARK" },
1563
+ { id: "light", label: "LIGHT" }
1564
+ ];
1565
+ for (const u of l) {
1566
+ const y = document.createElement("button");
1567
+ y.type = "button", y.className = `axon-toggle-btn ${this.themeManager.getTheme() === u.id ? "active" : ""}`, y.textContent = u.label, y.addEventListener("click", () => {
1568
+ this.themeManager.setTheme(u.id), this.renderContent();
1569
+ }), r.appendChild(y);
1570
+ }
1571
+ n.appendChild(o), n.appendChild(r);
1572
+ const p = document.createElement("div");
1573
+ p.className = "axon-setting-row";
1574
+ const f = document.createElement("span");
1575
+ f.textContent = this.i18n.translate("hapticsLabel");
1576
+ const g = document.createElement("div");
1577
+ g.className = "axon-toggle-group";
1578
+ const b = [
1579
+ { enabled: !0, label: this.i18n.translate("hapticsOn") },
1580
+ { enabled: !1, label: this.i18n.translate("hapticsOff") }
1581
+ ];
1582
+ for (const u of b) {
1583
+ const y = document.createElement("button");
1584
+ y.type = "button", y.className = `axon-toggle-btn ${this.hapticsEnabled === u.enabled ? "active" : ""}`, y.textContent = u.label, y.addEventListener("click", () => {
1585
+ this.hapticsEnabled = u.enabled, localStorage.setItem("axon_surge_haptics", String(u.enabled)), this.hapticsEnabled && this.platform.haptics.selectionChanged(), this.renderContent();
1586
+ }), g.appendChild(y);
1587
+ }
1588
+ p.appendChild(f), p.appendChild(g);
1589
+ const d = document.createElement("div");
1590
+ d.className = "axon-settings-credits", d.textContent = this.i18n.translate("creditsJam");
1591
+ const m = document.createElement("button");
1592
+ m.type = "button", m.className = "axon-start-button", m.style.padding = "12px 36px", m.style.fontSize = "14px", m.textContent = this.i18n.translate("closeButton"), m.addEventListener("click", () => {
1593
+ this.modal.close();
1594
+ }), this.card.appendChild(t), this.card.appendChild(i), this.card.appendChild(n), this.card.appendChild(p), this.card.appendChild(d), this.card.appendChild(m);
1595
+ }
1596
+ isHapticsEnabled() {
1597
+ return this.hapticsEnabled;
1598
+ }
1599
+ show() {
1600
+ this.renderContent(), this.modal.showModal();
1601
+ }
1602
+ hide() {
1603
+ this.modal.close();
1604
+ }
1605
+ }
1606
+ const O = "axon-surge-onboarding-completed";
1607
+ class et {
1608
+ container;
1609
+ i18n;
1610
+ hasCompleted = !1;
1611
+ isStep1Done = !1;
1612
+ constructor(t, i) {
1613
+ this.i18n = i, this.container = document.createElement("div"), this.container.className = "axon-onboarding", this.container.style.display = "none", t.appendChild(this.container);
1614
+ try {
1615
+ localStorage.getItem(O) === "true" && (this.hasCompleted = !0);
1616
+ } catch {
1617
+ }
1618
+ }
1619
+ isCompleted() {
1620
+ return this.hasCompleted;
1621
+ }
1622
+ showStep1() {
1623
+ this.hasCompleted || this.isStep1Done || (this.container.innerHTML = `
1624
+ <div class="axon-onboarding-hint">
1625
+ <div class="axon-onboarding-text">${this.i18n.translate("grabInstruction")}</div>
1626
+ </div>
1627
+ `, this.container.style.display = "flex");
1628
+ }
1629
+ showStep2() {
1630
+ this.hasCompleted || (this.isStep1Done = !0, this.container.innerHTML = `
1631
+ <div class="axon-onboarding-hint">
1632
+ <div class="axon-onboarding-text">${this.i18n.translate("throwInstruction")}</div>
1633
+ </div>
1634
+ `, this.container.style.display = "flex");
1635
+ }
1636
+ complete() {
1637
+ this.hasCompleted = !0, this.container.style.display = "none";
1638
+ try {
1639
+ localStorage.setItem(O, "true");
1640
+ } catch {
1641
+ }
1642
+ }
1643
+ reset() {
1644
+ this.hasCompleted || (this.isStep1Done = !1, this.container.style.display = "none");
1645
+ }
1646
+ }
1647
+ class st {
1648
+ fillElement;
1649
+ killsCount = 0;
1650
+ currentLevel = 1;
1651
+ onLevelUpCallback;
1652
+ constructor(t, i) {
1653
+ this.onLevelUpCallback = i;
1654
+ const e = document.createElement("div");
1655
+ e.className = "axon-hud-level-track", this.fillElement = document.createElement("div"), this.fillElement.className = "axon-hud-level-fill", e.appendChild(this.fillElement), t.appendChild(e);
1656
+ }
1657
+ getKillsRequiredForLevel(t) {
1658
+ return 16 + (t - 1) * 6;
1659
+ }
1660
+ addKill() {
1661
+ this.killsCount++;
1662
+ const t = this.getKillsRequiredForLevel(this.currentLevel), i = Math.min(100, this.killsCount / t * 100);
1663
+ this.fillElement.style.width = `${i}%`, this.killsCount >= t && (this.currentLevel++, this.killsCount = 0, this.fillElement.style.width = "0%", this.onLevelUpCallback && this.onLevelUpCallback(this.currentLevel));
1664
+ }
1665
+ getLevel() {
1666
+ return this.currentLevel;
1667
+ }
1668
+ reset() {
1669
+ this.killsCount = 0, this.currentLevel = 1, this.fillElement.style.width = "0%";
1670
+ }
1671
+ show() {
1672
+ this.fillElement && this.fillElement.parentElement && (this.fillElement.parentElement.style.display = "block");
1673
+ }
1674
+ hide() {
1675
+ this.fillElement && this.fillElement.parentElement && (this.fillElement.parentElement.style.display = "none");
1676
+ }
1677
+ }
1678
+ class at {
1679
+ haptics = {
1680
+ impact: async (t) => {
1681
+ if ("vibrate" in navigator) {
1682
+ const i = t === "light" ? 10 : t === "medium" ? 25 : 40;
1683
+ navigator.vibrate(i);
1684
+ }
1685
+ },
1686
+ notification: async (t) => {
1687
+ if ("vibrate" in navigator) {
1688
+ const i = t === "error" ? [30, 40, 30] : [20, 20];
1689
+ navigator.vibrate(i);
1690
+ }
1691
+ },
1692
+ selectionChanged: async () => {
1693
+ "vibrate" in navigator && navigator.vibrate(8);
1694
+ }
1695
+ };
1696
+ share = {
1697
+ share: async (t) => {
1698
+ if ("share" in navigator)
1699
+ try {
1700
+ await navigator.share(t);
1701
+ } catch {
1702
+ }
1703
+ }
1704
+ };
1705
+ review = {
1706
+ requestReview: async () => {
1707
+ }
1708
+ };
1709
+ analytics = {
1710
+ event: async () => {
1711
+ }
1712
+ };
1713
+ crashReporter = {
1714
+ record: async () => {
1715
+ }
1716
+ };
1717
+ }
1718
+ class nt {
1719
+ container;
1720
+ canvas;
1721
+ i18n;
1722
+ themeManager;
1723
+ platform;
1724
+ eventBus;
1725
+ gameLoop;
1726
+ inputManager;
1727
+ physicsEngine;
1728
+ waveDirector;
1729
+ renderer;
1730
+ juice;
1731
+ hud;
1732
+ startMenu;
1733
+ settingsModal;
1734
+ onboarding;
1735
+ progressBar;
1736
+ core;
1737
+ enemies = [];
1738
+ ambientEnemies = [];
1739
+ pools = [];
1740
+ vortices = [];
1741
+ shockwaves = [];
1742
+ particles = [];
1743
+ floatingTexts = [];
1744
+ score = { value: 0 };
1745
+ combo = { value: 0 };
1746
+ isRunning = !1;
1747
+ isPaused = !1;
1748
+ firstPlay = !0;
1749
+ constructor(t) {
1750
+ this.container = t.root, this.container.classList.add("axon-game-root"), this.i18n = new J(t.language), this.themeManager = new q(t.theme), this.platform = t.platform || new at(), this.canvas = document.createElement("canvas"), this.canvas.className = "axon-canvas", this.container.appendChild(this.canvas), this.resizeCanvas(), window.addEventListener("resize", () => this.resizeCanvas()), this.eventBus = new G(), this.core = new U(this.canvas.width / 2, this.canvas.height / 2), this.inputManager = new H(this.canvas), this.physicsEngine = new z(this.eventBus, this.i18n), this.waveDirector = new _(), this.renderer = new Q(this.canvas, this.themeManager), this.juice = new F(), this.settingsModal = new it(
1751
+ this.container,
1752
+ this.i18n,
1753
+ this.themeManager,
1754
+ this.platform,
1755
+ (i) => this.onLanguageChanged(i),
1756
+ () => {
1757
+ this.isPaused = !1;
1758
+ }
1759
+ ), this.onboarding = new et(this.container, this.i18n), this.hud = new j(this.container, this.i18n, () => {
1760
+ this.isPaused = !0, this.settingsModal.show();
1761
+ }), this.hud.show(), this.progressBar = new st(this.hud.progressSlot, (i) => {
1762
+ this.waveDirector.wave = i;
1763
+ }), this.startMenu = new tt(this.container, this.i18n, () => this.startGame()), this.initAmbientArena(), this.gameLoop = new B(
1764
+ (i) => this.update(i),
1765
+ () => this.render()
1766
+ ), this.setupEvents(), this.gameLoop.start();
1767
+ }
1768
+ setLanguage(t) {
1769
+ this.i18n.setLanguage(t), this.onLanguageChanged(t);
1770
+ }
1771
+ setTheme(t) {
1772
+ this.themeManager.setTheme(t);
1773
+ }
1774
+ onLanguageChanged(t) {
1775
+ this.startMenu.renderContent(), this.hud.renderLabels();
1776
+ }
1777
+ initAmbientArena() {
1778
+ this.ambientEnemies = [];
1779
+ const t = ["piercer", "spore", "cluster", "parasite"];
1780
+ for (let i = 0; i < 16; i++) {
1781
+ const e = t[i % t.length], s = i * Math.PI * 2 / 16, a = 180 + Math.random() * 220, c = {
1782
+ x: this.canvas.width / 2 + Math.cos(s) * a,
1783
+ y: this.canvas.height / 2 + Math.sin(s) * a
1784
+ }, h = L.createEnemy(e, c, {
1785
+ x: c.x + Math.sin(s) * 100,
1786
+ y: c.y - Math.cos(s) * 100
1787
+ });
1788
+ this.ambientEnemies.push(h);
1789
+ }
1790
+ }
1791
+ resizeCanvas() {
1792
+ this.canvas.width = this.container.clientWidth || window.innerWidth, this.canvas.height = this.container.clientHeight || window.innerHeight, this.core && (this.core.position = { x: this.canvas.width / 2, y: this.canvas.height / 2 });
1793
+ }
1794
+ setupEvents() {
1795
+ this.eventBus.on("onCoreDamaged", () => {
1796
+ this.settingsModal.isHapticsEnabled() && this.platform.haptics.notification("error");
1797
+ }), this.eventBus.on("onGameOver", () => {
1798
+ this.isRunning = !1, this.onboarding.complete(), this.progressBar.hide(), this.initAmbientArena(), this.startMenu.show();
1799
+ });
1800
+ const t = () => {
1801
+ if (!this.isRunning || this.isPaused) return;
1802
+ this.inputManager.tryGrab(this.enemies) && (this.firstPlay && !this.onboarding.isCompleted() && this.onboarding.showStep2(), this.settingsModal.isHapticsEnabled() && this.platform.haptics.impact("light"));
1803
+ }, i = () => {
1804
+ if (!this.isRunning || this.isPaused) return;
1805
+ this.inputManager.releaseAndThrow() && (this.firstPlay && (this.onboarding.complete(), this.firstPlay = !1), this.settingsModal.isHapticsEnabled() && this.platform.haptics.impact("medium"));
1806
+ };
1807
+ this.canvas.addEventListener("mousedown", (e) => {
1808
+ e.button === 0 && t();
1809
+ }), this.canvas.addEventListener("mouseup", (e) => {
1810
+ e.button === 0 && i();
1811
+ }), this.canvas.addEventListener("touchstart", t, { passive: !0 }), this.canvas.addEventListener("touchend", i, { passive: !0 }), this.canvas.addEventListener("touchcancel", i, { passive: !0 });
1812
+ }
1813
+ startGame() {
1814
+ this.score.value = 0, this.combo.value = 0, this.enemies = [], this.ambientEnemies = [], this.pools = [], this.vortices = [], this.shockwaves = [], this.particles = [], this.floatingTexts = [], this.core.reset(this.canvas.width / 2, this.canvas.height / 2), this.waveDirector.reset(), this.inputManager.reset(), this.hud.show(), this.hud.update(1, 0), this.progressBar.reset(), this.progressBar.show(), this.isPaused = !1, this.isRunning = !0, this.firstPlay && this.onboarding.showStep1();
1815
+ }
1816
+ update(t) {
1817
+ if (this.core.update(t), !this.isRunning || this.isPaused) {
1818
+ for (const e of this.ambientEnemies)
1819
+ e.update(t), e.position.x < -40 && (e.position.x = this.canvas.width + 40), e.position.x > this.canvas.width + 40 && (e.position.x = -40), e.position.y < -40 && (e.position.y = this.canvas.height + 40), e.position.y > this.canvas.height + 40 && (e.position.y = -40);
1820
+ return;
1821
+ }
1822
+ const i = this.waveDirector.update(
1823
+ t,
1824
+ this.enemies,
1825
+ this.canvas.width,
1826
+ this.canvas.height,
1827
+ this.core.position
1828
+ );
1829
+ i && this.enemies.push(i), this.juice.hitstopTime <= 0 && this.physicsEngine.update(
1830
+ t,
1831
+ this.core,
1832
+ this.enemies,
1833
+ this.pools,
1834
+ this.vortices,
1835
+ this.shockwaves,
1836
+ this.particles,
1837
+ this.floatingTexts,
1838
+ this.juice,
1839
+ this.combo,
1840
+ this.score,
1841
+ this.canvas.width,
1842
+ this.canvas.height,
1843
+ () => this.progressBar.addKill()
1844
+ ), this.hud.update(this.progressBar.getLevel(), this.combo.value), this.juice.update(t, this.floatingTexts, this.particles);
1845
+ }
1846
+ render() {
1847
+ const t = this.isRunning ? this.enemies : this.ambientEnemies;
1848
+ this.renderer.render(
1849
+ this.core,
1850
+ t,
1851
+ this.pools,
1852
+ this.vortices,
1853
+ this.shockwaves,
1854
+ this.particles,
1855
+ this.floatingTexts,
1856
+ this.juice,
1857
+ this.inputManager.grabbedEnemy,
1858
+ this.inputManager.pointerPosition
1859
+ );
1860
+ }
1861
+ }
1862
+ function ot(x) {
1863
+ return new nt(x);
1864
+ }
1865
+ export {
1866
+ at as BrowserPlatform,
1867
+ nt as GameEngine,
1868
+ k as LANGUAGES,
1869
+ q as ThemeManager,
1870
+ ot as createAxonSurge,
1871
+ V as isLanguage
1872
+ };