@gamebob/axon-surge 0.17.0 → 0.18.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 (75) hide show
  1. package/dist/axon-surge.js +1900 -1321
  2. package/dist/config/GameConfig.d.ts +27 -1
  3. package/dist/config/GameConfig.d.ts.map +1 -1
  4. package/dist/content/ContentRegistry.d.ts +25 -0
  5. package/dist/content/ContentRegistry.d.ts.map +1 -0
  6. package/dist/content/ContentTypes.d.ts +67 -0
  7. package/dist/content/ContentTypes.d.ts.map +1 -0
  8. package/dist/content/DefaultContentRegistry.d.ts +3 -0
  9. package/dist/content/DefaultContentRegistry.d.ts.map +1 -0
  10. package/dist/content/DefinitionRegistry.d.ts +22 -0
  11. package/dist/content/DefinitionRegistry.d.ts.map +1 -0
  12. package/dist/content/EnemyBehavior.d.ts +70 -0
  13. package/dist/content/EnemyBehavior.d.ts.map +1 -0
  14. package/dist/content/EnemyBehaviors.d.ts +4 -0
  15. package/dist/content/EnemyBehaviors.d.ts.map +1 -0
  16. package/dist/content/EnemyDefinitions.d.ts +4 -0
  17. package/dist/content/EnemyDefinitions.d.ts.map +1 -0
  18. package/dist/core/GameEngine.d.ts +5 -0
  19. package/dist/core/GameEngine.d.ts.map +1 -1
  20. package/dist/director/InteractiveTutorial.d.ts +6 -0
  21. package/dist/director/InteractiveTutorial.d.ts.map +1 -1
  22. package/dist/director/SpawnerPatterns.d.ts +10 -7
  23. package/dist/director/SpawnerPatterns.d.ts.map +1 -1
  24. package/dist/director/WaveDirector.d.ts +5 -1
  25. package/dist/director/WaveDirector.d.ts.map +1 -1
  26. package/dist/entities/CoreEntity.d.ts +3 -1
  27. package/dist/entities/CoreEntity.d.ts.map +1 -1
  28. package/dist/entities/EnemyEntity.d.ts +7 -0
  29. package/dist/entities/EnemyEntity.d.ts.map +1 -1
  30. package/dist/entities/ExperienceOrb.d.ts +26 -3
  31. package/dist/entities/ExperienceOrb.d.ts.map +1 -1
  32. package/dist/factory/EntityFactory.d.ts +5 -2
  33. package/dist/factory/EntityFactory.d.ts.map +1 -1
  34. package/dist/input/InputManager.d.ts +3 -1
  35. package/dist/input/InputManager.d.ts.map +1 -1
  36. package/dist/physics/EffectClusterer.d.ts +18 -0
  37. package/dist/physics/EffectClusterer.d.ts.map +1 -0
  38. package/dist/physics/PhysicsEngine.d.ts +5 -1
  39. package/dist/physics/PhysicsEngine.d.ts.map +1 -1
  40. package/dist/physics/handlers/ChainReactionHelper.d.ts +2 -2
  41. package/dist/physics/handlers/ChainReactionHelper.d.ts.map +1 -1
  42. package/dist/physics/handlers/CoreCollisionHandler.d.ts +3 -1
  43. package/dist/physics/handlers/CoreCollisionHandler.d.ts.map +1 -1
  44. package/dist/physics/handlers/ShieldCollisionHandler.d.ts +3 -1
  45. package/dist/physics/handlers/ShieldCollisionHandler.d.ts.map +1 -1
  46. package/dist/physics/handlers/ThrownCollisionHandler.d.ts +3 -1
  47. package/dist/physics/handlers/ThrownCollisionHandler.d.ts.map +1 -1
  48. package/dist/physics/handlers/ToxicPoolPhysicsHandler.d.ts +2 -1
  49. package/dist/physics/handlers/ToxicPoolPhysicsHandler.d.ts.map +1 -1
  50. package/dist/physics/handlers/VortexPhysicsHandler.d.ts +3 -2
  51. package/dist/physics/handlers/VortexPhysicsHandler.d.ts.map +1 -1
  52. package/dist/powerups/PowerUpRegistry.d.ts +10 -3
  53. package/dist/powerups/PowerUpRegistry.d.ts.map +1 -1
  54. package/dist/powerups/PowerUpTypes.d.ts +6 -1
  55. package/dist/powerups/PowerUpTypes.d.ts.map +1 -1
  56. package/dist/render/CanvasRenderer.d.ts +5 -2
  57. package/dist/render/CanvasRenderer.d.ts.map +1 -1
  58. package/dist/render/EnemyShapeRenderer.d.ts +5 -0
  59. package/dist/render/EnemyShapeRenderer.d.ts.map +1 -1
  60. package/dist/strategies/FragmentClusterStrategy.d.ts.map +1 -1
  61. package/dist/strategies/GravityParasiteStrategy.d.ts.map +1 -1
  62. package/dist/strategies/HeavyShieldStrategy.d.ts.map +1 -1
  63. package/dist/strategies/ImpactStrategy.d.ts +4 -0
  64. package/dist/strategies/ImpactStrategy.d.ts.map +1 -1
  65. package/dist/strategies/ToxicSporeStrategy.d.ts.map +1 -1
  66. package/dist/styles.css +1 -1
  67. package/dist/theme/GameColors.d.ts +4 -1
  68. package/dist/theme/GameColors.d.ts.map +1 -1
  69. package/dist/types/game.d.ts +5 -1
  70. package/dist/types/game.d.ts.map +1 -1
  71. package/dist/ui/HUDOverlay.d.ts +2 -6
  72. package/dist/ui/HUDOverlay.d.ts.map +1 -1
  73. package/dist/ui/ProgressBar.d.ts +8 -4
  74. package/dist/ui/ProgressBar.d.ts.map +1 -1
  75. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- class Y {
1
+ class it {
2
2
  listeners = /* @__PURE__ */ new Map();
3
3
  on(t, e) {
4
4
  return this.listeners.has(t) || this.listeners.set(t, /* @__PURE__ */ new Set()), this.listeners.get(t).add(e), () => this.off(t, e);
@@ -15,7 +15,7 @@ class Y {
15
15
  this.listeners.clear();
16
16
  }
17
17
  }
18
- class Z {
18
+ class st {
19
19
  animationFrameId = null;
20
20
  lastTime = 0;
21
21
  nextFrameTime = 0;
@@ -49,13 +49,17 @@ class Z {
49
49
  this.lastTime = t, this.nextFrameTime += e, this.nextFrameTime < t - e && (this.nextFrameTime = t + e), this.updateCallback(i), this.renderCallback(), this.animationFrameId = requestAnimationFrame(this.tick);
50
50
  }
51
51
  }
52
- const H = {
52
+ const X = {
53
53
  core: {
54
54
  maxIntegrity: 3,
55
55
  invulnerabilityDuration: 1.5,
56
56
  radius: 32,
57
57
  vampirismHealProgressRate: 0,
58
- hasOffscreenIndicators: !1
58
+ hasOffscreenIndicators: !1,
59
+ autoDeflectFragments: !0,
60
+ fragmentDeflectionLookahead: 0.32,
61
+ fragmentDeflectionSpeed: 900,
62
+ fragmentDeflectionCooldown: 0.45
59
63
  },
60
64
  toxicPool: {
61
65
  baseRadius: 40,
@@ -84,7 +88,10 @@ const H = {
84
88
  },
85
89
  cluster: {
86
90
  fragmentCount: 6,
87
- hasHoming: !1
91
+ hasHoming: !1,
92
+ explosionParticleCount: 18,
93
+ maxExplosionShockwaves: 12,
94
+ maxExplosionFloatingTexts: 8
88
95
  },
89
96
  piercer: {
90
97
  terminalAoERadius: 0,
@@ -96,16 +103,35 @@ const H = {
96
103
  psionicRadius: 70,
97
104
  corePickupRadius: 120,
98
105
  absorptionSpeed: 680
106
+ },
107
+ experience: {
108
+ mergeDistance: 34,
109
+ magneticAttractionDistance: 190,
110
+ magneticAttractionStrength: 900,
111
+ baseRadius: 5,
112
+ radiusGrowthPerLevel: 2.5,
113
+ maxRadius: 24,
114
+ mergeDuration: 0.65,
115
+ // Runs produce large XP volumes; keep colour tiers readable before
116
+ // a cluster reaches red.
117
+ blueThreshold: 4,
118
+ yellowThreshold: 32,
119
+ redThreshold: 256
120
+ },
121
+ effectAggregation: {
122
+ toxicPoolMergePadding: 12,
123
+ gravityVortexMergePadding: 24,
124
+ shockwaveMergeDistance: 120
99
125
  }
100
126
  };
101
- class v {
127
+ class N {
102
128
  static instance;
103
129
  config;
104
130
  constructor() {
105
- this.config = JSON.parse(JSON.stringify(H));
131
+ this.config = JSON.parse(JSON.stringify(X));
106
132
  }
107
133
  static getInstance() {
108
- return v.instance || (v.instance = new v()), v.instance;
134
+ return N.instance || (N.instance = new N()), N.instance;
109
135
  }
110
136
  getConfig() {
111
137
  return this.config;
@@ -123,10 +149,15 @@ class v {
123
149
  this.config.core.maxIntegrity += t;
124
150
  }
125
151
  resetToDefault() {
126
- this.config = JSON.parse(JSON.stringify(H));
152
+ this.config = JSON.parse(JSON.stringify(X));
127
153
  }
128
154
  }
129
- class $ {
155
+ class at {
156
+ constructor(t, e, i) {
157
+ this.configManager = i;
158
+ const s = this.configManager.getConfig().core;
159
+ this.position = { x: t, y: e }, this.radius = s.radius, this.integrity = s.maxIntegrity, this.maxIntegrity = s.maxIntegrity, this.maxInvulnerabilityDuration = s.invulnerabilityDuration, this.organicSeed = Math.random() * 100;
160
+ }
130
161
  position;
131
162
  radius;
132
163
  integrity;
@@ -138,16 +169,12 @@ class $ {
138
169
  customColor = { r: 0, g: 240, b: 255 };
139
170
  powerUpCount = 0;
140
171
  collectedPowerUpColors = [];
141
- constructor(t, e) {
142
- const i = v.getInstance().getConfig().core;
143
- this.position = { x: t, y: e }, this.radius = i.radius, this.integrity = i.maxIntegrity, this.maxIntegrity = i.maxIntegrity, this.maxInvulnerabilityDuration = i.invulnerabilityDuration, this.organicSeed = Math.random() * 100;
144
- }
145
172
  absorbPowerUpColor(t, e = 0.35) {
146
173
  this.powerUpCount++, this.collectedPowerUpColors.push(t);
147
174
  const i = t.replace("#", "");
148
175
  if (i.length === 6) {
149
- const s = parseInt(i.substring(0, 2), 16), a = parseInt(i.substring(2, 4), 16), r = parseInt(i.substring(4, 6), 16);
150
- this.customColor.r = Math.round(this.customColor.r * (1 - e) + s * e), this.customColor.g = Math.round(this.customColor.g * (1 - e) + a * e), this.customColor.b = Math.round(this.customColor.b * (1 - e) + r * e);
176
+ const s = parseInt(i.substring(0, 2), 16), a = parseInt(i.substring(2, 4), 16), n = parseInt(i.substring(4, 6), 16);
177
+ this.customColor.r = Math.round(this.customColor.r * (1 - e) + s * e), this.customColor.g = Math.round(this.customColor.g * (1 - e) + a * e), this.customColor.b = Math.round(this.customColor.b * (1 - e) + n * e);
151
178
  }
152
179
  }
153
180
  getHitboxRadius() {
@@ -166,7 +193,7 @@ class $ {
166
193
  }
167
194
  repairProgress = 0;
168
195
  addKillRepair() {
169
- const t = v.getInstance().getConfig().core.vampirismHealProgressRate;
196
+ const t = this.configManager.getConfig().core.vampirismHealProgressRate;
170
197
  return t <= 0 ? !1 : (this.repairProgress += t, this.repairProgress >= 1 ? (this.integrity += 1, this.integrity > this.maxIntegrity && (this.maxIntegrity = this.integrity), this.repairProgress = 0, !0) : !1);
171
198
  }
172
199
  heal(t = 1) {
@@ -179,44 +206,42 @@ class $ {
179
206
  return this.invulnerabilityTimer > 0 ? !1 : this.integrity > 0 ? (this.integrity -= 1, this.invulnerabilityTimer = this.maxInvulnerabilityDuration, !0) : !1;
180
207
  }
181
208
  reset(t, e) {
182
- const i = v.getInstance().getConfig().core;
209
+ const i = this.configManager.getConfig().core;
183
210
  this.position = { x: t, y: e }, this.radius = i.radius, this.maxIntegrity = i.maxIntegrity, this.integrity = this.maxIntegrity, this.maxInvulnerabilityDuration = i.invulnerabilityDuration, this.pulsePhase = 0, this.invulnerabilityTimer = 0, this.repairProgress = 0, this.powerUpCount = 0, this.collectedPowerUpColors = [], this.customColor = { r: 0, g: 240, b: 255 };
184
211
  }
185
212
  }
186
- const f = {
187
- piercer: "#ff2a5f",
188
- spore: "#39ff14",
189
- cluster: "#ffd700",
190
- parasite: "#9d4edd",
191
- heavy: "#c8d0d8",
192
- heavyAccent: "#7d8994",
193
- micro: "#ffd700",
194
- core: "#00f0ff",
195
- coreGlow: "rgba(0, 240, 255, 0.85)",
196
- coreAccent: "#ff00dd",
197
- shieldEye: "#ffd447",
198
- experience: "#fbbf24"
213
+ const J = {
214
+ rendererId: "circle",
215
+ rotatesWithVelocity: !0,
216
+ canBeChainReactionTarget: !0,
217
+ synergyKey: (p) => p.color
199
218
  };
200
- class G {
219
+ class F {
201
220
  id;
202
221
  position = { x: 0, y: 0 };
203
222
  velocity = { x: 0, y: 0 };
204
223
  radius = 20;
205
- type = "piercer";
224
+ type = "";
206
225
  active = !1;
207
226
  isGrabbed = !1;
208
227
  isThrown = !1;
209
228
  wasManipulated = !1;
229
+ isGrabbable = !0;
210
230
  rotation = 0;
211
- color = f.piercer;
231
+ color = "#ffffff";
212
232
  strategy = null;
213
- hitRadiusPadding = 1.2;
233
+ behavior = J;
234
+ synergyKey = "";
235
+ /** Collision padding is deliberately small; visual area effects define their own radius. */
236
+ hitRadiusPadding = 0.2;
214
237
  maxSpeed = 200;
215
238
  isStationaryShield = !1;
216
239
  shieldAngle = 0;
217
240
  launchDelay = 0;
218
241
  remainingHomingKills = 0;
219
242
  experienceDropPending = !1;
243
+ psionicDeflectionCooldown = 0;
244
+ psionicDeflectionTimer = 0;
220
245
  isDying = !1;
221
246
  deathType = "none";
222
247
  deathTimer = 0;
@@ -236,7 +261,7 @@ class G {
236
261
  }
237
262
  update(t) {
238
263
  if (this.active) {
239
- if (this.isDying) {
264
+ if (this.psionicDeflectionCooldown = Math.max(0, this.psionicDeflectionCooldown - t), this.psionicDeflectionTimer = Math.max(0, this.psionicDeflectionTimer - t), this.isDying) {
240
265
  this.deathTimer += t, this.deathTimer >= this.maxDeathTimer && (this.active = !1, this.isDying = !1);
241
266
  return;
242
267
  }
@@ -248,15 +273,15 @@ class G {
248
273
  this.velocity.x *= i, this.velocity.y *= i;
249
274
  }
250
275
  }
251
- this.position.x += this.velocity.x * t, this.position.y += this.velocity.y * t, this.type !== "heavy" && (this.velocity.x !== 0 || this.velocity.y !== 0) && (this.rotation = Math.atan2(this.velocity.y, this.velocity.x));
276
+ this.position.x += this.velocity.x * t, this.position.y += this.velocity.y * t, this.behavior.rotatesWithVelocity && (this.velocity.x !== 0 || this.velocity.y !== 0) && (this.rotation = Math.atan2(this.velocity.y, this.velocity.x));
252
277
  }
253
278
  }
254
279
  }
255
280
  reset() {
256
- 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.isStationaryShield = !1, this.shieldAngle = 0, this.launchDelay = 0, this.experienceDropPending = !1, this.position = { x: 0, y: 0 }, this.velocity = { x: 0, y: 0 }, this.rotation = 0, this.strategy = null, this.maxSpeed = 200;
281
+ this.active = !1, this.isGrabbed = !1, this.isThrown = !1, this.wasManipulated = !1, this.isGrabbable = !0, this.behavior = J, this.synergyKey = "", this.isDying = !1, this.deathType = "none", this.deathTimer = 0, this.sliceAngle = 0, this.isStationaryShield = !1, this.shieldAngle = 0, this.launchDelay = 0, this.experienceDropPending = !1, this.psionicDeflectionCooldown = 0, this.psionicDeflectionTimer = 0, this.position = { x: 0, y: 0 }, this.velocity = { x: 0, y: 0 }, this.rotation = 0, this.strategy = null, this.maxSpeed = 200, this.hitRadiusPadding = 0.2;
257
282
  }
258
283
  }
259
- class B {
284
+ class j {
260
285
  id;
261
286
  definition;
262
287
  position = { x: 0, y: 0 };
@@ -273,7 +298,7 @@ class B {
273
298
  this.active && !this.isGrabbed && !this.isHovered && (this.orbitAngle += t * 0.25, this.position.x = e.x + Math.cos(this.orbitAngle) * this.orbitDistance, this.position.y = e.y + Math.sin(this.orbitAngle) * this.orbitDistance);
274
299
  }
275
300
  }
276
- class z {
301
+ class ot {
277
302
  pointerPosition = { x: 0, y: 0 };
278
303
  isPointerDown = !1;
279
304
  grabbedEnemy = null;
@@ -281,21 +306,22 @@ class z {
281
306
  dragStart = null;
282
307
  pointerHistory = [];
283
308
  canvas;
284
- constructor(t) {
285
- this.canvas = t, this.bindEvents();
309
+ configManager;
310
+ constructor(t, e) {
311
+ this.canvas = t, this.configManager = e, this.bindEvents();
286
312
  }
287
313
  updatePointerPos(t, e) {
288
- const i = this.canvas.getBoundingClientRect(), s = i.width > 0 ? this.canvas.width / i.width : 1, a = i.height > 0 ? this.canvas.height / i.height : 1, r = performance.now() / 1e3;
314
+ const i = this.canvas.getBoundingClientRect(), s = i.width > 0 ? this.canvas.width / i.width : 1, a = i.height > 0 ? this.canvas.height / i.height : 1, n = performance.now() / 1e3;
289
315
  this.pointerPosition = {
290
316
  x: (t - i.left) * s,
291
317
  y: (e - i.top) * a
292
318
  }, this.pointerHistory.push({
293
319
  x: this.pointerPosition.x,
294
320
  y: this.pointerPosition.y,
295
- time: r
321
+ time: n
296
322
  });
297
- const o = r - 0.08;
298
- this.pointerHistory = this.pointerHistory.filter((n) => n.time >= o), this.grabbedEnemy && (this.grabbedEnemy.position = { ...this.pointerPosition });
323
+ const o = n - 0.08;
324
+ this.pointerHistory = this.pointerHistory.filter((r) => r.time >= o), this.grabbedEnemy && (this.grabbedEnemy.position = { ...this.pointerPosition });
299
325
  }
300
326
  bindEvents() {
301
327
  this.canvas.addEventListener("mousemove", (t) => {
@@ -334,9 +360,9 @@ class z {
334
360
  if (this.grabbedEnemy) return this.grabbedEnemy;
335
361
  const i = e ? 50 : 20;
336
362
  for (const s of t) {
337
- if (!s.active || s.isGrabbed || s.isThrown || s.wasManipulated || s.launchDelay > 0) continue;
338
- const a = this.pointerPosition.x - s.position.x, r = this.pointerPosition.y - s.position.y;
339
- if (Math.hypot(a, r) <= s.getHitRadius() + i)
363
+ if (!s.active || !s.isGrabbable || s.isGrabbed || s.isThrown || s.wasManipulated || s.launchDelay > 0) continue;
364
+ const a = this.pointerPosition.x - s.position.x, n = this.pointerPosition.y - s.position.y;
365
+ if (Math.hypot(a, n) <= s.getHitRadius() + i)
340
366
  return s.isGrabbed = !0, this.grabbedEnemy = s, this.dragStart = { ...this.pointerPosition }, this.pointerHistory = [], s;
341
367
  }
342
368
  return null;
@@ -346,8 +372,8 @@ class z {
346
372
  const i = e ? 50 : 20;
347
373
  for (const s of t) {
348
374
  if (!s.active || s.isGrabbed) continue;
349
- const a = this.pointerPosition.x - s.position.x, r = this.pointerPosition.y - s.position.y;
350
- if (Math.hypot(a, r) <= s.radius * 1.5 + i)
375
+ const a = this.pointerPosition.x - s.position.x, n = this.pointerPosition.y - s.position.y;
376
+ if (Math.hypot(a, n) <= s.radius * 1.5 + i)
351
377
  return s.isGrabbed = !0, this.grabbedOrb = s, s;
352
378
  }
353
379
  return null;
@@ -356,37 +382,31 @@ class z {
356
382
  if (!this.grabbedEnemy) return null;
357
383
  const t = this.grabbedEnemy;
358
384
  t.isGrabbed = !1, t.isThrown = !0, t.wasManipulated = !0;
359
- const i = performance.now() / 1e3 - 0.08, s = this.pointerHistory.filter((n) => n.time >= i);
360
- let a = 0, r = 0;
385
+ const i = performance.now() / 1e3 - 0.08, s = this.pointerHistory.filter((r) => r.time >= i);
386
+ let a = 0, n = 0;
361
387
  if (s.length >= 2) {
362
- const n = s[0], l = s[s.length - 1], h = Math.max(0.01, l.time - n.time);
363
- a = (l.x - n.x) / h, r = (l.y - n.y) / h;
388
+ const r = s[0], c = s[s.length - 1], l = Math.max(0.01, c.time - r.time);
389
+ a = (c.x - r.x) / l, n = (c.y - r.y) / l;
364
390
  }
365
- const o = Math.hypot(a, r);
391
+ const o = Math.hypot(a, n);
366
392
  if (o > 30) {
367
- const l = Math.min(o * 1.15, 2500), h = Math.atan2(r, a);
393
+ const c = Math.min(o * 1.15, 2500), l = Math.atan2(n, a);
368
394
  t.velocity = {
369
- x: Math.cos(h) * l,
370
- y: Math.sin(h) * l
395
+ x: Math.cos(l) * c,
396
+ y: Math.sin(l) * c
371
397
  };
372
398
  } else if (this.dragStart) {
373
- const n = t.position.x - this.dragStart.x, l = t.position.y - this.dragStart.y, h = Math.hypot(n, l);
374
- if (h > 5) {
375
- const c = Math.atan2(l, n), p = Math.min(h * 4, 600);
399
+ const r = t.position.x - this.dragStart.x, c = t.position.y - this.dragStart.y, l = Math.hypot(r, c);
400
+ if (l > 5) {
401
+ const h = Math.atan2(c, r), u = Math.min(l * 4, 600);
376
402
  t.velocity = {
377
- x: Math.cos(c) * p,
378
- y: Math.sin(c) * p
403
+ x: Math.cos(h) * u,
404
+ y: Math.sin(h) * u
379
405
  };
380
406
  } else
381
407
  t.velocity = { x: 0, y: 0 }, t.isThrown = !1;
382
408
  }
383
- if (t.type === "heavy")
384
- t.shieldAngle = t.rotation, t.velocity = { x: 0, y: 0 }, t.isStationaryShield = !0, t.isThrown = !1;
385
- else if (t.type === "piercer") {
386
- const n = v.getInstance().getConfig().piercer;
387
- n.hasHoming && (t.remainingHomingKills = n.homingTargets);
388
- }
389
- return this.grabbedEnemy = null, this.dragStart = null, this.pointerHistory = [], t;
409
+ return t.behavior.onRelease?.(t, { config: this.configManager.getConfig() }), this.grabbedEnemy = null, this.dragStart = null, this.pointerHistory = [], t;
390
410
  }
391
411
  forceRelease() {
392
412
  this.grabbedEnemy && (this.grabbedEnemy.isGrabbed = !1, this.grabbedEnemy.isThrown = !1, this.grabbedEnemy.wasManipulated = !1), this.grabbedOrb && (this.grabbedOrb.isGrabbed = !1), this.grabbedEnemy = null, this.grabbedOrb = null, this.dragStart = null, this.pointerHistory = [];
@@ -395,7 +415,7 @@ class z {
395
415
  this.grabbedEnemy = null, this.grabbedOrb = null, this.dragStart = null, this.pointerHistory = [], this.isPointerDown = !1;
396
416
  }
397
417
  }
398
- class J {
418
+ class nt {
399
419
  cellSize;
400
420
  grid = /* @__PURE__ */ new Map();
401
421
  constructor(t = 100) {
@@ -406,23 +426,23 @@ class J {
406
426
  }
407
427
  insert(t) {
408
428
  const e = Math.floor((t.position.x - t.radius) / this.cellSize), i = 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);
409
- for (let r = e; r <= i; r++)
429
+ for (let n = e; n <= i; n++)
410
430
  for (let o = s; o <= a; o++) {
411
- const n = `${r}:${o}`;
412
- this.grid.has(n) || this.grid.set(n, /* @__PURE__ */ new Set()), this.grid.get(n).add(t);
431
+ const r = `${n}:${o}`;
432
+ this.grid.has(r) || this.grid.set(r, /* @__PURE__ */ new Set()), this.grid.get(r).add(t);
413
433
  }
414
434
  }
415
435
  getNearby(t, e) {
416
- const i = /* @__PURE__ */ new Set(), s = Math.floor((t.x - e) / this.cellSize), a = Math.floor((t.x + e) / this.cellSize), r = Math.floor((t.y - e) / this.cellSize), o = Math.floor((t.y + e) / this.cellSize);
417
- for (let n = s; n <= a; n++)
418
- for (let l = r; l <= o; l++) {
419
- const h = `${n}:${l}`, c = this.grid.get(h);
420
- c && c.forEach((p) => i.add(p));
436
+ const i = /* @__PURE__ */ new Set(), s = Math.floor((t.x - e) / this.cellSize), a = Math.floor((t.x + e) / this.cellSize), n = Math.floor((t.y - e) / this.cellSize), o = Math.floor((t.y + e) / this.cellSize);
437
+ for (let r = s; r <= a; r++)
438
+ for (let c = n; c <= o; c++) {
439
+ const l = `${r}:${c}`, h = this.grid.get(l);
440
+ h && h.forEach((u) => i.add(u));
421
441
  }
422
442
  return i;
423
443
  }
424
444
  }
425
- class X {
445
+ class rt {
426
446
  shakeTime = 0;
427
447
  shakeDuration = 0.14;
428
448
  shakeIntensity = 0;
@@ -460,7 +480,7 @@ class X {
460
480
  };
461
481
  }
462
482
  }
463
- const D = {
483
+ const G = {
464
484
  es: {
465
485
  title: "AXON SURGE",
466
486
  startButton: "INICIAR ENLACE",
@@ -1308,7 +1328,7 @@ const D = {
1308
1328
  pu_core_ring_title: "核心过载",
1309
1329
  pu_core_ring_desc: "+1 生命环"
1310
1330
  }
1311
- }, W = [
1331
+ }, tt = [
1312
1332
  "es",
1313
1333
  "en",
1314
1334
  "fr",
@@ -1325,29 +1345,29 @@ const D = {
1325
1345
  "ko",
1326
1346
  "zh"
1327
1347
  ];
1328
- function k(b) {
1329
- return W.includes(b);
1348
+ function B(p) {
1349
+ return tt.includes(p);
1330
1350
  }
1331
- const K = "axon_surge_language";
1332
- class j {
1351
+ const q = "axon_surge_language";
1352
+ class ct {
1333
1353
  currentLanguage;
1334
1354
  constructor(t) {
1335
1355
  this.currentLanguage = this.detectLanguage(t);
1336
1356
  }
1337
1357
  detectLanguage(t) {
1338
1358
  try {
1339
- const e = localStorage.getItem(K);
1340
- if (e && k(e))
1359
+ const e = localStorage.getItem(q);
1360
+ if (e && B(e))
1341
1361
  return e;
1342
1362
  } catch {
1343
1363
  }
1344
- if (t && k(t))
1364
+ if (t && B(t))
1345
1365
  return t;
1346
1366
  try {
1347
1367
  const e = (document.documentElement.lang || document.body?.getAttribute("lang") || document.documentElement.getAttribute("data-lang") || "").toLowerCase();
1348
1368
  if (e) {
1349
1369
  const i = e.split("-")[0];
1350
- if (i && k(i))
1370
+ if (i && B(i))
1351
1371
  return i;
1352
1372
  }
1353
1373
  } catch {
@@ -1356,7 +1376,7 @@ class j {
1356
1376
  const e = (navigator.language || navigator.languages && navigator.languages[0] || "").toLowerCase();
1357
1377
  if (e) {
1358
1378
  const i = e.split("-")[0];
1359
- if (i && k(i))
1379
+ if (i && B(i))
1360
1380
  return i;
1361
1381
  }
1362
1382
  } catch {
@@ -1364,10 +1384,10 @@ class j {
1364
1384
  return "en";
1365
1385
  }
1366
1386
  setLanguage(t) {
1367
- if (D[t]) {
1387
+ if (G[t]) {
1368
1388
  this.currentLanguage = t;
1369
1389
  try {
1370
- localStorage.setItem(K, t);
1390
+ localStorage.setItem(q, t);
1371
1391
  } catch {
1372
1392
  }
1373
1393
  }
@@ -1376,37 +1396,50 @@ class j {
1376
1396
  return this.currentLanguage;
1377
1397
  }
1378
1398
  translate(t, e) {
1379
- let s = (D[this.currentLanguage] || D.en)[t] || D.en[t] || String(t);
1380
- return e && Object.entries(e).forEach(([a, r]) => {
1381
- s = s.replace(`{${a}}`, String(r));
1399
+ let s = (G[this.currentLanguage] || G.en)[t] || G.en[t] || String(t);
1400
+ return e && Object.entries(e).forEach(([a, n]) => {
1401
+ s = s.replace(`{${a}}`, String(n));
1382
1402
  }), s;
1383
1403
  }
1384
1404
  }
1385
- class q {
1386
- static update(t, e, i) {
1387
- const s = v.getInstance().getConfig();
1405
+ class V {
1406
+ static killEnemy(t, e, i) {
1407
+ !t.active || t.isDying || (t.experienceDropPending = !0, i.shockwaves.push({
1408
+ id: Math.random().toString(),
1409
+ position: { ...t.position },
1410
+ radius: 10,
1411
+ maxRadius: 180,
1412
+ color: t.color,
1413
+ alpha: 1,
1414
+ lifetime: 0,
1415
+ maxLifetime: 0.5
1416
+ }), t.behavior.onChainReaction ? t.behavior.onChainReaction({ ...i, enemy: t, angle: e }) : t.triggerDissolveDeath(!0));
1417
+ }
1418
+ }
1419
+ class lt {
1420
+ static update(t, e, i, s) {
1388
1421
  for (let a = t.length - 1; a >= 0; a--) {
1389
- const r = t[a];
1390
- if (r) {
1391
- r.duration += i;
1422
+ const n = t[a];
1423
+ if (n) {
1424
+ n.duration += i;
1392
1425
  for (const o of e) {
1393
- if (!o.active || o.isGrabbed || o.isDying || o.isStationaryShield || o.launchDelay > 0 || o.isThrown && o.type === "piercer") continue;
1394
- const n = r.position.x - o.position.x, l = r.position.y - o.position.y, h = n * n + l * l, c = Math.sqrt(h);
1395
- if (c > 2 && h <= r.radius * r.radius) {
1396
- const p = Math.pow(1 - c / r.radius, 0.7), g = r.pullForce * p, _ = Math.atan2(l, n);
1397
- o.velocity.x += Math.cos(_) * g * i, o.velocity.y += Math.sin(_) * g * i, o.position.x += Math.cos(_) * g * i * 0.8, o.position.y += Math.sin(_) * g * i * 0.8;
1426
+ if (!o.active || o.isGrabbed || o.isDying || o.isStationaryShield || o.launchDelay > 0 || o.isThrown && o.behavior.canInteractWithHazard?.(o, "gravity-vortex") === !1) continue;
1427
+ const r = n.position.x - o.position.x, c = n.position.y - o.position.y, l = r * r + c * c, h = Math.sqrt(l);
1428
+ if (h > 2 && l <= n.radius * n.radius) {
1429
+ const u = Math.pow(1 - h / n.radius, 0.7), d = n.pullForce * u, g = Math.atan2(c, r);
1430
+ o.velocity.x += Math.cos(g) * d * i, o.velocity.y += Math.sin(g) * d * i, o.position.x += Math.cos(g) * d * i * 0.8, o.position.y += Math.sin(g) * d * i * 0.8;
1398
1431
  }
1399
1432
  }
1400
- if (r.duration >= r.maxDuration) {
1433
+ if (n.duration >= n.maxDuration) {
1401
1434
  if (s.gravityVortex.hasImplosionLaunch)
1402
1435
  for (const o of e) {
1403
1436
  if (!o.active || o.isDying) continue;
1404
- const n = o.position.x - r.position.x, l = o.position.y - r.position.y;
1405
- if (n * n + l * l <= r.radius * r.radius) {
1406
- const c = Math.atan2(l, n), p = 1200;
1437
+ const r = o.position.x - n.position.x, c = o.position.y - n.position.y;
1438
+ if (r * r + c * c <= n.radius * n.radius) {
1439
+ const h = Math.atan2(c, r), u = 1200;
1407
1440
  o.isThrown = !0, o.wasManipulated = !0, o.velocity = {
1408
- x: Math.cos(c) * p,
1409
- y: Math.sin(c) * p
1441
+ x: Math.cos(h) * u,
1442
+ y: Math.sin(h) * u
1410
1443
  };
1411
1444
  }
1412
1445
  }
@@ -1416,33 +1449,48 @@ class q {
1416
1449
  }
1417
1450
  }
1418
1451
  }
1419
- class Q {
1420
- static update(t, e, i, s, a, r, o, n, l, h) {
1421
- for (const c of e) {
1422
- if (!c.active || c.isGrabbed || c.isDying || c.launchDelay > 0) continue;
1423
- const p = t.position.x - c.position.x, g = t.position.y - c.position.y;
1424
- if (Math.hypot(p, g) <= t.getHitboxRadius() + c.radius) {
1425
- if (c.active = !1, t.takeDamage()) {
1452
+ const E = {
1453
+ piercer: "#ff2a5f",
1454
+ spore: "#39ff14",
1455
+ cluster: "#ffd700",
1456
+ parasite: "#9d4edd",
1457
+ heavy: "#c8d0d8",
1458
+ micro: "#ffd700",
1459
+ core: "#00f0ff",
1460
+ coreGlow: "rgba(0, 240, 255, 0.85)",
1461
+ coreAccent: "#ff00dd",
1462
+ experience: "#ffffff",
1463
+ experienceBlue: "#38bdf8",
1464
+ experienceYellow: "#fbbf24",
1465
+ experienceRed: "#ef4444"
1466
+ };
1467
+ class ht {
1468
+ static update(t, e, i, s, a, n, o, r, c, l, h) {
1469
+ for (const u of e) {
1470
+ if (!u.active || u.isGrabbed || u.isDying || u.launchDelay > 0 || this.tryAutoDeflectFragment(t, u, i, s, n, h)) continue;
1471
+ const d = t.position.x - u.position.x, g = t.position.y - u.position.y;
1472
+ if (Math.hypot(d, g) <= t.getHitboxRadius() + u.radius) {
1473
+ if (u.active = !1, t.takeDamage()) {
1426
1474
  o.emit("onCoreDamaged", { currentIntegrity: t.integrity }), i.push({
1427
1475
  id: Math.random().toString(),
1428
1476
  position: { ...t.position },
1429
1477
  radius: 20,
1430
- maxRadius: Math.max(l, h) * 1.3,
1431
- color: f.core,
1478
+ maxRadius: Math.max(c, l) * 1.3,
1479
+ color: E.core,
1432
1480
  alpha: 1,
1433
1481
  lifetime: 0,
1434
1482
  maxLifetime: 0.8
1435
- }), r.triggerScreenShake({ x: p, y: g }, 25), r.triggerHitstop(0.15), r.triggerFlash(0.6);
1436
- for (const u of e)
1437
- if (u.active && !u.isGrabbed && u.launchDelay <= 0) {
1438
- u.triggerDissolveDeath();
1439
- for (let d = 0; d < 8; d++) {
1440
- const x = Math.random() * Math.PI * 2, y = 100 + Math.random() * 200;
1483
+ }), n.triggerScreenShake({ x: d, y: g }, 25), n.triggerHitstop(0.15), n.triggerFlash(0.6);
1484
+ for (const _ of e)
1485
+ if (_.active && !_.isGrabbed && _.launchDelay <= 0) {
1486
+ _.triggerDissolveDeath();
1487
+ for (let x = 0; x < 8; x++) {
1488
+ const y = Math.random() * Math.PI * 2, m = 100 + Math.random() * 200;
1441
1489
  s.push({
1442
1490
  id: Math.random().toString(),
1443
- position: { ...u.position },
1444
- velocity: { x: Math.cos(x) * y, y: Math.sin(x) * y },
1445
- color: f.core,
1491
+ position: { ..._.position },
1492
+ velocity: { x: Math.cos(y) * m, y: Math.sin(y) * m },
1493
+ color: E.core,
1446
1494
  radius: 3 + Math.random() * 3,
1447
1495
  alpha: 1,
1448
1496
  lifetime: 0,
@@ -1455,697 +1503,405 @@ class Q {
1455
1503
  text: "CORE OVERLOAD PULSE!",
1456
1504
  position: { ...t.position },
1457
1505
  velocity: { x: 0, y: -90 },
1458
- color: f.core,
1506
+ color: E.core,
1459
1507
  alpha: 1,
1460
1508
  lifetime: 0,
1461
1509
  maxLifetime: 1.5,
1462
1510
  size: 32
1463
- }), t.integrity <= 0 && o.emit("onGameOver", { score: n.value, wave: 1 });
1511
+ }), t.integrity <= 0 && o.emit("onGameOver", { score: r.value, wave: 1 });
1464
1512
  }
1465
1513
  break;
1466
1514
  }
1467
1515
  }
1468
1516
  }
1469
- }
1470
- class tt {
1471
- execute(t) {
1472
- const { thrownEnemy: e, targetEnemy: i, shockwaves: s, particles: a, floatingTexts: r } = t;
1473
- i.experienceDropPending = !0, i.active = !1, s.push({
1517
+ static tryAutoDeflectFragment(t, e, i, s, a, n) {
1518
+ const o = n.core;
1519
+ if (!o.autoDeflectFragments || !e.behavior.autoDeflectFromCore || e.psionicDeflectionCooldown > 0)
1520
+ return !1;
1521
+ const r = t.position.x - e.position.x, c = t.position.y - e.position.y, l = Math.hypot(r, c);
1522
+ if (l <= 0) return !1;
1523
+ const h = Math.hypot(e.velocity.x, e.velocity.y), u = (e.velocity.x * r + e.velocity.y * c) / l;
1524
+ if (h <= 0 || u <= 0) return !1;
1525
+ const d = t.getHitboxRadius() + e.radius;
1526
+ if (Math.max(0, l - d) / u > o.fragmentDeflectionLookahead) return !1;
1527
+ const f = Math.random() * Math.PI * 2, _ = Math.max(o.fragmentDeflectionSpeed, h * 1.08);
1528
+ e.velocity = {
1529
+ x: Math.cos(f) * _,
1530
+ y: Math.sin(f) * _
1531
+ }, e.rotation = f, e.psionicDeflectionCooldown = o.fragmentDeflectionCooldown, e.psionicDeflectionTimer = 0.24, i.push({
1474
1532
  id: Math.random().toString(),
1475
- position: { ...i.position },
1476
- radius: 10,
1477
- maxRadius: 180,
1478
- color: f.piercer,
1479
- alpha: 1,
1533
+ position: { ...e.position },
1534
+ radius: 4,
1535
+ maxRadius: 52,
1536
+ color: E.coreAccent,
1537
+ alpha: 0.9,
1480
1538
  lifetime: 0,
1481
- maxLifetime: 0.5
1539
+ maxLifetime: 0.24
1482
1540
  });
1483
- for (let o = 0; o < 30; o++) {
1484
- const n = Math.random() * Math.PI * 2, l = 180 + Math.random() * 320;
1485
- a.push({
1541
+ for (let x = 0; x < 6; x++) {
1542
+ const y = f + Math.PI + (Math.random() - 0.5) * 1.2, m = 120 + Math.random() * 180;
1543
+ s.push({
1486
1544
  id: Math.random().toString(),
1487
- position: { ...i.position },
1488
- velocity: { x: Math.cos(n) * l, y: Math.sin(n) * l },
1489
- color: f.piercer,
1490
- radius: 3 + Math.random() * 4,
1545
+ position: { ...e.position },
1546
+ velocity: { x: Math.cos(y) * m, y: Math.sin(y) * m },
1547
+ color: E.coreAccent,
1548
+ radius: 2 + Math.random() * 2,
1491
1549
  alpha: 1,
1492
1550
  lifetime: 0,
1493
- maxLifetime: 0.5
1551
+ maxLifetime: 0.3
1494
1552
  });
1495
1553
  }
1496
- r.push({
1497
- id: Math.random().toString(),
1498
- text: "PIERCING SLICE",
1499
- position: { ...i.position },
1500
- velocity: { x: 0, y: -50 },
1501
- color: f.piercer,
1502
- alpha: 1,
1503
- lifetime: 0,
1504
- maxLifetime: 0.8,
1505
- size: 20
1506
- });
1554
+ return a.triggerFlash(0.12), !0;
1507
1555
  }
1508
1556
  }
1509
- class et {
1510
- execute(t) {
1511
- const { thrownEnemy: e, pools: i, shockwaves: s, particles: a, floatingTexts: r, eventBus: o } = t, n = e.position, l = v.getInstance().getConfig();
1512
- i.push({
1513
- id: Math.random().toString(),
1514
- position: { ...n },
1515
- radius: Math.round(l.toxicPool.baseRadius * 2),
1516
- duration: 0,
1517
- maxDuration: l.toxicPool.baseDuration * 1.5,
1518
- damage: l.toxicPool.damage
1519
- }), s.push({
1520
- id: Math.random().toString(),
1521
- position: { ...n },
1522
- radius: 10,
1523
- maxRadius: Math.round(l.toxicPool.baseRadius * 2.2),
1524
- color: f.spore,
1525
- alpha: 1,
1526
- lifetime: 0,
1527
- maxLifetime: 0.6
1528
- });
1529
- for (let h = 0; h < 45; h++) {
1530
- const c = Math.random() * Math.PI * 2, p = 120 + Math.random() * 260;
1531
- a.push({
1532
- id: Math.random().toString(),
1533
- position: { ...n },
1534
- velocity: { x: Math.cos(c) * p, y: Math.sin(c) * p },
1535
- color: f.spore,
1536
- radius: 4 + Math.random() * 5,
1537
- alpha: 1,
1538
- lifetime: 0,
1539
- maxLifetime: 0.9
1557
+ class ut {
1558
+ static update(t, e, i, s, a, n, o, r, c, l, h, u, d, g, b, f) {
1559
+ const _ = (m, v) => {
1560
+ V.killEnemy(m, v, {
1561
+ enemies: t,
1562
+ pools: e,
1563
+ vortices: i,
1564
+ shockwaves: s,
1565
+ particles: a,
1566
+ floatingTexts: n,
1567
+ eventBus: r,
1568
+ juice: o,
1569
+ spatialHash: d,
1570
+ factory: g,
1571
+ config: b,
1572
+ width: l,
1573
+ height: h,
1574
+ currentThrowState: u,
1575
+ onKill: f ?? (() => {
1576
+ }),
1577
+ killEnemy: _
1540
1578
  });
1541
- }
1542
- r.push({
1579
+ }, x = () => ({
1580
+ enemies: t,
1581
+ pools: e,
1582
+ vortices: i,
1583
+ shockwaves: s,
1584
+ particles: a,
1585
+ floatingTexts: n,
1586
+ eventBus: r,
1587
+ juice: o,
1588
+ spatialHash: d,
1589
+ factory: g,
1590
+ config: b,
1591
+ width: l,
1592
+ height: h,
1593
+ currentThrowState: u,
1594
+ onKill: f ?? (() => {
1595
+ }),
1596
+ killEnemy: _
1597
+ });
1598
+ let y = !1;
1599
+ for (const m of t.slice())
1600
+ if (!(!m.active || !m.isThrown || m.isDying || m.launchDelay > 0)) {
1601
+ if (y = !0, m.position.x < -120 || m.position.x > l + 120 || m.position.y < -120 || m.position.y > h + 120) {
1602
+ m.behavior.onOutOfBounds?.(m, x()), m.active = !1, m.isThrown = !1;
1603
+ continue;
1604
+ }
1605
+ for (const v of d.getNearby(m.position, m.getHitRadius() + 80)) {
1606
+ if (v === m || !v.active || v.isGrabbed || v.isDying || v.launchDelay > 0 || v.isStationaryShield) continue;
1607
+ const A = v.position.x - m.position.x, S = v.position.y - m.position.y, L = m.getHitRadius() + v.getHitRadius();
1608
+ if (A * A + S * S > L * L) continue;
1609
+ u.pos = { x: m.position.x, y: m.position.y };
1610
+ const T = Math.atan2(m.velocity.y, m.velocity.x), I = { ...x(), thrownEnemy: m, targetEnemy: v, impactAngle: T };
1611
+ if (m.behavior.onCollision?.(I) ?? !1)
1612
+ break;
1613
+ if (m.strategy) {
1614
+ m.strategy.execute({
1615
+ thrownEnemy: m,
1616
+ targetEnemy: v,
1617
+ allEnemies: t,
1618
+ pools: e,
1619
+ vortices: i,
1620
+ shockwaves: s,
1621
+ particles: a,
1622
+ floatingTexts: n,
1623
+ eventBus: r,
1624
+ width: l,
1625
+ height: h,
1626
+ factory: g,
1627
+ config: b
1628
+ }), m.active && !m.isDying && m.triggerDissolveDeath(!0), v.active && !v.isDying && v.triggerDissolveDeath(!0), u.kills += 2, f?.();
1629
+ break;
1630
+ }
1631
+ const $ = m.synergyKey === v.synergyKey, Z = $ ? 360 : 250;
1632
+ s.push({
1633
+ id: Math.random().toString(),
1634
+ position: { ...u.pos },
1635
+ radius: 15,
1636
+ maxRadius: Z,
1637
+ color: m.color,
1638
+ alpha: 1,
1639
+ lifetime: 0,
1640
+ maxLifetime: 0.55
1641
+ });
1642
+ for (let C = 0; C < 45; C++) {
1643
+ const H = Math.random() * Math.PI * 2, z = 200 + Math.random() * 450;
1644
+ a.push({
1645
+ id: Math.random().toString(),
1646
+ position: { ...u.pos },
1647
+ velocity: { x: Math.cos(H) * z, y: Math.sin(H) * z },
1648
+ color: m.color,
1649
+ radius: 4 + Math.random() * 6,
1650
+ alpha: 1,
1651
+ lifetime: 0,
1652
+ maxLifetime: 0.7
1653
+ });
1654
+ }
1655
+ $ ? (u.kills += 2, o.triggerHitstop(0.14), o.triggerFlash(0.5), o.triggerScreenShake({ x: A, y: S }, 16), _(m, T), _(v, T)) : (u.kills += 2, o.triggerHitstop(0.08), o.triggerFlash(0.35), o.triggerScreenShake({ x: A, y: S }, 10), _(m, T), _(v, T));
1656
+ for (const C of t.slice()) {
1657
+ if (C === m || C === v || !C.active || C.isGrabbed || C.isDying) continue;
1658
+ Math.hypot(C.position.x - u.pos.x, C.position.y - u.pos.y) <= Z && C.behavior.canBeChainReactionTarget && (_(C, T), u.kills++);
1659
+ }
1660
+ f?.();
1661
+ break;
1662
+ }
1663
+ }
1664
+ c.value = u.kills, !y && u.kills > 0 && (u.kills >= 2 && u.pos && n.push({
1543
1665
  id: Math.random().toString(),
1544
- text: "MASSIVE SPORE NEBULA",
1545
- position: { ...n },
1546
- velocity: { x: 0, y: -60 },
1547
- color: f.spore,
1666
+ text: `MULTIKILL x${u.kills}!`,
1667
+ position: { ...u.pos },
1668
+ velocity: { x: 0, y: -90 },
1669
+ color: E.coreAccent,
1548
1670
  alpha: 1,
1549
1671
  lifetime: 0,
1550
- maxLifetime: 1.2,
1551
- size: 26
1552
- }), e.experienceDropPending = !0, e.active = !1, o.emit("onPoolCreated", { position: n });
1672
+ maxLifetime: 1.4,
1673
+ size: 32
1674
+ }), r.emit("onComboUpdated", { combo: c.value }), u.kills = 0, u.pos = null);
1553
1675
  }
1554
1676
  }
1555
- class it {
1556
- execute(t) {
1557
- const { thrownEnemy: e, targetEnemy: i, allEnemies: s, shockwaves: a, particles: r, floatingTexts: o } = t, n = i.position;
1558
- e.experienceDropPending = !0, i.experienceDropPending = !0, e.active = !1, i.active = !1, a.push({
1559
- id: Math.random().toString(),
1560
- position: { ...n },
1561
- radius: 15,
1562
- maxRadius: 280,
1563
- color: f.cluster,
1564
- alpha: 1,
1565
- lifetime: 0,
1566
- maxLifetime: 0.6
1567
- });
1568
- const l = v.getInstance().getConfig(), h = l.cluster.fragmentCount, c = l.cluster.hasHoming;
1569
- for (let p = 0; p < h; p++) {
1570
- const g = p * Math.PI * 2 / h, _ = 800 + Math.random() * 300, m = {
1571
- x: n.x + Math.cos(g) * 45,
1572
- y: n.y + Math.sin(g) * 45
1573
- };
1574
- let u = g;
1575
- if (c) {
1576
- let x = null, y = 1 / 0;
1577
- for (const E of s) {
1578
- if (E === e || E === i || !E.active || E.isGrabbed || E.isDying) continue;
1579
- const I = Math.hypot(E.position.x - m.x, E.position.y - m.y);
1580
- I < y && (y = I, x = E);
1677
+ class pt {
1678
+ static update(t, e, i, s, a, n, o, r, c) {
1679
+ for (let l = t.length - 1; l >= 0; l--) {
1680
+ const h = t[l];
1681
+ if (h) {
1682
+ h.duration += n;
1683
+ for (const u of e.slice()) {
1684
+ if (!u.active || u.isGrabbed || u.isDying || u.launchDelay > 0 || u.isThrown && u.behavior.canInteractWithHazard?.(u, "toxic-pool") === !1) continue;
1685
+ const d = u.position.x - h.position.x, g = u.position.y - h.position.y;
1686
+ d * d + g * g <= h.radius * h.radius && (V.killEnemy(u, 0, r), o.kills++, c && c());
1581
1687
  }
1582
- x && (u = Math.atan2(x.position.y - m.y, x.position.x - m.x));
1688
+ h.duration >= h.maxDuration && t.splice(l, 1);
1583
1689
  }
1584
- const d = P.createEnemy("micro", m, {
1585
- x: m.x + Math.cos(u) * 500,
1586
- y: m.y + Math.sin(u) * 500
1587
- });
1588
- d.isThrown = !0, d.wasManipulated = !0, d.velocity = {
1589
- x: Math.cos(u) * _,
1590
- y: Math.sin(u) * _
1591
- }, s.push(d);
1592
- }
1593
- for (let p = 0; p < 35; p++) {
1594
- const g = Math.random() * Math.PI * 2, _ = 200 + Math.random() * 300;
1595
- r.push({
1596
- id: Math.random().toString(),
1597
- position: { ...n },
1598
- velocity: { x: Math.cos(g) * _, y: Math.sin(g) * _ },
1599
- color: f.cluster,
1600
- radius: 4 + Math.random() * 4,
1601
- alpha: 1,
1602
- lifetime: 0,
1603
- maxLifetime: 0.6
1604
- });
1605
1690
  }
1606
- o.push({
1607
- id: Math.random().toString(),
1608
- text: "CLUSTER DETONATION",
1609
- position: { ...n },
1610
- velocity: { x: 0, y: -60 },
1611
- color: f.cluster,
1612
- alpha: 1,
1613
- lifetime: 0,
1614
- maxLifetime: 1,
1615
- size: 24
1616
- });
1617
1691
  }
1618
1692
  }
1619
- class st {
1620
- execute(t) {
1621
- const { thrownEnemy: e, targetEnemy: i, vortices: s, shockwaves: a } = t, r = v.getInstance().getConfig(), o = {
1622
- x: (e.position.x + i.position.x) / 2,
1623
- y: (e.position.y + i.position.y) / 2
1624
- };
1625
- s.push({
1626
- id: Math.random().toString(),
1627
- position: o,
1628
- radius: Math.round(r.gravityVortex.baseRadius * 2.2),
1629
- duration: 0,
1630
- maxDuration: r.gravityVortex.baseDuration * 1.5,
1631
- pullForce: r.gravityVortex.basePullForce * 1.6
1632
- }), a.push({
1633
- id: Math.random().toString(),
1634
- position: o,
1635
- radius: 20,
1636
- maxRadius: Math.round(r.gravityVortex.baseRadius * 2.2),
1637
- color: f.parasite,
1638
- alpha: 1,
1639
- lifetime: 0,
1640
- maxLifetime: 0.65
1641
- }), e.triggerDissolveDeath(!0), i.triggerDissolveDeath(!0);
1693
+ class dt {
1694
+ static update(t, e, i, s, a, n, o, r, c, l, h, u, d, g, b) {
1695
+ const f = g.shield.protectionArc;
1696
+ for (const _ of t.slice())
1697
+ if (!(!_.active || !_.isStationaryShield || _.isDying))
1698
+ for (const x of u.getNearby(_.position, _.getHitRadius() + 80)) {
1699
+ if (x === _ || !x.active || x.isGrabbed || x.isDying || x.launchDelay > 0) continue;
1700
+ const y = x.position.x - _.position.x, m = x.position.y - _.position.y;
1701
+ let v = Math.atan2(m, y) - _.rotation;
1702
+ for (; v < -Math.PI; ) v += Math.PI * 2;
1703
+ for (; v > Math.PI; ) v -= Math.PI * 2;
1704
+ if (Math.abs(v) > f / 2) continue;
1705
+ const A = _.getHitRadius() + x.getHitRadius();
1706
+ if (y * y + m * m <= A * A) {
1707
+ _.isStationaryShield = !1, _.strategy && _.strategy.execute({
1708
+ thrownEnemy: _,
1709
+ targetEnemy: x,
1710
+ allEnemies: t,
1711
+ pools: e,
1712
+ vortices: i,
1713
+ shockwaves: s,
1714
+ particles: a,
1715
+ floatingTexts: n,
1716
+ eventBus: r,
1717
+ width: l,
1718
+ height: h,
1719
+ factory: d,
1720
+ config: g
1721
+ }), c.kills += 2, o.triggerHitstop(0.12), o.triggerScreenShake({ x: y, y: m }, 18), b && b();
1722
+ break;
1723
+ }
1724
+ }
1642
1725
  }
1643
1726
  }
1644
- class at {
1645
- execute(t) {
1646
- const { thrownEnemy: e, targetEnemy: i, allEnemies: s, shockwaves: a, particles: r, floatingTexts: o } = t, n = i.position.x - e.position.x, l = i.position.y - e.position.y, h = Math.atan2(l, n), c = v.getInstance().getConfig().shield, p = c.blastSpeed || 1400, g = c.isFanBlast ? [0, -c.fanBlastAngle, c.fanBlastAngle] : [0];
1647
- for (const [_, m] of g.entries()) {
1648
- const u = h + m, d = _ === 0 ? e : P.createEnemy(
1649
- "heavy",
1650
- {
1651
- x: e.position.x + Math.cos(u) * 30,
1652
- y: e.position.y + Math.sin(u) * 30
1653
- },
1654
- { x: 0, y: 0 }
1655
- );
1656
- d.isStationaryShield = !1, d.isThrown = !0, d.wasManipulated = !0, d.shieldAngle = u, d.rotation = u, d.launchDelay = c.isFanBlast ? _ * c.fanBlastInterval : 0, d.velocity = {
1657
- x: Math.cos(u) * p,
1658
- y: Math.sin(u) * p
1659
- }, d !== e && s.push(d);
1660
- }
1661
- i.active = !1, i.triggerDissolveDeath(!0), o.push({
1662
- id: Math.random().toString(),
1663
- text: "ARC BLAST!",
1664
- position: { ...e.position },
1665
- velocity: { x: 0, y: -50 },
1666
- color: f.heavy,
1667
- alpha: 1,
1668
- lifetime: 0,
1669
- maxLifetime: 0.9,
1670
- size: 24
1727
+ class R {
1728
+ static merge(t, e, i, s) {
1729
+ R.mergeToxicPools(t, s.toxicPoolMergePadding), R.mergeVortices(e, s.gravityVortexMergePadding), R.mergeShockwaves(i, s.shockwaveMergeDistance);
1730
+ }
1731
+ static mergeToxicPools(t, e) {
1732
+ R.mergeNearby(t, (i, s) => R.distance(i.position.x, i.position.y, s.position.x, s.position.y) <= i.radius + s.radius + e, (i, s) => {
1733
+ const a = Math.max(0, i.maxDuration - i.duration), n = Math.max(0, s.maxDuration - s.duration);
1734
+ R.mergePositionByArea(i, s), i.radius = Math.hypot(i.radius, s.radius), i.duration = 0, i.maxDuration = Math.max(a, n), i.damage += s.damage, i.sourceCount = R.sourceCount(i) + R.sourceCount(s);
1671
1735
  });
1672
- for (let _ = 0; _ < 50; _++) {
1673
- const m = (Math.random() - 0.5) * 1.5, u = h + m, d = 300 + Math.random() * 500;
1674
- r.push({
1675
- id: Math.random().toString(),
1676
- position: { ...e.position },
1677
- velocity: { x: Math.cos(u) * d, y: Math.sin(u) * d },
1678
- color: f.heavy,
1679
- radius: 4 + Math.random() * 6,
1680
- alpha: 1,
1681
- lifetime: 0,
1682
- maxLifetime: 0.7
1683
- });
1684
- }
1685
- o.push({
1686
- id: Math.random().toString(),
1687
- text: "ARC BLAST!",
1688
- position: { ...e.position },
1689
- velocity: { x: 0, y: -50 },
1690
- color: f.heavy,
1691
- alpha: 1,
1692
- lifetime: 0,
1693
- maxLifetime: 0.9,
1694
- size: 24
1736
+ }
1737
+ static mergeVortices(t, e) {
1738
+ R.mergeNearby(t, (i, s) => R.distance(i.position.x, i.position.y, s.position.x, s.position.y) <= i.radius + s.radius + e, (i, s) => {
1739
+ const a = Math.max(0, i.maxDuration - i.duration), n = Math.max(0, s.maxDuration - s.duration);
1740
+ R.mergePositionByArea(i, s), i.radius = Math.hypot(i.radius, s.radius), i.duration = 0, i.maxDuration = Math.max(a, n), i.pullForce += s.pullForce, i.sourceCount = R.sourceCount(i) + R.sourceCount(s);
1695
1741
  });
1696
1742
  }
1697
- }
1698
- class P {
1699
- static createEnemy(t, e, i) {
1700
- const s = `enemy_${Date.now()}_${Math.random()}`, a = new G(s);
1701
- return this.configureEnemy(a, t, e, i), a;
1743
+ static mergeShockwaves(t, e) {
1744
+ R.mergeNearby(t, (i, s) => i.color !== s.color ? !1 : R.distance(i.position.x, i.position.y, s.position.x, s.position.y) <= e, (i, s) => {
1745
+ const a = i.maxRadius > 0 ? i.radius / i.maxRadius : 0, n = s.maxRadius > 0 ? s.radius / s.maxRadius : 0, o = R.sourceCount(i), r = R.sourceCount(s);
1746
+ i.position = {
1747
+ x: (i.position.x * o + s.position.x * r) / (o + r),
1748
+ y: (i.position.y * o + s.position.y * r) / (o + r)
1749
+ }, i.maxRadius = Math.hypot(i.maxRadius, s.maxRadius), i.radius = i.maxRadius * Math.max(a, n), i.lifetime = Math.max(i.lifetime, s.lifetime), i.maxLifetime = Math.max(i.maxLifetime, s.maxLifetime), i.alpha = Math.min(1, Math.max(i.alpha, s.alpha) + 0.08), i.sourceCount = o + r;
1750
+ });
1751
+ }
1752
+ static mergeNearby(t, e, i) {
1753
+ for (let s = 0; s < t.length; s++) {
1754
+ const a = t[s];
1755
+ if (a)
1756
+ for (let n = t.length - 1; n > s; n--) {
1757
+ const o = t[n];
1758
+ !o || !e(a, o) || (i(a, o), t.splice(n, 1));
1759
+ }
1760
+ }
1702
1761
  }
1703
- static configureEnemy(t, e, i, s) {
1704
- t.type = e, t.position = { ...i }, t.active = !0, t.isGrabbed = !1, t.isThrown = !1;
1705
- const a = s.x - i.x, r = s.y - i.y, o = Math.atan2(r, a);
1706
- let n = 70, l = 100, h = 20, c = f.piercer, p = null;
1707
- e === "piercer" ? (n = 95, l = 140, h = 18, c = f.piercer, p = new tt()) : e === "spore" ? (n = 65, l = 90, h = 24, c = f.spore, p = new et()) : e === "cluster" ? (n = 50, l = 75, h = 26, c = f.cluster, p = new it()) : e === "parasite" ? (n = 80, l = 110, h = 22, c = f.parasite, p = new st()) : e === "heavy" ? (n = 35, l = 50, h = 34, c = f.heavy, p = new at(), t.rotation = Math.random() * Math.PI * 2) : e === "micro" && (n = 130, l = 160, h = 12, c = f.micro), t.radius = h, t.color = c, t.strategy = p, t.maxSpeed = l, t.velocity = {
1708
- x: Math.cos(o) * n,
1709
- y: Math.sin(o) * n
1762
+ static mergePositionByArea(t, e) {
1763
+ const i = Math.max(1, t.radius * t.radius), s = Math.max(1, e.radius * e.radius), a = i + s;
1764
+ t.position = {
1765
+ x: (t.position.x * i + e.position.x * s) / a,
1766
+ y: (t.position.y * i + e.position.y * s) / a
1710
1767
  };
1711
1768
  }
1769
+ static sourceCount(t) {
1770
+ return Math.max(1, t.sourceCount ?? 1);
1771
+ }
1772
+ static distance(t, e, i, s) {
1773
+ return Math.hypot(i - t, s - e);
1774
+ }
1712
1775
  }
1713
- class O {
1714
- static killEnemy(t, e, i, s, a, r) {
1715
- if (!t.active || t.isDying) return;
1716
- const o = v.getInstance().getConfig();
1717
- if (t.experienceDropPending = !0, a.push({
1718
- id: Math.random().toString(),
1719
- position: { ...t.position },
1720
- radius: 10,
1721
- maxRadius: 180,
1722
- color: t.color,
1723
- alpha: 1,
1724
- lifetime: 0,
1725
- maxLifetime: 0.5
1726
- }), t.type === "spore")
1727
- t.triggerDissolveDeath(!0), i.push({
1728
- id: Math.random().toString(),
1729
- position: { ...t.position },
1730
- radius: o.toxicPool.baseRadius,
1731
- duration: 0,
1732
- maxDuration: o.toxicPool.baseDuration,
1733
- damage: o.toxicPool.damage
1734
- });
1735
- else if (t.type === "cluster") {
1736
- t.triggerDissolveDeath(!0);
1737
- const n = o.cluster.fragmentCount, l = o.cluster.hasHoming;
1738
- for (let h = 0; h < n; h++) {
1739
- const c = h * Math.PI * 2 / n, p = 750 + Math.random() * 250, g = {
1740
- x: t.position.x + Math.cos(c) * 40,
1741
- y: t.position.y + Math.sin(c) * 40
1742
- };
1743
- let _ = c;
1744
- if (l) {
1745
- let u = null, d = 1 / 0;
1746
- for (const x of r) {
1747
- if (x === t || !x.active || x.isGrabbed || x.isDying) continue;
1748
- const y = Math.hypot(x.position.x - g.x, x.position.y - g.y);
1749
- y < d && (d = y, u = x);
1776
+ class gt {
1777
+ constructor(t, e, i, s) {
1778
+ this.factory = i, this.configManager = s, this.spatialHash = new nt(100), this.eventBus = t, this.i18n = e;
1779
+ }
1780
+ spatialHash;
1781
+ eventBus;
1782
+ i18n;
1783
+ throwState = { kills: 0, pos: null };
1784
+ update(t, e, i, s, a, n, o, r, c, l, h, u, d, g) {
1785
+ const b = this.configManager.getConfig();
1786
+ let f;
1787
+ const _ = (y, m) => V.killEnemy(y, m, f);
1788
+ f = {
1789
+ enemies: i,
1790
+ pools: s,
1791
+ vortices: a,
1792
+ shockwaves: n,
1793
+ particles: o,
1794
+ floatingTexts: r,
1795
+ eventBus: this.eventBus,
1796
+ juice: c,
1797
+ spatialHash: this.spatialHash,
1798
+ factory: this.factory,
1799
+ config: b,
1800
+ width: u,
1801
+ height: d,
1802
+ currentThrowState: this.throwState,
1803
+ onKill: g ?? (() => {
1804
+ }),
1805
+ killEnemy: _
1806
+ };
1807
+ for (const y of i)
1808
+ if (y.active && !y.isDying) {
1809
+ if (y.behavior.onThrownUpdate?.(y, {
1810
+ dt: t,
1811
+ enemies: i,
1812
+ config: b
1813
+ }), y.isStationaryShield) {
1814
+ let m = null, v = 1 / 0;
1815
+ for (const A of i) {
1816
+ if (A === y || !A.active || A.isGrabbed || A.isDying || A.isStationaryShield) continue;
1817
+ const S = A.position.x - y.position.x, L = A.position.y - y.position.y, T = S * S + L * L;
1818
+ T < v && (v = T, m = A);
1819
+ }
1820
+ if (m) {
1821
+ let S = Math.atan2(m.position.y - y.position.y, m.position.x - y.position.x) - y.rotation;
1822
+ for (; S < -Math.PI; ) S += Math.PI * 2;
1823
+ for (; S > Math.PI; ) S -= Math.PI * 2;
1824
+ const L = 5 * t;
1825
+ y.rotation += Math.sign(S) * Math.min(Math.abs(S), L);
1750
1826
  }
1751
- u && (_ = Math.atan2(u.position.y - g.y, u.position.x - g.x));
1752
1827
  }
1753
- const m = P.createEnemy("micro", g, {
1754
- x: g.x + Math.cos(_) * 500,
1755
- y: g.y + Math.sin(_) * 500
1756
- });
1757
- m.isThrown = !0, m.wasManipulated = !0, m.velocity = {
1758
- x: Math.cos(_) * p,
1759
- y: Math.sin(_) * p
1760
- }, r.push(m);
1761
- }
1762
- } else t.type === "parasite" ? (t.triggerDissolveDeath(!0), s.push({
1763
- id: Math.random().toString(),
1764
- position: { ...t.position },
1765
- radius: o.gravityVortex.baseRadius,
1766
- duration: 0,
1767
- maxDuration: o.gravityVortex.baseDuration,
1768
- pullForce: o.gravityVortex.basePullForce
1769
- })) : t.type === "piercer" ? t.triggerSliceDeath(e, !0) : t.triggerDissolveDeath(!0);
1770
- }
1771
- }
1772
- class ot {
1773
- static update(t, e, i, s, a, r, o, n, l, h, c, p, g, _) {
1774
- let m = !1;
1775
- for (const u of t)
1776
- if (!(!u.active || !u.isThrown || u.isDying || u.launchDelay > 0)) {
1777
- if (m = !0, u.position.x < -120 || u.position.x > h + 120 || u.position.y < -120 || u.position.y > c + 120) {
1778
- if (u.type === "heavy") {
1779
- s.push({
1780
- id: Math.random().toString(),
1781
- position: { ...u.position },
1782
- radius: 20,
1783
- maxRadius: 350,
1784
- color: f.core,
1785
- alpha: 1,
1786
- lifetime: 0,
1787
- maxLifetime: 0.6
1788
- });
1789
- for (let d = 0; d < 40; d++) {
1790
- const x = Math.random() * Math.PI * 2, y = 250 + Math.random() * 450;
1791
- a.push({
1792
- id: Math.random().toString(),
1793
- position: { ...u.position },
1794
- velocity: { x: Math.cos(x) * y, y: Math.sin(x) * y },
1795
- color: f.core,
1796
- radius: 4 + Math.random() * 5,
1797
- alpha: 1,
1798
- lifetime: 0,
1799
- maxLifetime: 0.6
1800
- });
1801
- }
1802
- } else if (u.type === "piercer") {
1803
- const d = v.getInstance().getConfig().piercer;
1804
- if (d.terminalAoERadius > 0) {
1805
- const x = d.terminalAoERadius;
1806
- s.push({
1807
- id: Math.random().toString(),
1808
- position: { ...u.position },
1809
- radius: 20,
1810
- maxRadius: x,
1811
- color: f.piercer,
1812
- alpha: 1,
1813
- lifetime: 0,
1814
- maxLifetime: 0.6
1815
- });
1816
- for (const y of g.getNearby(u.position, x)) {
1817
- if (!y.active || y.isGrabbed || y.isDying) continue;
1818
- const E = y.position.x - u.position.x, I = y.position.y - u.position.y;
1819
- E * E + I * I <= x * x && O.killEnemy(y, Math.atan2(I, E), e, i, s, t);
1820
- }
1821
- }
1822
- }
1823
- u.active = !1, u.isThrown = !1;
1824
- continue;
1825
- }
1826
- for (const d of g.getNearby(u.position, u.getHitRadius() + 80)) {
1827
- if (d === u || !d.active || d.isGrabbed || d.isDying || d.launchDelay > 0) continue;
1828
- const x = d.position.x - u.position.x, y = d.position.y - u.position.y, E = u.getHitRadius() + d.getHitRadius();
1829
- if (x * x + y * y <= E * E) {
1830
- p.pos = { x: u.position.x, y: u.position.y };
1831
- const I = Math.atan2(u.velocity.y, u.velocity.x);
1832
- if (u.type === "heavy") {
1833
- p.kills++, O.killEnemy(d, u.rotation, e, i, s, t), o.triggerHitstop(0.04), o.triggerScreenShake({ x, y }, 8);
1834
- for (let T = 0; T < 8; T++) {
1835
- const L = u.rotation + (Math.random() - 0.5), A = 200 + Math.random() * 350;
1836
- a.push({
1837
- id: Math.random().toString(),
1838
- position: { ...d.position },
1839
- velocity: { x: Math.cos(L) * A, y: Math.sin(L) * A },
1840
- color: f.core,
1841
- radius: 3 + Math.random() * 4,
1842
- alpha: 1,
1843
- lifetime: 0,
1844
- maxLifetime: 0.4
1845
- });
1846
- }
1847
- _ && _();
1848
- } else if (u.type === "piercer") {
1849
- p.kills++, O.killEnemy(d, I, e, i, s, t), o.triggerHitstop(0.05), o.triggerScreenShake({ x, y }, 7), s.push({
1850
- id: Math.random().toString(),
1851
- position: { ...d.position },
1852
- radius: 10,
1853
- maxRadius: 180,
1854
- color: f.piercer,
1855
- alpha: 1,
1856
- lifetime: 0,
1857
- maxLifetime: 0.45
1858
- });
1859
- for (let T = 0; T < 16; T++) {
1860
- const L = Math.random() * Math.PI * 2, A = 150 + Math.random() * 300;
1861
- a.push({
1862
- id: Math.random().toString(),
1863
- position: { ...d.position },
1864
- velocity: { x: Math.cos(L) * A, y: Math.sin(L) * A },
1865
- color: f.piercer,
1866
- radius: 3 + Math.random() * 3,
1867
- alpha: 1,
1868
- lifetime: 0,
1869
- maxLifetime: 0.4
1870
- });
1871
- }
1872
- if (u.remainingHomingKills > 0) {
1873
- u.remainingHomingKills--;
1874
- let T = null, L = 1 / 0;
1875
- for (const A of t) {
1876
- if (A === u || A === d || !A.active || A.isGrabbed || A.isDying) continue;
1877
- const R = A.position.x - u.position.x, C = A.position.y - u.position.y, S = Math.hypot(R, C);
1878
- S < L && (L = S, T = A);
1879
- }
1880
- if (T) {
1881
- const A = Math.atan2(T.position.y - u.position.y, T.position.x - u.position.x), R = Math.hypot(u.velocity.x, u.velocity.y) || 1200;
1882
- u.rotation = A, u.velocity = {
1883
- x: Math.cos(A) * R,
1884
- y: Math.sin(A) * R
1885
- };
1886
- }
1887
- }
1888
- _ && _();
1889
- } else {
1890
- const T = u.type === d.type, L = T ? 360 : 250;
1891
- s.push({
1892
- id: Math.random().toString(),
1893
- position: { ...p.pos },
1894
- radius: 15,
1895
- maxRadius: L,
1896
- color: u.color,
1897
- alpha: 1,
1898
- lifetime: 0,
1899
- maxLifetime: 0.55
1900
- });
1901
- for (let A = 0; A < 45; A++) {
1902
- const R = Math.random() * Math.PI * 2, C = 200 + Math.random() * 450;
1903
- a.push({
1904
- id: Math.random().toString(),
1905
- position: { ...p.pos },
1906
- velocity: { x: Math.cos(R) * C, y: Math.sin(R) * C },
1907
- color: u.color,
1908
- radius: 4 + Math.random() * 6,
1909
- alpha: 1,
1910
- lifetime: 0,
1911
- maxLifetime: 0.7
1912
- });
1913
- }
1914
- if (u.strategy) {
1915
- u.strategy.execute({
1916
- thrownEnemy: u,
1917
- targetEnemy: d,
1918
- allEnemies: t,
1919
- pools: e,
1920
- vortices: i,
1921
- shockwaves: s,
1922
- particles: a,
1923
- floatingTexts: r,
1924
- eventBus: n,
1925
- width: h,
1926
- height: c
1927
- }), p.kills += 2, _ && _();
1928
- break;
1929
- }
1930
- if (T) {
1931
- p.kills += 2, o.triggerHitstop(0.14), o.triggerFlash(0.5), o.triggerScreenShake({ x, y }, 16), r.push({
1932
- id: Math.random().toString(),
1933
- text: "COLOR SYNERGY!",
1934
- position: { ...p.pos },
1935
- velocity: { x: 0, y: -80 },
1936
- color: u.color,
1937
- alpha: 1,
1938
- lifetime: 0,
1939
- maxLifetime: 1.2,
1940
- size: 26
1941
- });
1942
- const A = v.getInstance().getConfig();
1943
- u.type === "spore" ? e.push({
1944
- id: Math.random().toString(),
1945
- position: { ...p.pos },
1946
- radius: Math.round(A.toxicPool.baseRadius * 2),
1947
- duration: 0,
1948
- maxDuration: A.toxicPool.synergyDuration,
1949
- damage: A.toxicPool.damage * 2
1950
- }) : u.type === "parasite" && i.push({
1951
- id: Math.random().toString(),
1952
- position: { ...p.pos },
1953
- radius: Math.round(A.gravityVortex.baseRadius * 1.8),
1954
- duration: 0,
1955
- maxDuration: A.gravityVortex.synergyDuration,
1956
- pullForce: A.gravityVortex.synergyPullForce
1957
- }), O.killEnemy(u, I, e, i, s, t), O.killEnemy(d, I, e, i, s, t);
1958
- } else
1959
- p.kills += 2, o.triggerHitstop(0.08), o.triggerFlash(0.35), o.triggerScreenShake({ x, y }, 10), O.killEnemy(u, I, e, i, s, t), O.killEnemy(d, I, e, i, s, t);
1960
- for (const A of t) {
1961
- if (A === u || A === d || !A.active || A.isGrabbed || A.isDying) continue;
1962
- const R = A.position.x - p.pos.x, C = A.position.y - p.pos.y;
1963
- Math.hypot(R, C) <= L && A.type !== "micro" && (O.killEnemy(A, I, e, i, s, t), p.kills++);
1964
- }
1965
- _ && _();
1966
- break;
1967
- }
1968
- }
1969
- }
1970
- }
1971
- l.value = p.kills, !m && p.kills > 0 && (p.kills >= 2 && p.pos && r.push({
1972
- id: Math.random().toString(),
1973
- text: `MULTIKILL x${p.kills}!`,
1974
- position: { ...p.pos },
1975
- velocity: { x: 0, y: -90 },
1976
- color: f.coreAccent,
1977
- alpha: 1,
1978
- lifetime: 0,
1979
- maxLifetime: 1.4,
1980
- size: 32
1981
- }), n.emit("onComboUpdated", { combo: l.value }), p.kills = 0, p.pos = null);
1982
- }
1983
- }
1984
- class nt {
1985
- static update(t, e, i, s, a, r, o, n) {
1986
- for (let l = t.length - 1; l >= 0; l--) {
1987
- const h = t[l];
1988
- if (h) {
1989
- h.duration += r;
1990
- for (const c of e) {
1991
- if (!c.active || c.isGrabbed || c.isDying || c.launchDelay > 0 || c.isThrown && c.type === "piercer") continue;
1992
- const p = c.position.x - h.position.x, g = c.position.y - h.position.y;
1993
- p * p + g * g <= h.radius * h.radius && (O.killEnemy(c, 0, t, i, s, e), o.kills++, n && n());
1994
- }
1995
- h.duration >= h.maxDuration && t.splice(l, 1);
1996
- }
1828
+ y.update(t);
1829
+ } else y.active && y.isDying && y.update(t);
1830
+ for (let y = n.length - 1; y >= 0; y--) {
1831
+ const m = n[y];
1832
+ if (!m) continue;
1833
+ m.lifetime += t;
1834
+ const v = m.lifetime / m.maxLifetime;
1835
+ m.radius = m.maxRadius * v, m.alpha = Math.max(0, 1 - v), m.lifetime >= m.maxLifetime && n.splice(y, 1);
1997
1836
  }
1998
- }
1999
- }
2000
- class rt {
2001
- static update(t, e, i, s, a, r, o, n, l, h, c, p, g) {
2002
- const _ = v.getInstance().getConfig().shield.protectionArc;
2003
- for (const m of t)
2004
- if (!(!m.active || !m.isStationaryShield || m.isDying))
2005
- for (const u of p.getNearby(m.position, m.getHitRadius() + 80)) {
2006
- if (u === m || !u.active || u.isGrabbed || u.isDying || u.launchDelay > 0) continue;
2007
- const d = u.position.x - m.position.x, x = u.position.y - m.position.y;
2008
- let y = Math.atan2(x, d) - m.rotation;
2009
- for (; y < -Math.PI; ) y += Math.PI * 2;
2010
- for (; y > Math.PI; ) y -= Math.PI * 2;
2011
- if (Math.abs(y) > _ / 2) continue;
2012
- const E = m.getHitRadius() + u.getHitRadius();
2013
- if (d * d + x * x <= E * E) {
2014
- m.isStationaryShield = !1, m.strategy && m.strategy.execute({
2015
- thrownEnemy: m,
2016
- targetEnemy: u,
2017
- allEnemies: t,
2018
- pools: e,
2019
- vortices: i,
2020
- shockwaves: s,
2021
- particles: a,
2022
- floatingTexts: r,
2023
- eventBus: n,
2024
- width: h,
2025
- height: c
2026
- }), l.kills += 2, o.triggerHitstop(0.12), o.triggerScreenShake({ x: d, y: x }, 18), g && g();
2027
- break;
2028
- }
2029
- }
2030
- }
2031
- }
2032
- class lt {
2033
- spatialHash;
2034
- eventBus;
2035
- i18n;
2036
- throwState = { kills: 0, pos: null };
2037
- constructor(t, e) {
2038
- this.spatialHash = new J(100), this.eventBus = t, this.i18n = e;
2039
- }
2040
- update(t, e, i, s, a, r, o, n, l, h, c, p, g, _) {
2041
- const m = v.getInstance().getConfig().piercer;
2042
- for (const d of i)
2043
- if (d.active && !d.isDying) {
2044
- if (d.isThrown && d.type === "piercer" && m.hasHoming && d.remainingHomingKills > 0) {
2045
- let x = null, y = 1 / 0;
2046
- for (const E of i) {
2047
- if (E === d || !E.active || E.isGrabbed || E.isDying) continue;
2048
- const I = E.position.x - d.position.x, T = E.position.y - d.position.y, L = I * I + T * T;
2049
- L < y && (y = L, x = E);
2050
- }
2051
- if (x) {
2052
- const E = Math.atan2(x.position.y - d.position.y, x.position.x - d.position.x), I = Math.max(Math.hypot(d.velocity.x, d.velocity.y), 1e3), T = 25 * t, L = Math.atan2(d.velocity.y, d.velocity.x);
2053
- let A = E - L;
2054
- for (; A < -Math.PI; ) A += Math.PI * 2;
2055
- for (; A > Math.PI; ) A -= Math.PI * 2;
2056
- const R = L + Math.sign(A) * Math.min(Math.abs(A), T);
2057
- d.rotation = R, d.velocity = {
2058
- x: Math.cos(R) * I,
2059
- y: Math.sin(R) * I
2060
- };
2061
- }
2062
- }
2063
- if (d.isStationaryShield) {
2064
- let x = null, y = 1 / 0;
2065
- for (const E of i) {
2066
- if (E === d || !E.active || E.isGrabbed || E.isDying || E.isStationaryShield) continue;
2067
- const I = E.position.x - d.position.x, T = E.position.y - d.position.y, L = I * I + T * T;
2068
- L < y && (y = L, x = E);
2069
- }
2070
- if (x) {
2071
- let I = Math.atan2(x.position.y - d.position.y, x.position.x - d.position.x) - d.rotation;
2072
- for (; I < -Math.PI; ) I += Math.PI * 2;
2073
- for (; I > Math.PI; ) I -= Math.PI * 2;
2074
- const T = 5 * t;
2075
- d.rotation += Math.sign(I) * Math.min(Math.abs(I), T);
2076
- }
2077
- }
2078
- d.update(t);
2079
- } else d.active && d.isDying && d.update(t);
2080
- for (let d = r.length - 1; d >= 0; d--) {
2081
- const x = r[d];
2082
- if (!x) continue;
2083
- x.lifetime += t;
2084
- const y = x.lifetime / x.maxLifetime;
2085
- x.radius = x.maxRadius * y, x.alpha = Math.max(0, 1 - y), x.lifetime >= x.maxLifetime && r.splice(d, 1);
2086
- }
2087
- q.update(a, i, t), this.spatialHash.clear();
2088
- for (const d of i)
2089
- d.active && !d.isDying && d.launchDelay <= 0 && this.spatialHash.insert(d);
2090
- Q.update(
1837
+ lt.update(a, i, t, b), this.spatialHash.clear();
1838
+ for (const y of i)
1839
+ y.active && !y.isDying && y.launchDelay <= 0 && this.spatialHash.insert(y);
1840
+ ht.update(
2091
1841
  e,
2092
1842
  i,
2093
- r,
2094
- o,
2095
1843
  n,
2096
- l,
2097
- this.eventBus,
1844
+ o,
1845
+ r,
2098
1846
  c,
2099
- p,
2100
- g
2101
- ), ot.update(
1847
+ this.eventBus,
1848
+ h,
1849
+ u,
1850
+ d,
1851
+ b
1852
+ ), ut.update(
2102
1853
  i,
2103
1854
  s,
2104
1855
  a,
2105
- r,
2106
- o,
2107
1856
  n,
2108
- l,
1857
+ o,
1858
+ r,
1859
+ c,
2109
1860
  this.eventBus,
2110
- h,
2111
- p,
2112
- g,
1861
+ l,
1862
+ u,
1863
+ d,
2113
1864
  this.throwState,
2114
1865
  this.spatialHash,
2115
- _
2116
- ), nt.update(
1866
+ this.factory,
1867
+ b,
1868
+ g
1869
+ ), pt.update(
2117
1870
  s,
2118
1871
  i,
2119
1872
  a,
2120
- r,
1873
+ n,
2121
1874
  o,
2122
1875
  t,
2123
1876
  this.throwState,
2124
- _
2125
- ), rt.update(
1877
+ f,
1878
+ g
1879
+ ), dt.update(
2126
1880
  i,
2127
1881
  s,
2128
1882
  a,
2129
- r,
2130
- o,
2131
1883
  n,
2132
- l,
1884
+ o,
1885
+ r,
1886
+ c,
2133
1887
  this.eventBus,
2134
1888
  this.throwState,
2135
- p,
2136
- g,
1889
+ u,
1890
+ d,
2137
1891
  this.spatialHash,
2138
- _
2139
- );
2140
- const u = 32;
2141
- r.length > u && r.splice(0, r.length - u);
1892
+ this.factory,
1893
+ b,
1894
+ g
1895
+ ), R.merge(s, a, n, b.effectAggregation);
1896
+ const x = 32;
1897
+ n.length > x && n.splice(0, n.length - x);
2142
1898
  }
2143
1899
  }
2144
- class ct {
1900
+ class mt {
2145
1901
  pool = [];
2146
1902
  constructor(t = 500) {
2147
1903
  for (let e = 0; e < t; e++) {
2148
- const i = new G(`pool_enemy_${e}`);
1904
+ const i = new F(`pool_enemy_${e}`);
2149
1905
  this.pool.push(i);
2150
1906
  }
2151
1907
  }
@@ -2153,7 +1909,7 @@ class ct {
2153
1909
  for (const e of this.pool)
2154
1910
  if (!e.active)
2155
1911
  return e.reset(), e;
2156
- const t = new G(`fallback_enemy_${Date.now()}_${Math.random()}`);
1912
+ const t = new F(`fallback_enemy_${Date.now()}_${Math.random()}`);
2157
1913
  return this.pool.push(t), t;
2158
1914
  }
2159
1915
  resetAll() {
@@ -2161,185 +1917,295 @@ class ct {
2161
1917
  t.reset();
2162
1918
  }
2163
1919
  }
2164
- class N {
1920
+ class w {
1921
+ static algorithms = {
1922
+ circle: (t, e, i, s, a, n) => w.spawnCircleOfDeath(t, e, i, s, a, n),
1923
+ dense: (t, e, i, s, a, n) => w.spawnDenseCluster(t, e, i, a, n, s),
1924
+ sine: (t, e, i, s, a, n) => w.spawnSineSnake(t, e, i, a, n, s),
1925
+ spiral: (t, e, i, s, a, n) => w.spawnDoubleSpiral(t, e, i, a, n, s),
1926
+ marching: (t, e, i, s, a, n) => w.spawnMarchingWall(t, e, i, a, n, s),
1927
+ crossfire: (t, e, i, s, a, n) => w.spawnCrossfireStreams(t, e, i, a, n, s)
1928
+ };
1929
+ static spawn(t, e, i, s, a, n, o) {
1930
+ return this.algorithms[i]?.(t, e, s, a, n, o) ?? [];
1931
+ }
2165
1932
  static getOffscreenPosition(t, e) {
2166
1933
  const i = Math.floor(Math.random() * 4), s = 70;
2167
1934
  return i === 0 ? { x: Math.random() * t, y: -s } : i === 1 ? { x: t + s, y: Math.random() * e } : i === 2 ? { x: Math.random() * t, y: e + s } : { x: -s, y: Math.random() * e };
2168
1935
  }
2169
- static spawnCircleOfDeath(t, e, i, s) {
2170
- const a = [], o = Math.max(i, s) * 0.55 + 80;
2171
- for (let n = 0; n < 18; n++) {
2172
- const l = n * Math.PI * 2 / 18, h = {
2173
- x: e.x + Math.cos(l) * o,
2174
- y: e.y + Math.sin(l) * o
2175
- }, c = t.get(), p = ["piercer", "spore", "cluster", "parasite"], g = p[n % p.length];
2176
- P.configureEnemy(c, g, h, e), c.velocity = {
2177
- x: Math.cos(l + Math.PI) * 55,
2178
- y: Math.sin(l + Math.PI) * 55
2179
- }, a.push(c);
1936
+ static spawnCircleOfDeath(t, e, i, s, a, n) {
1937
+ const o = [], c = Math.max(a, n) * 0.55 + 80;
1938
+ for (let l = 0; l < 18; l++) {
1939
+ const h = l * Math.PI * 2 / 18, u = {
1940
+ x: s.x + Math.cos(h) * c,
1941
+ y: s.y + Math.sin(h) * c
1942
+ }, d = e.get(), g = i[l % i.length];
1943
+ t.configureEnemy(d, g, u, s), d.velocity = {
1944
+ x: Math.cos(h + Math.PI) * 55,
1945
+ y: Math.sin(h + Math.PI) * 55
1946
+ }, o.push(d);
2180
1947
  }
2181
- return a;
2182
- }
2183
- static spawnDenseCluster(t, e, i, s) {
2184
- const a = [], o = Math.floor(Math.random() * 4);
2185
- let n = { x: -60, y: -60 };
2186
- o === 0 ? n = { x: Math.random() * e, y: -80 } : o === 1 ? n = { x: e + 80, y: Math.random() * i } : o === 2 ? n = { x: Math.random() * e, y: i + 80 } : n = { x: -80, y: Math.random() * i };
2187
- for (let l = 0; l < 14; l++) {
2188
- const h = {
1948
+ return o;
1949
+ }
1950
+ static spawnDenseCluster(t, e, i, s, a, n) {
1951
+ const o = [], c = Math.floor(Math.random() * 4);
1952
+ let l = { x: -60, y: -60 };
1953
+ c === 0 ? l = { x: Math.random() * s, y: -80 } : c === 1 ? l = { x: s + 80, y: Math.random() * a } : c === 2 ? l = { x: Math.random() * s, y: a + 80 } : l = { x: -80, y: Math.random() * a };
1954
+ for (let h = 0; h < 14; h++) {
1955
+ const u = {
2189
1956
  x: (Math.random() - 0.5) * 60,
2190
1957
  y: (Math.random() - 0.5) * 60
2191
- }, c = { x: n.x + h.x, y: n.y + h.y }, p = t.get();
2192
- P.configureEnemy(p, "spore", c, s);
2193
- const g = s.x - c.x, _ = s.y - c.y, m = Math.atan2(_, g);
2194
- p.velocity = {
2195
- x: Math.cos(m) * (50 + Math.random() * 20),
2196
- y: Math.sin(m) * (50 + Math.random() * 20)
2197
- }, a.push(p);
1958
+ }, d = { x: l.x + u.x, y: l.y + u.y }, g = e.get();
1959
+ t.configureEnemy(g, i[0], d, n);
1960
+ const b = n.x - d.x, f = n.y - d.y, _ = Math.atan2(f, b);
1961
+ g.velocity = {
1962
+ x: Math.cos(_) * (50 + Math.random() * 20),
1963
+ y: Math.sin(_) * (50 + Math.random() * 20)
1964
+ }, o.push(g);
2198
1965
  }
2199
- return a;
2200
- }
2201
- static spawnSineSnake(t, e, i, s) {
2202
- const a = [], o = i * 0.2 + Math.random() * i * 0.6;
2203
- for (let n = 0; n < 12; n++) {
2204
- const l = {
2205
- x: -60 - n * 40,
2206
- y: o + Math.sin(n * 0.45) * 70
2207
- }, h = t.get();
2208
- P.configureEnemy(h, "cluster", l, s), h.velocity = { x: 75, y: Math.cos(n * 0.45) * 30 }, a.push(h);
1966
+ return o;
1967
+ }
1968
+ static spawnSineSnake(t, e, i, s, a, n) {
1969
+ const o = [], c = a * 0.2 + Math.random() * a * 0.6;
1970
+ for (let l = 0; l < 12; l++) {
1971
+ const h = {
1972
+ x: -60 - l * 40,
1973
+ y: c + Math.sin(l * 0.45) * 70
1974
+ }, u = e.get();
1975
+ t.configureEnemy(u, i[0], h, n), u.velocity = { x: 75, y: Math.cos(l * 0.45) * 30 }, o.push(u);
2209
1976
  }
2210
- return a;
2211
- }
2212
- static spawnDoubleSpiral(t, e, i, s) {
2213
- const a = [];
2214
- for (let o = 0; o < 14; o++) {
2215
- const n = o / 14, l = n * Math.PI * 4, h = 120 + n * 450, c = {
2216
- x: e + Math.cos(l) * h,
2217
- y: -60 + Math.sin(l) * h
2218
- }, p = t.get();
2219
- P.configureEnemy(p, "parasite", c, s), a.push(p);
1977
+ return o;
1978
+ }
1979
+ static spawnDoubleSpiral(t, e, i, s, a, n) {
1980
+ const o = [];
1981
+ for (let c = 0; c < 14; c++) {
1982
+ const l = c / 14, h = l * Math.PI * 4, u = 120 + l * 450, d = {
1983
+ x: s + Math.cos(h) * u,
1984
+ y: -60 + Math.sin(h) * u
1985
+ }, g = e.get();
1986
+ t.configureEnemy(g, i[0], d, n), o.push(g);
2220
1987
  }
2221
- return a;
2222
- }
2223
- static spawnMarchingWall(t, e, i, s) {
2224
- const a = [], o = Math.random() > 0.5;
2225
- for (let n = 0; n < 12; n++) {
2226
- const l = n / 11 * i, h = {
2227
- x: o ? -60 : e + 60,
2228
- y: l
2229
- }, c = t.get();
2230
- P.configureEnemy(c, "piercer", h, s), c.velocity = {
2231
- x: o ? 70 : -70,
1988
+ return o;
1989
+ }
1990
+ static spawnMarchingWall(t, e, i, s, a, n) {
1991
+ const o = [], c = Math.random() > 0.5;
1992
+ for (let l = 0; l < 12; l++) {
1993
+ const h = l / 11 * a, u = {
1994
+ x: c ? -60 : s + 60,
1995
+ y: h
1996
+ }, d = e.get();
1997
+ t.configureEnemy(d, i[0], u, n), d.velocity = {
1998
+ x: c ? 70 : -70,
2232
1999
  y: 0
2233
- }, a.push(c);
2000
+ }, o.push(d);
2234
2001
  }
2235
- return a;
2236
- }
2237
- static spawnCrossfireStreams(t, e, i, s) {
2238
- const a = [];
2239
- for (let o = 0; o < 10; o++) {
2240
- const n = { x: -50 - o * 35, y: -50 - o * 35 }, l = t.get();
2241
- P.configureEnemy(l, "spore", n, s), a.push(l);
2242
- const h = { x: e + 50 + o * 35, y: i + 50 + o * 35 }, c = t.get();
2243
- P.configureEnemy(c, "cluster", h, s), a.push(c);
2002
+ return o;
2003
+ }
2004
+ static spawnCrossfireStreams(t, e, i, s, a, n) {
2005
+ const o = [];
2006
+ for (let c = 0; c < 10; c++) {
2007
+ const l = { x: -50 - c * 35, y: -50 - c * 35 }, h = e.get();
2008
+ t.configureEnemy(h, i[0], l, n), o.push(h);
2009
+ const u = { x: s + 50 + c * 35, y: a + 50 + c * 35 }, d = e.get();
2010
+ t.configureEnemy(d, i[1 % i.length], u, n), o.push(d);
2244
2011
  }
2245
- return a;
2012
+ return o;
2246
2013
  }
2247
2014
  }
2248
- class ht {
2015
+ class _t {
2016
+ constructor(t, e) {
2017
+ this.factory = t, this.content = e, this.pool = new mt(500);
2018
+ }
2249
2019
  wave = 1;
2250
2020
  pool;
2251
2021
  spawnTimer = 0;
2252
2022
  waveTimer = 0;
2253
2023
  patternCooldown = 0;
2254
2024
  initialGracePeriod = 6;
2255
- constructor() {
2256
- this.pool = new ct(500);
2257
- }
2258
2025
  reset() {
2259
2026
  this.wave = 1, this.spawnTimer = 0, this.waveTimer = 0, this.patternCooldown = 0;
2260
2027
  }
2261
2028
  update(t, e, i, s, a) {
2262
2029
  this.waveTimer += t, this.spawnTimer += t, this.patternCooldown += t, this.applyFlockingBehaviors(e, t, a);
2263
- const r = e.filter((l) => l.active).length, o = Math.max(0.9, 2.2 - (this.wave - 1) * 0.18);
2264
- if (this.waveTimer > this.initialGracePeriod && this.patternCooldown > Math.max(12 - this.wave, 6) && r < 35) {
2030
+ const n = e.filter((c) => c.active).length, o = Math.max(0.9, 2.2 - (this.wave - 1) * 0.18);
2031
+ if (this.waveTimer > this.initialGracePeriod && this.patternCooldown > Math.max(12 - this.wave, 6) && n < 35) {
2265
2032
  this.patternCooldown = 0;
2266
- const l = this.spawnPatternFormation(i, s, a);
2267
- for (const h of l)
2268
- e.push(h);
2033
+ const c = this.spawnPatternFormation(i, s, a);
2034
+ for (const l of c)
2035
+ e.push(l);
2269
2036
  }
2270
- const n = Math.min(18 + this.wave * 4, 80);
2271
- return this.spawnTimer >= o && r < n ? (this.spawnTimer = 0, this.spawnSingleEnemy(i, s, a)) : null;
2037
+ const r = Math.min(18 + this.wave * 4, 80);
2038
+ return this.spawnTimer >= o && n < r ? (this.spawnTimer = 0, this.spawnSingleEnemy(i, s, a)) : null;
2272
2039
  }
2273
2040
  spawnSingleEnemy(t, e, i) {
2274
- const s = N.getOffscreenPosition(t, e), a = Math.random();
2275
- let r = "piercer";
2276
- a > 0.75 ? r = "heavy" : a > 0.55 ? r = "parasite" : a > 0.35 ? r = "cluster" : a > 0.15 && (r = "spore");
2277
- const o = this.pool.get();
2278
- return P.configureEnemy(o, r, s, i), o;
2041
+ const s = w.getOffscreenPosition(t, e), a = this.content.enemies.values().filter((l) => (l.spawnWeight ?? 0) > 0), n = a.reduce((l, h) => l + (h.spawnWeight ?? 0), 0);
2042
+ let o = Math.random() * n, r = a[0]?.id ?? "";
2043
+ for (const l of a)
2044
+ if (o -= l.spawnWeight ?? 0, o <= 0) {
2045
+ r = l.id;
2046
+ break;
2047
+ }
2048
+ const c = this.pool.get();
2049
+ return this.factory.configureEnemy(c, r, s, i), c;
2279
2050
  }
2280
2051
  spawnPatternFormation(t, e, i) {
2281
- const s = Math.random();
2282
- return s < 0.25 ? N.spawnCircleOfDeath(this.pool, i, t, e) : s < 0.5 ? N.spawnDenseCluster(this.pool, t, e, i) : s < 0.75 ? N.spawnSineSnake(this.pool, t, e, i) : N.spawnMarchingWall(this.pool, t, e, i);
2052
+ const s = this.content.spawnerPatterns.values(), a = s.reduce((r, c) => r + c.weight, 0);
2053
+ let n = Math.random() * a;
2054
+ const o = s.find((r) => (n -= r.weight, n <= 0));
2055
+ return o ? w.spawn(this.factory, this.pool, o.algorithmId, o.enemyIds, i, t, e) : [];
2283
2056
  }
2284
2057
  applyFlockingBehaviors(t, e, i) {
2285
2058
  for (let a = 0; a < t.length; a++) {
2286
- const r = t[a];
2287
- if (!r.active || r.isGrabbed || r.isThrown || r.isDying) continue;
2288
- let o = 0, n = 0, l = 0;
2289
- for (let g = 0; g < t.length; g++) {
2290
- if (a === g) continue;
2291
- const _ = t[g];
2292
- if (!_.active || _.isGrabbed || _.isDying) continue;
2293
- const m = r.position.x - _.position.x, u = r.position.y - _.position.y, d = Math.hypot(m, u);
2294
- d > 0 && d < 70 && (o += m / d, n += u / d, l++);
2059
+ const n = t[a];
2060
+ if (!n.active || n.isGrabbed || n.isThrown || n.isDying) continue;
2061
+ let o = 0, r = 0, c = 0;
2062
+ for (let d = 0; d < t.length; d++) {
2063
+ if (a === d) continue;
2064
+ const g = t[d];
2065
+ if (!g.active || g.isGrabbed || g.isDying) continue;
2066
+ const b = n.position.x - g.position.x, f = n.position.y - g.position.y, _ = Math.hypot(b, f);
2067
+ _ > 0 && _ < 70 && (o += b / _, r += f / _, c++);
2295
2068
  }
2296
- l > 0 && (o /= l, n /= l, r.velocity.x += o * 60 * e, r.velocity.y += n * 60 * e);
2297
- const h = i.x - r.position.x, c = i.y - r.position.y, p = Math.hypot(h, c);
2298
- if (p > 0) {
2299
- const g = 80 + Math.min(this.wave * 4, 40);
2300
- r.velocity.x += h / p * g * e, r.velocity.y += c / p * g * e;
2069
+ c > 0 && (o /= c, r /= c, n.velocity.x += o * 60 * e, n.velocity.y += r * 60 * e);
2070
+ const l = i.x - n.position.x, h = i.y - n.position.y, u = Math.hypot(l, h);
2071
+ if (u > 0) {
2072
+ const d = 80 + Math.min(this.wave * 4, 40);
2073
+ n.velocity.x += l / u * d * e, n.velocity.y += h / u * d * e;
2301
2074
  }
2302
- if (r.maxSpeed > 0) {
2303
- const g = Math.hypot(r.velocity.x, r.velocity.y);
2304
- if (g > r.maxSpeed) {
2305
- const _ = r.maxSpeed / g;
2306
- r.velocity.x *= _, r.velocity.y *= _;
2075
+ if (n.maxSpeed > 0) {
2076
+ const d = Math.hypot(n.velocity.x, n.velocity.y);
2077
+ if (d > n.maxSpeed) {
2078
+ const g = n.maxSpeed / d;
2079
+ n.velocity.x *= g, n.velocity.y *= g;
2307
2080
  }
2308
2081
  }
2309
2082
  }
2310
2083
  }
2311
2084
  }
2312
- class pt {
2085
+ const ft = {
2086
+ mergeDistance: 34,
2087
+ magneticAttractionDistance: 190,
2088
+ magneticAttractionStrength: 900,
2089
+ baseRadius: 5,
2090
+ radiusGrowthPerLevel: 2.5,
2091
+ maxRadius: 24,
2092
+ mergeDuration: 0.65,
2093
+ blueThreshold: 4,
2094
+ yellowThreshold: 32,
2095
+ redThreshold: 256
2096
+ };
2097
+ class k {
2313
2098
  id;
2314
2099
  position;
2315
2100
  velocity;
2316
2101
  value;
2317
- radius = 5;
2102
+ radius;
2103
+ color;
2318
2104
  active = !0;
2319
2105
  isAbsorbing = !1;
2320
- constructor(t, e = 1) {
2321
- this.id = `xp_${Date.now()}_${Math.random()}`, this.position = { ...t }, this.value = e;
2322
- const i = Math.random() * Math.PI * 2, s = 25 + Math.random() * 45;
2106
+ isMerging = !1;
2107
+ visualScale = 1;
2108
+ mergePulse = 0;
2109
+ absorbedByCore = !1;
2110
+ config;
2111
+ mergeTarget = null;
2112
+ mergeStartPosition = null;
2113
+ mergeElapsed = 0;
2114
+ constructor(t, e = 1, i = ft) {
2115
+ this.id = `xp_${Date.now()}_${Math.random()}`, this.position = { ...t }, this.value = Math.max(1, e), this.config = i, this.radius = i.baseRadius, this.color = E.experience, this.updateAppearance();
2116
+ const s = Math.random() * Math.PI * 2, a = 25 + Math.random() * 45;
2323
2117
  this.velocity = {
2324
- x: Math.cos(i) * s,
2325
- y: Math.sin(i) * s
2118
+ x: Math.cos(s) * a,
2119
+ y: Math.sin(s) * a
2326
2120
  };
2327
2121
  }
2122
+ /**
2123
+ * Fuses nearby, loose orbs into a single cluster. A spatial hash keeps this
2124
+ * bounded when many enemies die in the same area instead of comparing every
2125
+ * orb with every other orb.
2126
+ */
2127
+ static mergeNearby(t, e) {
2128
+ if (t.length < 2 || e <= 0) return;
2129
+ const i = e, s = /* @__PURE__ */ new Map();
2130
+ for (const a of t) {
2131
+ if (!a.active || a.isAbsorbing || a.isMerging) continue;
2132
+ const n = k.getCellKey(a.position, i), o = s.get(n);
2133
+ o ? o.push(a) : s.set(n, [a]);
2134
+ }
2135
+ for (const a of t) {
2136
+ if (!a.active || a.isAbsorbing || a.isMerging) continue;
2137
+ const n = Math.floor(a.position.x / i), o = Math.floor(a.position.y / i);
2138
+ for (let r = -1; r <= 1; r++)
2139
+ for (let c = -1; c <= 1; c++) {
2140
+ const l = s.get(`${n + r}:${o + c}`);
2141
+ if (l)
2142
+ for (const h of l) {
2143
+ if (h === a || !h.active || h.isAbsorbing || h.isMerging) continue;
2144
+ const u = h.position.x - a.position.x, d = h.position.y - a.position.y, g = Math.hypot(u, d), b = Math.min(12, Math.max(0, Math.max(a.radius, h.radius) - a.config.baseRadius));
2145
+ g <= e + b && a.mergeWith(h);
2146
+ }
2147
+ }
2148
+ }
2149
+ }
2150
+ /** Applies a gentle pairwise pull before fusion so the player can read the cluster forming. */
2151
+ static attractNearby(t, e, i) {
2152
+ const s = e.magneticAttractionDistance;
2153
+ if (t.length < 2 || s <= 0 || e.magneticAttractionStrength <= 0) return;
2154
+ const a = s, n = /* @__PURE__ */ new Map();
2155
+ for (const o of t) {
2156
+ if (!o.active || o.isAbsorbing || o.isMerging) continue;
2157
+ const r = k.getCellKey(o.position, a), c = n.get(r);
2158
+ c ? c.push(o) : n.set(r, [o]);
2159
+ }
2160
+ for (const o of t) {
2161
+ if (!o.active || o.isAbsorbing || o.isMerging) continue;
2162
+ const r = Math.floor(o.position.x / a), c = Math.floor(o.position.y / a);
2163
+ for (let l = -1; l <= 1; l++)
2164
+ for (let h = -1; h <= 1; h++) {
2165
+ const u = n.get(`${r + l}:${c + h}`);
2166
+ if (u)
2167
+ for (const d of u) {
2168
+ if (d === o || !d.active || d.isAbsorbing || d.isMerging || d.id <= o.id)
2169
+ continue;
2170
+ const g = d.position.x - o.position.x, b = d.position.y - o.position.y, f = Math.hypot(g, b);
2171
+ if (f <= 0 || f > s) continue;
2172
+ const _ = 1 - f / s, y = e.magneticAttractionStrength * _ * _ * i, m = g / f, v = b / f;
2173
+ o.velocity.x += m * y, o.velocity.y += v * y, d.velocity.x -= m * y, d.velocity.y -= v * y;
2174
+ }
2175
+ }
2176
+ }
2177
+ }
2328
2178
  beginAbsorption() {
2329
2179
  this.active && (this.isAbsorbing = !0);
2330
2180
  }
2181
+ mergeWith(t) {
2182
+ if (!this.active || !t.active || this.isAbsorbing || t.isAbsorbing || this === t)
2183
+ return;
2184
+ const e = this.value + t.value, i = this.value / e, s = t.value / e;
2185
+ this.position = {
2186
+ x: this.position.x * i + t.position.x * s,
2187
+ y: this.position.y * i + t.position.y * s
2188
+ }, this.velocity = {
2189
+ x: this.velocity.x * i + t.velocity.x * s,
2190
+ y: this.velocity.y * i + t.velocity.y * s
2191
+ }, this.value = e, this.updateAppearance(), this.mergePulse = Math.min(1, this.mergePulse + 0.35), t.isMerging = !0, t.mergeTarget = this, t.mergeStartPosition = { ...t.position }, t.mergeElapsed = 0, t.visualScale = 1, t.isAbsorbing = !1, t.velocity = { x: 0, y: 0 };
2192
+ }
2331
2193
  update(t, e, i, s) {
2332
2194
  if (this.active) {
2333
- if (this.isAbsorbing) {
2334
- const a = e.x - this.position.x, r = e.y - this.position.y, o = Math.hypot(a, r);
2195
+ if (this.isMerging) {
2196
+ this.updateMergeAnimation(t);
2197
+ return;
2198
+ }
2199
+ if (this.mergePulse = Math.max(0, this.mergePulse - t * 3.5), this.isAbsorbing) {
2200
+ const a = e.x - this.position.x, n = e.y - this.position.y, o = Math.hypot(a, n);
2335
2201
  if (o <= i + this.radius) {
2336
- this.position = { ...e }, this.active = !1;
2202
+ this.position = { ...e }, this.absorbedByCore = !0, this.active = !1;
2337
2203
  return;
2338
2204
  }
2339
- const n = Math.min(s + o * 0.7, 1600);
2205
+ const r = Math.min(s + o * 0.7, 1600);
2340
2206
  this.velocity = {
2341
- x: a / o * n,
2342
- y: r / o * n
2207
+ x: a / o * r,
2208
+ y: n / o * r
2343
2209
  };
2344
2210
  } else {
2345
2211
  const a = Math.pow(0.04, t);
@@ -2348,22 +2214,45 @@ class pt {
2348
2214
  this.position.x += this.velocity.x * t, this.position.y += this.velocity.y * t;
2349
2215
  }
2350
2216
  }
2217
+ updateAppearance() {
2218
+ const e = Math.log2(this.value) * this.config.radiusGrowthPerLevel;
2219
+ this.radius = Math.min(this.config.maxRadius, this.config.baseRadius + e), this.color = this.getTierColor();
2220
+ }
2221
+ getTierColor() {
2222
+ return this.value >= this.config.redThreshold ? E.experienceRed : this.value >= this.config.yellowThreshold ? E.experienceYellow : this.value >= this.config.blueThreshold ? E.experienceBlue : E.experience;
2223
+ }
2224
+ updateMergeAnimation(t) {
2225
+ const e = this.mergeTarget, i = this.mergeStartPosition;
2226
+ if (!e || !e.active || !i) {
2227
+ this.active = !1, this.isMerging = !1;
2228
+ return;
2229
+ }
2230
+ this.mergeElapsed += t;
2231
+ const s = Math.min(1, this.mergeElapsed / this.config.mergeDuration), a = 1 - Math.pow(1 - s, 3);
2232
+ this.position = {
2233
+ x: i.x + (e.position.x - i.x) * a,
2234
+ y: i.y + (e.position.y - i.y) * a
2235
+ }, this.visualScale = 1 - a * 0.85, s >= 1 && (this.active = !1, this.isMerging = !1, this.mergeTarget = null, this.mergeStartPosition = null, this.visualScale = 1);
2236
+ }
2237
+ static getCellKey(t, e) {
2238
+ return `${Math.floor(t.x / e)}:${Math.floor(t.y / e)}`;
2239
+ }
2351
2240
  }
2352
- const w = {
2241
+ const U = {
2353
2242
  bioluminescent: {
2354
2243
  bgInner: "#081220",
2355
2244
  bgMid: "#050b16",
2356
2245
  bgOuter: "#020408",
2357
2246
  nebulaCyan: "rgba(0, 240, 255, 0.08)",
2358
2247
  nebulaMagenta: "rgba(255, 0, 221, 0.07)",
2359
- piercerColor: f.piercer,
2360
- sporeColor: f.spore,
2361
- clusterColor: f.cluster,
2362
- parasiteColor: f.parasite,
2363
- microColor: f.micro,
2364
- corePrimary: f.core,
2365
- coreGlow: f.coreGlow,
2366
- tendrilMagenta: f.coreAccent,
2248
+ piercerColor: E.piercer,
2249
+ sporeColor: E.spore,
2250
+ clusterColor: E.cluster,
2251
+ parasiteColor: E.parasite,
2252
+ microColor: E.micro,
2253
+ corePrimary: E.core,
2254
+ coreGlow: E.coreGlow,
2255
+ tendrilMagenta: E.coreAccent,
2367
2256
  tendrilCyan: "#00ffff",
2368
2257
  effectHighlight: "#ffffff",
2369
2258
  effectInk: "#ffffff",
@@ -2416,22 +2305,22 @@ const w = {
2416
2305
  vortexCore: "#274760",
2417
2306
  vortexMid: "#577c9e"
2418
2307
  }
2419
- }, U = "axon_surge_theme";
2420
- class ut {
2308
+ }, K = "axon_surge_theme";
2309
+ class yt {
2421
2310
  currentTheme = "dark";
2422
2311
  isExplicit = !1;
2423
2312
  targetElement;
2424
2313
  constructor(t, e) {
2425
2314
  e !== void 0 && (this.targetElement = e);
2426
2315
  try {
2427
- const i = localStorage.getItem(U);
2428
- if (i && w[i]) {
2316
+ const i = localStorage.getItem(K);
2317
+ if (i && U[i]) {
2429
2318
  this.currentTheme = i, this.isExplicit = !0, this.applyThemeToDOM();
2430
2319
  return;
2431
2320
  }
2432
2321
  } catch {
2433
2322
  }
2434
- if (t && w[t]) {
2323
+ if (t && U[t]) {
2435
2324
  this.currentTheme = t, this.isExplicit = !0, this.applyThemeToDOM();
2436
2325
  return;
2437
2326
  }
@@ -2441,10 +2330,10 @@ class ut {
2441
2330
  this.targetElement = t, this.isExplicit ? this.applyThemeToDOM() : this.currentTheme = this.detectParentOrSystemTheme();
2442
2331
  }
2443
2332
  setTheme(t) {
2444
- if (w[t]) {
2333
+ if (U[t]) {
2445
2334
  this.currentTheme = t, this.isExplicit = !0, this.applyThemeToDOM();
2446
2335
  try {
2447
- localStorage.setItem(U, t);
2336
+ localStorage.setItem(K, t);
2448
2337
  } catch {
2449
2338
  }
2450
2339
  }
@@ -2452,7 +2341,7 @@ class ut {
2452
2341
  clearExplicitTheme() {
2453
2342
  this.isExplicit = !1;
2454
2343
  try {
2455
- localStorage.removeItem(U);
2344
+ localStorage.removeItem(K);
2456
2345
  } catch {
2457
2346
  }
2458
2347
  this.removeThemeClasses(), this.currentTheme = this.detectParentOrSystemTheme();
@@ -2461,7 +2350,7 @@ class ut {
2461
2350
  return this.isExplicit || (this.currentTheme = this.detectParentOrSystemTheme()), this.currentTheme;
2462
2351
  }
2463
2352
  getPalette() {
2464
- return w[this.getTheme()] || w.dark;
2353
+ return U[this.getTheme()] || U.dark;
2465
2354
  }
2466
2355
  detectParentOrSystemTheme() {
2467
2356
  try {
@@ -2499,83 +2388,83 @@ class ut {
2499
2388
  this.targetElement.classList.add(t);
2500
2389
  }
2501
2390
  }
2502
- class dt {
2391
+ class xt {
2503
2392
  maxDistance = 800;
2504
2393
  maxThickness = 18;
2505
2394
  minThickness = 5;
2506
2395
  maxLength = 110;
2507
2396
  minLength = 50;
2508
2397
  render(t, e, i, s, a) {
2509
- for (const r of e) {
2510
- if (!r.active || r.isGrabbed || r.isDying) continue;
2511
- const o = r.position.x, n = r.position.y;
2512
- if (o >= 0 && o <= i && n >= 0 && n <= s) continue;
2513
- const l = Math.min(i, Math.max(0, o)), h = Math.min(s, Math.max(0, n)), c = Math.hypot(o - l, n - h);
2514
- if (c <= 0 || c > this.maxDistance) continue;
2515
- const p = Math.min(1, Math.max(0, c / this.maxDistance)), g = this.minThickness + (this.maxThickness - this.minThickness) * (1 - p), _ = this.minLength + (this.maxLength - this.minLength) * (1 - p), m = 0.55 + (1 - p) * 0.35;
2516
- if (t.save(), t.globalAlpha = m, t.shadowColor = r.color, t.shadowBlur = 14, t.strokeStyle = r.color, t.lineWidth = g, t.lineCap = "round", t.beginPath(), l === 0 || l === i) {
2517
- const u = Math.max(0, h - _ / 2), d = Math.min(s, h + _ / 2);
2518
- t.moveTo(l, u), t.lineTo(l, d);
2398
+ for (const n of e) {
2399
+ if (!n.active || n.isGrabbed || n.isDying) continue;
2400
+ const o = n.position.x, r = n.position.y;
2401
+ if (o >= 0 && o <= i && r >= 0 && r <= s) continue;
2402
+ const c = Math.min(i, Math.max(0, o)), l = Math.min(s, Math.max(0, r)), h = Math.hypot(o - c, r - l);
2403
+ if (h <= 0 || h > this.maxDistance) continue;
2404
+ const u = Math.min(1, Math.max(0, h / this.maxDistance)), d = this.minThickness + (this.maxThickness - this.minThickness) * (1 - u), g = this.minLength + (this.maxLength - this.minLength) * (1 - u), b = 0.55 + (1 - u) * 0.35;
2405
+ if (t.save(), t.globalAlpha = b, t.shadowColor = n.color, t.shadowBlur = 14, t.strokeStyle = n.color, t.lineWidth = d, t.lineCap = "round", t.beginPath(), c === 0 || c === i) {
2406
+ const f = Math.max(0, l - g / 2), _ = Math.min(s, l + g / 2);
2407
+ t.moveTo(c, f), t.lineTo(c, _);
2519
2408
  } else {
2520
- const u = Math.max(0, l - _ / 2), d = Math.min(i, l + _ / 2);
2521
- t.moveTo(u, h), t.lineTo(d, h);
2409
+ const f = Math.max(0, c - g / 2), _ = Math.min(i, c + g / 2);
2410
+ t.moveTo(f, l), t.lineTo(_, l);
2522
2411
  }
2523
- t.stroke(), t.strokeStyle = a.effectHighlight, t.lineWidth = Math.max(1.8, g * 0.28), t.globalAlpha = m * 0.9, t.stroke(), t.restore();
2412
+ t.stroke(), t.strokeStyle = a.effectHighlight, t.lineWidth = Math.max(1.8, d * 0.28), t.globalAlpha = b * 0.9, t.stroke(), t.restore();
2524
2413
  }
2525
2414
  }
2526
2415
  }
2527
- class gt {
2528
- render(t, e, i, s, a, r, o = !1) {
2529
- const n = Math.max(1, a), l = Math.min(1, (n - 1) / 8), h = this.wrapHue(190 + (n - 1) * 34 + Math.sin(s * 0.1) * 5), c = this.wrapHue(h + 42), p = this.wrapHue(h + 150), g = e / 2, _ = i / 2, m = Math.max(e, i) * 0.82, u = t.createRadialGradient(g, _, 20, g, _, m);
2530
- o ? (u.addColorStop(0, `hsl(${h}, 42%, 91%)`), u.addColorStop(0.42, `hsl(${c}, 42%, 86%)`), u.addColorStop(0.78, `hsl(${p}, 38%, 81%)`), u.addColorStop(1, r.bgOuter)) : (u.addColorStop(0, `hsl(${h}, 42%, 11%)`), u.addColorStop(0.42, `hsl(${c}, 48%, 8%)`), u.addColorStop(0.78, `hsl(${p}, 42%, 5%)`), u.addColorStop(1, `hsl(${p}, 48%, 2.5%)`)), t.fillStyle = u, t.fillRect(0, 0, e, i);
2531
- const d = Math.min(e, i) * 0.055;
2416
+ class bt {
2417
+ render(t, e, i, s, a, n, o = !1) {
2418
+ const r = Math.max(1, a), c = Math.min(1, (r - 1) / 8), l = this.wrapHue(190 + (r - 1) * 34 + Math.sin(s * 0.1) * 5), h = this.wrapHue(l + 42), u = this.wrapHue(l + 150), d = e / 2, g = i / 2, b = Math.max(e, i) * 0.82, f = t.createRadialGradient(d, g, 20, d, g, b);
2419
+ o ? (f.addColorStop(0, `hsl(${l}, 42%, 91%)`), f.addColorStop(0.42, `hsl(${h}, 42%, 86%)`), f.addColorStop(0.78, `hsl(${u}, 38%, 81%)`), f.addColorStop(1, n.bgOuter)) : (f.addColorStop(0, `hsl(${l}, 42%, 11%)`), f.addColorStop(0.42, `hsl(${h}, 48%, 8%)`), f.addColorStop(0.78, `hsl(${u}, 42%, 5%)`), f.addColorStop(1, `hsl(${u}, 48%, 2.5%)`)), t.fillStyle = f, t.fillRect(0, 0, e, i);
2420
+ const _ = Math.min(e, i) * 0.055;
2532
2421
  this.drawNebula(
2533
2422
  t,
2534
- e * 0.22 + Math.sin(s * 0.18) * d,
2535
- i * 0.28 + Math.cos(s * 0.15) * d,
2423
+ e * 0.22 + Math.sin(s * 0.18) * _,
2424
+ i * 0.28 + Math.cos(s * 0.15) * _,
2536
2425
  Math.max(e, i) * 0.42,
2537
- h,
2426
+ l,
2538
2427
  o ? 0.27 : 0.23,
2539
2428
  o
2540
2429
  ), this.drawNebula(
2541
2430
  t,
2542
- e * 0.8 + Math.cos(s * 0.14) * d,
2543
- i * 0.7 + Math.sin(s * 0.17) * d,
2431
+ e * 0.8 + Math.cos(s * 0.14) * _,
2432
+ i * 0.7 + Math.sin(s * 0.17) * _,
2544
2433
  Math.max(e, i) * 0.48,
2545
- c,
2434
+ h,
2546
2435
  o ? 0.23 : 0.2,
2547
2436
  o
2548
2437
  ), this.drawNebula(
2549
2438
  t,
2550
- e * 0.86 + Math.sin(s * 0.11) * d * 0.7,
2551
- i * 0.16 + Math.cos(s * 0.13) * d * 0.7,
2439
+ e * 0.86 + Math.sin(s * 0.11) * _ * 0.7,
2440
+ i * 0.16 + Math.cos(s * 0.13) * _ * 0.7,
2552
2441
  Math.max(e, i) * 0.3,
2553
- p,
2442
+ u,
2554
2443
  o ? 0.17 : 0.14,
2555
2444
  o
2556
- ), this.drawSoftFlows(t, e, i, s, h, l, o), this.drawParticleField(t, e, i, s, h, c, n, o);
2557
- const x = t.createRadialGradient(g, _, Math.min(e, i) * 0.28, g, _, m);
2445
+ ), this.drawSoftFlows(t, e, i, s, l, c, o), this.drawParticleField(t, e, i, s, l, h, r, o);
2446
+ const x = t.createRadialGradient(d, g, Math.min(e, i) * 0.28, d, g, b);
2558
2447
  x.addColorStop(0, "rgba(0, 0, 0, 0)"), x.addColorStop(1, o ? "rgba(40, 60, 90, 0.09)" : "rgba(0, 0, 0, 0.2)"), t.fillStyle = x, t.fillRect(0, 0, e, i);
2559
2448
  }
2560
- drawNebula(t, e, i, s, a, r, o) {
2561
- const n = t.createRadialGradient(e, i, 0, e, i, s), l = o ? 52 : 60;
2562
- n.addColorStop(0, `hsla(${a}, ${o ? 88 : 80}%, ${l}%, ${r})`), n.addColorStop(0.38, `hsla(${a}, ${o ? 82 : 75}%, ${l - (o ? 7 : 12)}%, ${r * 0.5})`), n.addColorStop(1, "rgba(0, 0, 0, 0)"), t.fillStyle = n, t.beginPath(), t.arc(e, i, s, 0, Math.PI * 2), t.fill();
2449
+ drawNebula(t, e, i, s, a, n, o) {
2450
+ const r = t.createRadialGradient(e, i, 0, e, i, s), c = o ? 52 : 60;
2451
+ r.addColorStop(0, `hsla(${a}, ${o ? 88 : 80}%, ${c}%, ${n})`), r.addColorStop(0.38, `hsla(${a}, ${o ? 82 : 75}%, ${c - (o ? 7 : 12)}%, ${n * 0.5})`), r.addColorStop(1, "rgba(0, 0, 0, 0)"), t.fillStyle = r, t.beginPath(), t.arc(e, i, s, 0, Math.PI * 2), t.fill();
2563
2452
  }
2564
- drawSoftFlows(t, e, i, s, a, r, o) {
2453
+ drawSoftFlows(t, e, i, s, a, n, o) {
2565
2454
  t.save();
2566
- const n = Math.min(e, i), l = n * 0.035;
2567
- t.globalAlpha = o ? 0.15 : 0.12, t.lineWidth = Math.max(1.3, n * 17e-4), t.lineCap = "round", t.shadowBlur = n * 0.02, t.shadowColor = `hsla(${a}, 85%, ${o ? 52 : 62}%, 0.28)`;
2568
- for (let h = 0; h < 3; h++) {
2569
- const c = (h - 1) * n * 0.075 + Math.sin(s * 0.06 + h) * l, p = h * 28 + r * 18;
2570
- t.strokeStyle = `hsla(${this.wrapHue(a + p)}, ${o ? 78 : 74}%, ${o ? 47 : 62}%, ${0.52 - h * 0.08})`, t.beginPath(), t.moveTo(-n * 0.12, i * 0.2 + c), t.bezierCurveTo(e * 0.2, i * 0.02 + c, e * 0.47, i * 0.2 - c, e * 0.73, i * 0.07 + c), t.bezierCurveTo(e * 0.94, -n * 0.02 + c, e * 1.04, i * 0.16 + c, e * 1.1, i * 0.36 + c), t.stroke(), t.beginPath(), t.moveTo(-n * 0.1, i * 0.8 - c), t.bezierCurveTo(e * 0.2, i * 0.98 - c, e * 0.48, i * 0.8 + c, e * 0.75, i * 0.93 - c), t.bezierCurveTo(e * 0.94, i * 1.02 - c, e * 1.04, i * 0.84 - c, e * 1.1, i * 0.65 - c), t.stroke();
2455
+ const r = Math.min(e, i), c = r * 0.035;
2456
+ t.globalAlpha = o ? 0.15 : 0.12, t.lineWidth = Math.max(1.3, r * 17e-4), t.lineCap = "round", t.shadowBlur = r * 0.02, t.shadowColor = `hsla(${a}, 85%, ${o ? 52 : 62}%, 0.28)`;
2457
+ for (let l = 0; l < 3; l++) {
2458
+ const h = (l - 1) * r * 0.075 + Math.sin(s * 0.06 + l) * c, u = l * 28 + n * 18;
2459
+ t.strokeStyle = `hsla(${this.wrapHue(a + u)}, ${o ? 78 : 74}%, ${o ? 47 : 62}%, ${0.52 - l * 0.08})`, t.beginPath(), t.moveTo(-r * 0.12, i * 0.2 + h), t.bezierCurveTo(e * 0.2, i * 0.02 + h, e * 0.47, i * 0.2 - h, e * 0.73, i * 0.07 + h), t.bezierCurveTo(e * 0.94, -r * 0.02 + h, e * 1.04, i * 0.16 + h, e * 1.1, i * 0.36 + h), t.stroke(), t.beginPath(), t.moveTo(-r * 0.1, i * 0.8 - h), t.bezierCurveTo(e * 0.2, i * 0.98 - h, e * 0.48, i * 0.8 + h, e * 0.75, i * 0.93 - h), t.bezierCurveTo(e * 0.94, i * 1.02 - h, e * 1.04, i * 0.84 - h, e * 1.1, i * 0.65 - h), t.stroke();
2571
2460
  }
2572
2461
  t.restore();
2573
2462
  }
2574
- drawParticleField(t, e, i, s, a, r, o, n) {
2575
- const l = 44 + Math.min(24, o * 2), h = e / 2, c = i / 2, p = Math.min(e, i) * 0.17;
2576
- for (let g = 0; g < l; g++) {
2577
- const _ = g + o * 17, m = this.unitNoise(_ * 1.7) * e, u = this.unitNoise(_ * 2.9 + 13) * i, d = Math.hypot(m - h, u - c), x = Math.min(1, Math.max(0, (d - p) / (Math.min(e, i) * 0.28))), y = 0.7 + Math.sin(s * (0.6 + g % 4 * 0.08) + _) * 0.3, E = (n ? 0.34 : 0.3) * x * y, I = 0.65 + g % 3 * 0.45;
2578
- t.fillStyle = `hsla(${g % 3 === 0 ? r : a}, ${n ? 82 : 78}%, ${n ? 40 : 70}%, ${E})`, t.beginPath(), t.arc(m, u, I, 0, Math.PI * 2), t.fill();
2463
+ drawParticleField(t, e, i, s, a, n, o, r) {
2464
+ const c = 44 + Math.min(24, o * 2), l = e / 2, h = i / 2, u = Math.min(e, i) * 0.17;
2465
+ for (let d = 0; d < c; d++) {
2466
+ const g = d + o * 17, b = this.unitNoise(g * 1.7) * e, f = this.unitNoise(g * 2.9 + 13) * i, _ = Math.hypot(b - l, f - h), x = Math.min(1, Math.max(0, (_ - u) / (Math.min(e, i) * 0.28))), y = 0.7 + Math.sin(s * (0.6 + d % 4 * 0.08) + g) * 0.3, m = (r ? 0.34 : 0.3) * x * y, v = 0.65 + d % 3 * 0.45;
2467
+ t.fillStyle = `hsla(${d % 3 === 0 ? n : a}, ${r ? 82 : 78}%, ${r ? 40 : 70}%, ${m})`, t.beginPath(), t.arc(b, f, v, 0, Math.PI * 2), t.fill();
2579
2468
  }
2580
2469
  }
2581
2470
  unitNoise(t) {
@@ -2585,50 +2474,64 @@ class gt {
2585
2474
  return (t % 360 + 360) % 360;
2586
2475
  }
2587
2476
  }
2588
- class _t {
2477
+ class Et {
2589
2478
  render(t, e, i) {
2590
2479
  if (!e.isActive) return;
2591
2480
  const s = e.getLauncher(), a = e.getTarget();
2592
2481
  if (!s || !a || !s.active || !a.active) return;
2593
- const r = e.getStep();
2594
- if (t.save(), r === 1) {
2595
- const o = Math.sin(i * 6) * 10, n = s.position.x, l = s.position.y - 65 + o;
2596
- t.shadowColor = f.core, t.shadowBlur = 20, t.fillStyle = f.core, t.beginPath(), t.moveTo(n, l + 20), t.lineTo(n - 16, l - 12), t.lineTo(n - 6, l - 12), t.lineTo(n - 6, l - 32), t.lineTo(n + 6, l - 32), t.lineTo(n + 6, l - 12), t.lineTo(n + 16, l - 12), t.closePath(), t.fill();
2597
- const h = s.radius * (1.6 + Math.sin(i * 8) * 0.3);
2598
- t.strokeStyle = "rgba(0, 240, 255, 0.8)", t.lineWidth = 3, t.beginPath(), t.arc(s.position.x, s.position.y, h, 0, Math.PI * 2), t.stroke();
2599
- } else if (r === 2) {
2600
- const o = a.position.x - s.position.x, n = a.position.y - s.position.y;
2601
- if (Math.hypot(o, n) > 10) {
2602
- const h = Math.atan2(n, o);
2603
- t.shadowColor = f.coreAccent, t.shadowBlur = 22, t.strokeStyle = f.coreAccent, t.lineWidth = 4, t.setLineDash([12, 8]), t.beginPath(), t.moveTo(s.position.x, s.position.y), t.lineTo(a.position.x, a.position.y), t.stroke(), t.setLineDash([]);
2604
- const c = a.position.x - Math.cos(h) * (a.radius + 10), p = a.position.y - Math.sin(h) * (a.radius + 10);
2605
- t.fillStyle = f.coreAccent, t.beginPath(), t.moveTo(c, p), t.lineTo(c - Math.cos(h - 0.4) * 24, p - Math.sin(h - 0.4) * 24), t.lineTo(c - Math.cos(h + 0.4) * 24, p - Math.sin(h + 0.4) * 24), t.closePath(), t.fill();
2606
- const g = a.radius * (1.8 + Math.cos(i * 10) * 0.3);
2607
- t.strokeStyle = "rgba(255, 0, 221, 0.9)", t.lineWidth = 3.5, t.beginPath(), t.arc(a.position.x, a.position.y, g, 0, Math.PI * 2), t.stroke();
2482
+ const n = e.getStep();
2483
+ if (t.save(), n === 1) {
2484
+ const o = Math.sin(i * 6) * 10, r = s.position.x, c = s.position.y - 65 + o;
2485
+ t.shadowColor = E.core, t.shadowBlur = 20, t.fillStyle = E.core, t.beginPath(), t.moveTo(r, c + 20), t.lineTo(r - 16, c - 12), t.lineTo(r - 6, c - 12), t.lineTo(r - 6, c - 32), t.lineTo(r + 6, c - 32), t.lineTo(r + 6, c - 12), t.lineTo(r + 16, c - 12), t.closePath(), t.fill();
2486
+ const l = s.radius * (1.6 + Math.sin(i * 8) * 0.3);
2487
+ t.strokeStyle = "rgba(0, 240, 255, 0.8)", t.lineWidth = 3, t.beginPath(), t.arc(s.position.x, s.position.y, l, 0, Math.PI * 2), t.stroke();
2488
+ } else if (n === 2) {
2489
+ const o = a.position.x - s.position.x, r = a.position.y - s.position.y;
2490
+ if (Math.hypot(o, r) > 10) {
2491
+ const l = Math.atan2(r, o);
2492
+ t.shadowColor = E.coreAccent, t.shadowBlur = 22, t.strokeStyle = E.coreAccent, t.lineWidth = 4, t.setLineDash([12, 8]), t.beginPath(), t.moveTo(s.position.x, s.position.y), t.lineTo(a.position.x, a.position.y), t.stroke(), t.setLineDash([]);
2493
+ const h = a.position.x - Math.cos(l) * (a.radius + 10), u = a.position.y - Math.sin(l) * (a.radius + 10);
2494
+ t.fillStyle = E.coreAccent, t.beginPath(), t.moveTo(h, u), t.lineTo(h - Math.cos(l - 0.4) * 24, u - Math.sin(l - 0.4) * 24), t.lineTo(h - Math.cos(l + 0.4) * 24, u - Math.sin(l + 0.4) * 24), t.closePath(), t.fill();
2495
+ const d = a.radius * (1.8 + Math.cos(i * 10) * 0.3);
2496
+ t.strokeStyle = "rgba(255, 0, 221, 0.9)", t.lineWidth = 3.5, t.beginPath(), t.arc(a.position.x, a.position.y, d, 0, Math.PI * 2), t.stroke();
2608
2497
  }
2609
2498
  }
2610
2499
  t.restore();
2611
2500
  }
2612
2501
  }
2613
- class mt {
2502
+ class vt {
2503
+ constructor(t) {
2504
+ this.configManager = t;
2505
+ }
2614
2506
  draw(t, e, i, s, a) {
2615
- t.shadowColor = a, t.shadowBlur = 16, t.fillStyle = a, e.type === "piercer" ? this.drawPiercer(t, e, i, s) : e.type === "spore" ? this.drawSpore(t, e, i, s) : e.type === "cluster" ? this.drawCluster(t, e, i) : e.type === "parasite" ? this.drawParasite(t, e, i, s) : e.type === "heavy" ? this.drawHeavy(t, e, i, s) : (t.beginPath(), t.arc(0, 0, e.radius, 0, Math.PI * 2), t.fill());
2507
+ t.shadowColor = a, t.shadowBlur = 16, t.fillStyle = a, (this.renderers[e.behavior.rendererId] ?? this.drawCircle)(t, e, i, s);
2508
+ }
2509
+ renderers = {
2510
+ piercer: (t, e, i, s) => this.drawPiercer(t, e, i, s),
2511
+ spore: (t, e, i, s) => this.drawSpore(t, e, i, s),
2512
+ cluster: (t, e, i) => this.drawCluster(t, e, i),
2513
+ parasite: (t, e, i, s) => this.drawParasite(t, e, i, s),
2514
+ heavy: (t, e, i, s) => this.drawHeavy(t, e, i, s),
2515
+ circle: (t, e) => this.drawCircle(t, e)
2516
+ };
2517
+ drawCircle(t, e) {
2518
+ t.beginPath(), t.arc(0, 0, e.radius, 0, Math.PI * 2), t.fill();
2616
2519
  }
2617
2520
  drawPiercer(t, e, i, s) {
2618
2521
  t.rotate(e.rotation), t.beginPath();
2619
2522
  const a = 12;
2620
- for (let r = 0; r <= a; r++) {
2621
- const o = r * Math.PI * 2 / a, n = e.radius * 1.6 + Math.sin(o * 3 + i * 4) * 3, l = e.radius * 0.6 + Math.cos(o * 2 + i * 3) * 2, h = Math.cos(o) * n, c = Math.sin(o) * l;
2622
- r === 0 ? t.moveTo(h, c) : t.lineTo(h, c);
2523
+ for (let n = 0; n <= a; n++) {
2524
+ const o = n * Math.PI * 2 / a, r = e.radius * 1.6 + Math.sin(o * 3 + i * 4) * 3, c = e.radius * 0.6 + Math.cos(o * 2 + i * 3) * 2, l = Math.cos(o) * r, h = Math.sin(o) * c;
2525
+ n === 0 ? t.moveTo(l, h) : t.lineTo(l, h);
2623
2526
  }
2624
2527
  t.closePath(), t.fill(), t.fillStyle = s.effectHighlight, t.beginPath(), t.arc(4, 0, 4, 0, Math.PI * 2), t.fill();
2625
2528
  }
2626
2529
  drawSpore(t, e, i, s) {
2627
2530
  t.beginPath();
2628
2531
  const a = 8;
2629
- for (let r = 0; r < a; r++) {
2630
- const o = r * Math.PI * 2 / a, n = e.radius + Math.sin(o * 4 + i * 3 + e.position.x) * 4, l = Math.cos(o) * n, h = Math.sin(o) * n;
2631
- r === 0 ? t.moveTo(l, h) : t.lineTo(l, h);
2532
+ for (let n = 0; n < a; n++) {
2533
+ const o = n * Math.PI * 2 / a, r = e.radius + Math.sin(o * 4 + i * 3 + e.position.x) * 4, c = Math.cos(o) * r, l = Math.sin(o) * r;
2534
+ n === 0 ? t.moveTo(c, l) : t.lineTo(c, l);
2632
2535
  }
2633
2536
  t.closePath(), t.fill(), t.fillStyle = s.effectHighlight, t.beginPath(), t.arc(-4, -4, 5, 0, Math.PI * 2), t.arc(5, 3, 4, 0, Math.PI * 2), t.fill();
2634
2537
  }
@@ -2640,95 +2543,99 @@ class mt {
2640
2543
  drawParasite(t, e, i, s) {
2641
2544
  t.beginPath();
2642
2545
  const a = 14;
2643
- for (let r = 0; r <= a; r++) {
2644
- const o = r * Math.PI * 2 / a, n = e.radius + Math.sin(o * 5 - i * 5) * 3, l = Math.cos(o) * n, h = Math.sin(o) * n;
2645
- r === 0 ? t.moveTo(l, h) : t.lineTo(l, h);
2546
+ for (let n = 0; n <= a; n++) {
2547
+ const o = n * Math.PI * 2 / a, r = e.radius + Math.sin(o * 5 - i * 5) * 3, c = Math.cos(o) * r, l = Math.sin(o) * r;
2548
+ n === 0 ? t.moveTo(c, l) : t.lineTo(c, l);
2646
2549
  }
2647
2550
  t.closePath(), t.fill(), t.fillStyle = s.bgOuter, t.beginPath(), t.arc(0, 0, e.radius * 0.45, 0, Math.PI * 2), t.fill();
2648
2551
  }
2649
2552
  drawHeavy(t, e, i, s) {
2650
2553
  t.rotate(e.rotation);
2651
- const a = e.radius, r = a * 0.88, o = Math.sin(i * 3 + e.position.x * 0.01) * 1.5, n = f.heavy;
2652
- t.save(), t.translate(-a * 0.12, o), t.fillStyle = n, t.shadowColor = n, t.shadowBlur = 20, t.beginPath();
2653
- const l = 10;
2654
- for (let u = 0; u <= l; u++) {
2655
- const d = u * Math.PI * 2 / l, x = 1 + Math.sin(d * 3 + i * 2.4) * 0.08, y = Math.cos(d) * r * x, E = Math.sin(d) * r * x * 0.9;
2656
- u === 0 ? t.moveTo(y, E) : t.lineTo(y, E);
2554
+ const a = e.radius, n = a * 0.88, o = Math.sin(i * 3 + e.position.x * 0.01) * 1.5, r = e.color;
2555
+ t.save(), t.translate(-a * 0.12, o), t.fillStyle = r, t.shadowColor = r, t.shadowBlur = 20, t.beginPath();
2556
+ const c = 10;
2557
+ for (let f = 0; f <= c; f++) {
2558
+ const _ = f * Math.PI * 2 / c, x = 1 + Math.sin(_ * 3 + i * 2.4) * 0.08, y = Math.cos(_) * n * x, m = Math.sin(_) * n * x * 0.9;
2559
+ f === 0 ? t.moveTo(y, m) : t.lineTo(y, m);
2657
2560
  }
2658
- t.closePath(), t.fill(), t.fillStyle = f.shieldEye, t.shadowColor = f.shieldEye, t.shadowBlur = 7, t.beginPath(), t.arc(-a * 0.28, -a * 0.2, a * 0.11, 0, Math.PI * 2), t.arc(a * 0.02, a * 0.18, a * 0.08, 0, Math.PI * 2), t.fill(), t.restore();
2659
- const h = a * 0.22, c = v.getInstance().getConfig().shield.protectionArc, p = a * 0.72, g = a * 0.38;
2660
- t.save(), t.translate(h, 0), t.beginPath(), t.arc(0, 0, p, -c / 2, c / 2, !1);
2661
- const _ = Math.cos(c / 2) * g, m = Math.sin(c / 2) * g;
2662
- t.lineTo(_, m), t.arc(0, 0, g, c / 2, -c / 2, !0), t.closePath(), t.fillStyle = f.heavy, t.shadowColor = f.heavy, t.shadowBlur = e.isStationaryShield ? 28 : 16, t.fill(), t.strokeStyle = s.effectHighlight, t.lineWidth = 2.5, t.beginPath(), t.arc(0, 0, p + Math.sin(i * 4) * 2, -c / 2 + 0.1, c / 2 - 0.1), t.stroke(), t.strokeStyle = f.heavyAccent, t.lineWidth = 1.5, t.shadowColor = f.heavyAccent, t.shadowBlur = 8, t.beginPath(), t.arc(0, 0, g * 0.72, -c * 0.42, c * 0.42), t.stroke();
2663
- for (let u = -2; u <= 2; u++) {
2664
- const d = u * c / 6, x = Math.cos(d) * (g + 6), y = Math.sin(d) * (g + 6);
2561
+ t.closePath(), t.fill(), t.fillStyle = s.effectHighlight, t.shadowColor = s.effectHighlight, t.shadowBlur = 7, t.beginPath(), t.arc(-a * 0.28, -a * 0.2, a * 0.11, 0, Math.PI * 2), t.arc(a * 0.02, a * 0.18, a * 0.08, 0, Math.PI * 2), t.fill(), t.restore();
2562
+ const l = a * 0.22, h = this.configManager.getConfig().shield.protectionArc, u = a * 0.72, d = a * 0.38;
2563
+ t.save(), t.translate(l, 0), t.beginPath(), t.arc(0, 0, u, -h / 2, h / 2, !1);
2564
+ const g = Math.cos(h / 2) * d, b = Math.sin(h / 2) * d;
2565
+ t.lineTo(g, b), t.arc(0, 0, d, h / 2, -h / 2, !0), t.closePath(), t.fillStyle = e.color, t.shadowColor = e.color, t.shadowBlur = e.isStationaryShield ? 28 : 16, t.fill(), t.strokeStyle = s.effectHighlight, t.lineWidth = 2.5, t.beginPath(), t.arc(0, 0, u + Math.sin(i * 4) * 2, -h / 2 + 0.1, h / 2 - 0.1), t.stroke(), t.strokeStyle = s.effectHighlight, t.lineWidth = 1.5, t.shadowColor = s.effectHighlight, t.shadowBlur = 8, t.beginPath(), t.arc(0, 0, d * 0.72, -h * 0.42, h * 0.42), t.stroke();
2566
+ for (let f = -2; f <= 2; f++) {
2567
+ const _ = f * h / 6, x = Math.cos(_) * (d + 6), y = Math.sin(_) * (d + 6);
2665
2568
  t.fillStyle = s.effectHighlight, t.beginPath(), t.arc(x, y, 3, 0, Math.PI * 2), t.fill();
2666
2569
  }
2667
2570
  t.restore();
2668
2571
  }
2669
2572
  }
2670
- const ft = {
2671
- common: f.spore,
2672
- rare: f.parasite,
2673
- epic: f.cluster,
2674
- legendary: f.core
2573
+ const At = {
2574
+ common: E.spore,
2575
+ rare: E.parasite,
2576
+ epic: E.cluster,
2577
+ legendary: E.core
2675
2578
  };
2676
- class xt {
2579
+ class Mt {
2677
2580
  canvas;
2678
2581
  ctx;
2679
2582
  themeManager;
2583
+ configManager;
2680
2584
  indicatorRenderer;
2681
2585
  bgRenderer;
2682
2586
  tutorialArrowRenderer;
2683
2587
  enemyShapeRenderer;
2684
- constructor(t, e) {
2685
- this.canvas = t, this.ctx = t.getContext("2d"), this.themeManager = e, this.indicatorRenderer = new dt(), this.bgRenderer = new gt(), this.tutorialArrowRenderer = new _t(), this.enemyShapeRenderer = new mt();
2588
+ constructor(t, e, i) {
2589
+ this.canvas = t, this.ctx = t.getContext("2d"), this.themeManager = e, this.indicatorRenderer = new xt(), this.bgRenderer = new bt(), this.tutorialArrowRenderer = new Et(), this.enemyShapeRenderer = new vt(i), this.configManager = i;
2686
2590
  }
2687
- render(t, e, i, s, a, r, o, n, l, h, c, p = 1, g) {
2591
+ render(t, e, i, s, a, n, o, r, c, l, h, u = 1, d = 0, g = 0, b) {
2688
2592
  if (!this.ctx) return;
2689
- const _ = this.themeManager.getPalette(), { width: m, height: u } = this.canvas, d = l.getShakeOffset();
2690
- this.ctx.save(), this.ctx.translate(d.x, d.y), this.bgRenderer.render(
2593
+ const f = this.themeManager.getPalette(), { width: _, height: x } = this.canvas, y = c.getShakeOffset();
2594
+ this.ctx.save(), this.ctx.translate(y.x, y.y), this.bgRenderer.render(
2691
2595
  this.ctx,
2692
- m,
2693
- u,
2694
- t.pulsePhase,
2695
- p,
2696
2596
  _,
2597
+ x,
2598
+ t.pulsePhase,
2599
+ u,
2600
+ f,
2697
2601
  this.themeManager.getTheme() === "light"
2698
- ), this.drawExperienceOrbs(i, t.position, t.pulsePhase, _), this.drawToxicPools(s, t.pulsePhase), this.drawGravityVortices(a, t.pulsePhase), this.drawShockwaves(r), this.drawCoreFilaments(t, _), this.drawParticles(o), v.getInstance().getConfig().core.hasOffscreenIndicators && this.indicatorRenderer.render(this.ctx, e, m, u, _), this.drawOrganicEnemies(e, t.pulsePhase, _), g && this.tutorialArrowRenderer.render(this.ctx, g, t.pulsePhase), h ? this.drawPsionicTendril(t.position, h.position, _) : t && this.drawHoverTendril(t.position, c, e, _), this.drawOrganicConsciousnessCore(t, _), this.drawFloatingTexts(n), l.flashAlpha > 0 && (this.ctx.fillStyle = `rgba(255, 255, 255, ${l.flashAlpha})`, this.ctx.fillRect(0, 0, m, u)), this.ctx.restore();
2602
+ ), this.drawExperienceOrbs(i, t.position, t.pulsePhase, f), this.drawToxicPools(s, t.pulsePhase), this.drawGravityVortices(a, t.pulsePhase), this.drawShockwaves(n), this.drawCoreFilaments(t, f), this.drawAutoDeflectionBeams(t.position, e, t.pulsePhase, f), this.drawParticles(o), this.configManager.getConfig().core.hasOffscreenIndicators && this.indicatorRenderer.render(this.ctx, e, _, x, f), this.drawOrganicEnemies(e, t.pulsePhase, f), b && this.tutorialArrowRenderer.render(this.ctx, b, t.pulsePhase), l ? this.drawPsionicTendril(t.position, l.position, f) : t && this.drawHoverTendril(t.position, h, e, f), this.drawOrganicConsciousnessCore(t, f, d, g), this.drawFloatingTexts(r), c.flashAlpha > 0 && (this.ctx.fillStyle = `rgba(255, 255, 255, ${c.flashAlpha})`, this.ctx.fillRect(0, 0, _, x)), this.ctx.restore();
2699
2603
  }
2700
2604
  drawExperienceOrbs(t, e, i, s) {
2701
2605
  if (this.ctx)
2702
2606
  for (const a of t) {
2703
2607
  if (!a.active) continue;
2704
- const r = a.radius + Math.sin(i * 7 + a.position.x * 0.01) * 0.8, { x: o, y: n } = a.position;
2705
- this.ctx.save(), this.ctx.shadowColor = s.corePrimary, this.ctx.shadowBlur = a.isAbsorbing ? 18 : 10, a.isAbsorbing && (this.ctx.globalAlpha = 0.35, this.ctx.strokeStyle = s.tendrilCyan, this.ctx.lineWidth = 1, this.ctx.setLineDash([4, 7]), this.ctx.beginPath(), this.ctx.moveTo(o, n), this.ctx.lineTo(e.x, e.y), this.ctx.stroke(), this.ctx.setLineDash([]), this.ctx.globalAlpha = 1);
2706
- const l = this.ctx.createRadialGradient(o - 1, n - 1, 1, o, n, r * 1.6);
2707
- l.addColorStop(0, s.effectHighlight), l.addColorStop(0.4, s.corePrimary), l.addColorStop(1, "rgba(0, 0, 0, 0)"), this.ctx.fillStyle = l, this.ctx.beginPath(), this.ctx.arc(o, n, r * 1.6, 0, Math.PI * 2), this.ctx.fill(), this.ctx.fillStyle = s.effectHighlight, this.ctx.beginPath(), this.ctx.arc(o, n, r * 0.65, 0, Math.PI * 2), this.ctx.fill(), this.ctx.strokeStyle = s.tendrilCyan, this.ctx.lineWidth = 1, this.ctx.beginPath(), this.ctx.arc(o, n, r + 3, -i * 2, -i * 2 + Math.PI * 1.4), this.ctx.stroke(), this.ctx.restore();
2608
+ const n = Math.max(
2609
+ 1,
2610
+ a.radius * a.visualScale + Math.sin(i * 7 + a.position.x * 0.01) * (0.8 + a.mergePulse * 1.2)
2611
+ ), { x: o, y: r } = a.position;
2612
+ this.ctx.save(), this.ctx.shadowColor = a.color, this.ctx.shadowBlur = a.isAbsorbing ? 18 : Math.min(24, 8 + a.radius * 0.45 + a.mergePulse * 10), a.isAbsorbing && (this.ctx.globalAlpha = 0.35, this.ctx.strokeStyle = s.tendrilCyan, this.ctx.lineWidth = 1, this.ctx.setLineDash([4, 7]), this.ctx.beginPath(), this.ctx.moveTo(o, r), this.ctx.lineTo(e.x, e.y), this.ctx.stroke(), this.ctx.setLineDash([]), this.ctx.globalAlpha = 1);
2613
+ const c = this.ctx.createRadialGradient(o - 1, r - 1, 1, o, r, n * 1.6);
2614
+ c.addColorStop(0, s.effectHighlight), c.addColorStop(0.4, a.color), c.addColorStop(1, "rgba(0, 0, 0, 0)"), this.ctx.fillStyle = c, this.ctx.beginPath(), this.ctx.arc(o, r, n * 1.6, 0, Math.PI * 2), this.ctx.fill(), this.ctx.fillStyle = s.effectHighlight, this.ctx.beginPath(), this.ctx.arc(o, r, n * 0.65, 0, Math.PI * 2), this.ctx.fill(), this.ctx.strokeStyle = a.color, this.ctx.lineWidth = Math.min(3, 1 + a.radius * 0.08), this.ctx.beginPath(), this.ctx.arc(o, r, n + 3, -i * 2, -i * 2 + Math.PI * 1.4), this.ctx.stroke(), this.ctx.restore();
2708
2615
  }
2709
2616
  }
2710
2617
  drawToxicPools(t, e) {
2711
2618
  if (!this.ctx) return;
2712
2619
  const i = this.themeManager.getPalette();
2713
2620
  for (const s of t) {
2714
- const a = s.duration / s.maxDuration, r = Math.min(0.7, (1 - a) * 0.7), { x: o, y: n } = s.position;
2621
+ const a = s.duration / s.maxDuration, n = Math.min(0.7, (1 - a) * 0.7), { x: o, y: r } = s.position;
2715
2622
  this.ctx.save();
2716
- const l = this.ctx.createRadialGradient(o, n, 10, o, n, s.radius * 1.2);
2717
- l.addColorStop(0, this.colorWithAlpha(i.sporeColor, r * 0.9)), l.addColorStop(0.4, `rgba(16, 185, 129, ${r * 0.65})`), l.addColorStop(0.8, `rgba(5, 80, 45, ${r * 0.35})`), l.addColorStop(1, "rgba(2, 35, 15, 0)"), this.ctx.fillStyle = l, this.ctx.shadowColor = i.sporeColor, this.ctx.shadowBlur = 30, this.ctx.beginPath();
2718
- const h = 70;
2719
- for (let c = 0; c <= h; c++) {
2720
- const p = c * Math.PI * 2 / h, g = Math.sin(p * 5 + e * 3) * 14, _ = Math.cos(p * 3 - e * 2) * 9, m = s.radius + g + _, u = o + Math.cos(p) * m, d = n + Math.sin(p) * m;
2721
- c === 0 ? this.ctx.moveTo(u, d) : this.ctx.lineTo(u, d);
2623
+ const c = this.ctx.createRadialGradient(o, r, 10, o, r, s.radius * 1.2);
2624
+ c.addColorStop(0, this.colorWithAlpha(i.sporeColor, n * 0.9)), c.addColorStop(0.4, `rgba(16, 185, 129, ${n * 0.65})`), c.addColorStop(0.8, `rgba(5, 80, 45, ${n * 0.35})`), c.addColorStop(1, "rgba(2, 35, 15, 0)"), this.ctx.fillStyle = c, this.ctx.shadowColor = i.sporeColor, this.ctx.shadowBlur = 30, this.ctx.beginPath();
2625
+ const l = 70;
2626
+ for (let h = 0; h <= l; h++) {
2627
+ const u = h * Math.PI * 2 / l, d = Math.sin(u * 5 + e * 3) * 14, g = Math.cos(u * 3 - e * 2) * 9, b = s.radius + d + g, f = o + Math.cos(u) * b, _ = r + Math.sin(u) * b;
2628
+ h === 0 ? this.ctx.moveTo(f, _) : this.ctx.lineTo(f, _);
2722
2629
  }
2723
- this.ctx.closePath(), this.ctx.fill(), this.ctx.strokeStyle = this.colorWithAlpha(i.sporeColor, r * 0.8), this.ctx.lineWidth = 2.5, this.ctx.beginPath();
2724
- for (let c = 0; c <= h; c++) {
2725
- const p = c * Math.PI * 2 / h, g = Math.sin(p * 6 + e * 4) * 8, _ = s.radius * 0.75 + g, m = o + Math.cos(p) * _, u = n + Math.sin(p) * _;
2726
- c === 0 ? this.ctx.moveTo(m, u) : this.ctx.lineTo(m, u);
2630
+ this.ctx.closePath(), this.ctx.fill(), this.ctx.strokeStyle = this.colorWithAlpha(i.sporeColor, n * 0.8), this.ctx.lineWidth = 2.5, this.ctx.beginPath();
2631
+ for (let h = 0; h <= l; h++) {
2632
+ const u = h * Math.PI * 2 / l, d = Math.sin(u * 6 + e * 4) * 8, g = s.radius * 0.75 + d, b = o + Math.cos(u) * g, f = r + Math.sin(u) * g;
2633
+ h === 0 ? this.ctx.moveTo(b, f) : this.ctx.lineTo(b, f);
2727
2634
  }
2728
2635
  this.ctx.closePath(), this.ctx.stroke();
2729
- for (let c = 0; c < 6; c++) {
2730
- const p = c * Math.PI * 0.33 + e * 1.5, g = s.radius * 0.5 * (0.3 + Math.sin(e * 2 + c) * 0.3), _ = o + Math.cos(p) * g, m = n + Math.sin(p) * g, u = 3 + Math.sin(e * 3 + c) * 2;
2731
- this.ctx.fillStyle = `rgba(255, 255, 255, ${r * 0.8})`, this.ctx.beginPath(), this.ctx.arc(_, m, Math.max(1, u), 0, Math.PI * 2), this.ctx.fill();
2636
+ for (let h = 0; h < 6; h++) {
2637
+ const u = h * Math.PI * 0.33 + e * 1.5, d = s.radius * 0.5 * (0.3 + Math.sin(e * 2 + h) * 0.3), g = o + Math.cos(u) * d, b = r + Math.sin(u) * d, f = 3 + Math.sin(e * 3 + h) * 2;
2638
+ this.ctx.fillStyle = `rgba(255, 255, 255, ${n * 0.8})`, this.ctx.beginPath(), this.ctx.arc(g, b, Math.max(1, f), 0, Math.PI * 2), this.ctx.fill();
2732
2639
  }
2733
2640
  this.ctx.restore();
2734
2641
  }
@@ -2755,13 +2662,13 @@ class xt {
2755
2662
  if (!this.ctx) return;
2756
2663
  const i = this.themeManager.getPalette();
2757
2664
  for (const s of t) {
2758
- const a = Math.min(0.85, (1 - s.duration / s.maxDuration) * 0.85), r = s.radius * (1 - s.duration / s.maxDuration * 0.1), { x: o, y: n } = s.position;
2665
+ const a = Math.min(0.85, (1 - s.duration / s.maxDuration) * 0.85), n = s.radius * (1 - s.duration / s.maxDuration * 0.1), { x: o, y: r } = s.position;
2759
2666
  this.ctx.save();
2760
- const l = this.ctx.createRadialGradient(o, n, 0, o, n, 60);
2761
- l.addColorStop(0, this.colorWithAlpha(i.vortexCore, a)), l.addColorStop(0.7, this.colorWithAlpha(i.vortexMid, a)), l.addColorStop(1, this.colorWithAlpha(i.parasiteColor, a * 0.5)), this.ctx.fillStyle = l, this.ctx.beginPath(), this.ctx.arc(o, n, 60, 0, Math.PI * 2), this.ctx.fill(), this.ctx.strokeStyle = i.parasiteColor, this.ctx.lineWidth = 5, this.ctx.shadowColor = i.parasiteColor, this.ctx.shadowBlur = 32;
2762
- for (let h = 1; h <= 5; h++) {
2763
- const c = r * h / 5, p = e * h * 2.2;
2764
- this.ctx.beginPath(), this.ctx.arc(o, n, c, p, p + Math.PI * 1.5), this.ctx.stroke();
2667
+ const c = this.ctx.createRadialGradient(o, r, 0, o, r, 60);
2668
+ c.addColorStop(0, this.colorWithAlpha(i.vortexCore, a)), c.addColorStop(0.7, this.colorWithAlpha(i.vortexMid, a)), c.addColorStop(1, this.colorWithAlpha(i.parasiteColor, a * 0.5)), this.ctx.fillStyle = c, this.ctx.beginPath(), this.ctx.arc(o, r, 60, 0, Math.PI * 2), this.ctx.fill(), this.ctx.strokeStyle = i.parasiteColor, this.ctx.lineWidth = 5, this.ctx.shadowColor = i.parasiteColor, this.ctx.shadowBlur = 32;
2669
+ for (let l = 1; l <= 5; l++) {
2670
+ const h = n * l / 5, u = e * l * 2.2;
2671
+ this.ctx.beginPath(), this.ctx.arc(o, r, h, u, u + Math.PI * 1.5), this.ctx.stroke();
2765
2672
  }
2766
2673
  this.ctx.restore();
2767
2674
  }
@@ -2770,10 +2677,10 @@ class xt {
2770
2677
  if (!this.ctx) return;
2771
2678
  const a = this.ctx.createRadialGradient(t / 2, e / 2, 40, t / 2, e / 2, Math.max(t, e));
2772
2679
  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, e);
2773
- const r = t * 0.35 + Math.sin(i * 0.3) * 60, o = e * 0.45 + Math.cos(i * 0.25) * 50, n = this.ctx.createRadialGradient(r, o, 20, r, o, 380);
2774
- n.addColorStop(0, s.nebulaCyan), n.addColorStop(1, "rgba(0, 0, 0, 0)"), this.ctx.fillStyle = n, this.ctx.beginPath(), this.ctx.arc(r, o, 380, 0, Math.PI * 2), this.ctx.fill();
2775
- const l = t * 0.68 + Math.cos(i * 0.35) * 50, h = e * 0.55 + Math.sin(i * 0.3) * 45, c = this.ctx.createRadialGradient(l, h, 20, l, h, 420);
2776
- c.addColorStop(0, s.nebulaMagenta), c.addColorStop(1, "rgba(0, 0, 0, 0)"), this.ctx.fillStyle = c, this.ctx.beginPath(), this.ctx.arc(l, h, 420, 0, Math.PI * 2), this.ctx.fill();
2680
+ const n = t * 0.35 + Math.sin(i * 0.3) * 60, o = e * 0.45 + Math.cos(i * 0.25) * 50, r = this.ctx.createRadialGradient(n, o, 20, n, o, 380);
2681
+ r.addColorStop(0, s.nebulaCyan), r.addColorStop(1, "rgba(0, 0, 0, 0)"), this.ctx.fillStyle = r, this.ctx.beginPath(), this.ctx.arc(n, o, 380, 0, Math.PI * 2), this.ctx.fill();
2682
+ const c = t * 0.68 + Math.cos(i * 0.35) * 50, l = e * 0.55 + Math.sin(i * 0.3) * 45, h = this.ctx.createRadialGradient(c, l, 20, c, l, 420);
2683
+ h.addColorStop(0, s.nebulaMagenta), h.addColorStop(1, "rgba(0, 0, 0, 0)"), this.ctx.fillStyle = h, this.ctx.beginPath(), this.ctx.arc(c, l, 420, 0, Math.PI * 2), this.ctx.fill();
2777
2684
  }
2778
2685
  drawCoreFilaments(t, e) {
2779
2686
  if (!this.ctx) return;
@@ -2782,68 +2689,93 @@ class xt {
2782
2689
  for (let s = 0; s < i; s++) {
2783
2690
  const a = t.collectedPowerUpColors[s] || e.nebulaCyan;
2784
2691
  this.ctx.strokeStyle = a;
2785
- const r = s * Math.PI * 2 / i + t.pulsePhase * 0.12, o = 85 + Math.sin(t.pulsePhase * 1.5 + s) * 25, n = t.position.x + Math.cos(r) * o, l = t.position.y + Math.sin(r) * o, h = t.position.x + Math.cos(r + 0.4) * 48, c = t.position.y + Math.sin(r + 0.4) * 48;
2786
- this.ctx.beginPath(), this.ctx.moveTo(t.position.x, t.position.y), this.ctx.quadraticCurveTo(h, c, n, l), this.ctx.stroke(), this.ctx.fillStyle = a, this.ctx.beginPath(), this.ctx.arc(n, l, 3.5, 0, Math.PI * 2), this.ctx.fill();
2692
+ const n = s * Math.PI * 2 / i + t.pulsePhase * 0.12, o = 85 + Math.sin(t.pulsePhase * 1.5 + s) * 25, r = t.position.x + Math.cos(n) * o, c = t.position.y + Math.sin(n) * o, l = t.position.x + Math.cos(n + 0.4) * 48, h = t.position.y + Math.sin(n + 0.4) * 48;
2693
+ this.ctx.beginPath(), this.ctx.moveTo(t.position.x, t.position.y), this.ctx.quadraticCurveTo(l, h, r, c), this.ctx.stroke(), this.ctx.fillStyle = a, this.ctx.beginPath(), this.ctx.arc(r, c, 3.5, 0, Math.PI * 2), this.ctx.fill();
2787
2694
  }
2788
2695
  }
2789
- drawOrganicConsciousnessCore(t, e) {
2696
+ drawAutoDeflectionBeams(t, e, i, s) {
2697
+ if (this.ctx)
2698
+ for (const a of e) {
2699
+ if (!a.active || a.psionicDeflectionTimer <= 0) continue;
2700
+ const n = Math.min(1, a.psionicDeflectionTimer / 0.24), o = a.position.x - t.x, r = a.position.y - t.y, c = Math.hypot(o, r);
2701
+ if (c <= 0) continue;
2702
+ const l = -r / c, h = o / c, u = Math.sin(i * 18 + a.position.x * 0.02) * 10, d = (t.x + a.position.x) / 2 + l * u, g = (t.y + a.position.y) / 2 + h * u;
2703
+ this.ctx.save(), this.ctx.globalAlpha = n, this.ctx.strokeStyle = s.tendrilMagenta, this.ctx.lineWidth = 6, this.ctx.shadowColor = s.tendrilMagenta, this.ctx.shadowBlur = 18, this.ctx.beginPath(), this.ctx.moveTo(t.x, t.y), this.ctx.quadraticCurveTo(d, g, a.position.x, a.position.y), this.ctx.stroke(), this.ctx.strokeStyle = s.effectHighlight, this.ctx.lineWidth = 1.8, this.ctx.shadowColor = s.tendrilCyan, this.ctx.shadowBlur = 10, this.ctx.beginPath(), this.ctx.moveTo(t.x, t.y), this.ctx.quadraticCurveTo(d, g, a.position.x, a.position.y), this.ctx.stroke(), this.ctx.restore();
2704
+ }
2705
+ }
2706
+ drawOrganicConsciousnessCore(t, e, i, s) {
2790
2707
  if (!this.ctx) return;
2791
- const { x: i, y: s } = t.position;
2708
+ const { x: a, y: n } = t.position;
2792
2709
  if (this.ctx.save(), t.invulnerabilityTimer > 0) {
2793
- const l = Math.floor(t.invulnerabilityTimer * 20) % 2 === 0;
2794
- this.ctx.globalAlpha = l ? 0.3 : 0.9;
2710
+ const x = Math.floor(t.invulnerabilityTimer * 20) % 2 === 0;
2711
+ this.ctx.globalAlpha = x ? 0.3 : 0.9;
2795
2712
  }
2796
- const a = t.getColorHex();
2797
- for (let l = 0; l < t.integrity; l++) {
2798
- const h = t.radius + 16 + l * 12;
2799
- this.ctx.strokeStyle = a, this.ctx.lineWidth = 2.2, this.ctx.shadowColor = a, this.ctx.shadowBlur = 12, this.ctx.beginPath();
2800
- const c = 60;
2801
- for (let p = 0; p <= c; p++) {
2802
- const g = p * Math.PI * 2 / c, _ = h + Math.sin(g * 4 + t.pulsePhase * 2 + l) * 3, m = i + Math.cos(g) * _, u = s + Math.sin(g) * _;
2803
- p === 0 ? this.ctx.moveTo(m, u) : this.ctx.lineTo(m, u);
2713
+ const o = t.getColorHex();
2714
+ for (let x = 0; x < t.integrity; x++) {
2715
+ const y = t.radius + 16 + x * 12;
2716
+ this.ctx.strokeStyle = o, this.ctx.lineWidth = 2.2, this.ctx.shadowColor = o, this.ctx.shadowBlur = 12, this.ctx.beginPath();
2717
+ const m = 60;
2718
+ for (let v = 0; v <= m; v++) {
2719
+ const A = v * Math.PI * 2 / m, S = y + Math.sin(A * 4 + t.pulsePhase * 2 + x) * 3, L = a + Math.cos(A) * S, T = n + Math.sin(A) * S;
2720
+ v === 0 ? this.ctx.moveTo(L, T) : this.ctx.lineTo(L, T);
2804
2721
  }
2805
2722
  this.ctx.closePath(), this.ctx.stroke();
2806
2723
  }
2807
2724
  if (t.repairProgress > 0) {
2808
- const l = t.integrity, h = t.radius + 16 + l * 12;
2809
- this.ctx.save(), this.ctx.globalAlpha = Math.max(0.15, t.repairProgress), this.ctx.strokeStyle = a, this.ctx.lineWidth = 2, this.ctx.shadowColor = a, this.ctx.shadowBlur = 8, this.ctx.setLineDash([6, 4]), this.ctx.beginPath();
2810
- const c = 60;
2811
- for (let p = 0; p <= c; p++) {
2812
- const g = p * Math.PI * 2 / c, _ = h + Math.sin(g * 4 + t.pulsePhase * 2 + l) * 3, m = i + Math.cos(g) * _, u = s + Math.sin(g) * _;
2813
- p === 0 ? this.ctx.moveTo(m, u) : this.ctx.lineTo(m, u);
2725
+ const x = t.integrity, y = t.radius + 16 + x * 12;
2726
+ this.ctx.save(), this.ctx.globalAlpha = Math.max(0.15, t.repairProgress), this.ctx.strokeStyle = o, this.ctx.lineWidth = 2, this.ctx.shadowColor = o, this.ctx.shadowBlur = 8, this.ctx.setLineDash([6, 4]), this.ctx.beginPath();
2727
+ const m = 60;
2728
+ for (let v = 0; v <= m; v++) {
2729
+ const A = v * Math.PI * 2 / m, S = y + Math.sin(A * 4 + t.pulsePhase * 2 + x) * 3, L = a + Math.cos(A) * S, T = n + Math.sin(A) * S;
2730
+ v === 0 ? this.ctx.moveTo(L, T) : this.ctx.lineTo(L, T);
2814
2731
  }
2815
2732
  this.ctx.closePath(), this.ctx.stroke(), this.ctx.restore();
2816
2733
  }
2817
- const r = this.ctx.createRadialGradient(i, s, 5, i, s, t.radius * 2.2);
2818
- r.addColorStop(0, a), r.addColorStop(0.5, e.nebulaMagenta), r.addColorStop(1, "rgba(0, 0, 0, 0)"), this.ctx.fillStyle = r, this.ctx.beginPath(), this.ctx.arc(i, s, t.radius * 2.2, 0, Math.PI * 2), this.ctx.fill(), this.ctx.save(), this.ctx.translate(i, s), this.ctx.strokeStyle = a, this.ctx.lineWidth = 3, this.ctx.fillStyle = a, this.ctx.shadowColor = a, this.ctx.shadowBlur = 20, this.ctx.beginPath();
2819
- const o = 80;
2820
- for (let l = 0; l <= o; l++) {
2821
- const h = l * Math.PI * 2 / o, c = t.getMembraneRadius(h), p = Math.cos(h) * c, g = Math.sin(h) * c;
2822
- l === 0 ? this.ctx.moveTo(p, g) : this.ctx.lineTo(p, g);
2734
+ const r = this.ctx.createRadialGradient(a, n, 5, a, n, t.radius * 2.2);
2735
+ r.addColorStop(0, o), r.addColorStop(0.5, e.nebulaMagenta), r.addColorStop(1, "rgba(0, 0, 0, 0)"), this.ctx.fillStyle = r, this.ctx.beginPath(), this.ctx.arc(a, n, t.radius * 2.2, 0, Math.PI * 2), this.ctx.fill(), this.ctx.save(), this.ctx.translate(a, n), this.ctx.strokeStyle = o, this.ctx.lineWidth = 3, this.ctx.fillStyle = o, this.ctx.shadowColor = o, this.ctx.shadowBlur = 20, this.ctx.beginPath();
2736
+ const c = 80;
2737
+ for (let x = 0; x <= c; x++) {
2738
+ const y = x * Math.PI * 2 / c, m = t.getMembraneRadius(y), v = Math.cos(y) * m, A = Math.sin(y) * m;
2739
+ x === 0 ? this.ctx.moveTo(v, A) : this.ctx.lineTo(v, A);
2823
2740
  }
2824
- this.ctx.closePath(), this.ctx.fill(), this.ctx.stroke();
2825
- const n = t.powerUpCount;
2826
- if (n > 0) {
2827
- this.ctx.strokeStyle = e.effectHighlight, this.ctx.lineWidth = 1.8, this.ctx.shadowColor = a, this.ctx.shadowBlur = 10;
2828
- for (let l = 0; l < n; l++) {
2829
- const h = l * Math.PI * 2 / n + t.pulsePhase * 0.4, c = t.radius * (0.45 + Math.sin(t.pulsePhase * 2 + l) * 0.15);
2741
+ this.ctx.closePath(), this.ctx.fillStyle = o, this.ctx.fill(), this.ctx.strokeStyle = o, this.ctx.lineWidth = 3, this.ctx.stroke();
2742
+ const l = t.powerUpCount;
2743
+ if (l > 0) {
2744
+ this.ctx.strokeStyle = e.effectHighlight, this.ctx.lineWidth = 1.8, this.ctx.shadowColor = o, this.ctx.shadowBlur = 10;
2745
+ for (let x = 0; x < l; x++) {
2746
+ const y = x * Math.PI * 2 / l + t.pulsePhase * 0.4, m = t.radius * (0.45 + Math.sin(t.pulsePhase * 2 + x) * 0.15);
2830
2747
  this.ctx.beginPath(), this.ctx.moveTo(0, 0);
2831
- const p = Math.cos(h + Math.sin(t.pulsePhase + l) * 0.4) * (c * 0.6), g = Math.sin(h + Math.cos(t.pulsePhase + l) * 0.4) * (c * 0.6), _ = Math.cos(h) * c, m = Math.sin(h) * c;
2832
- this.ctx.quadraticCurveTo(p, g, _, m), this.ctx.stroke(), this.ctx.fillStyle = a, this.ctx.beginPath(), this.ctx.arc(_, m, 2.5, 0, Math.PI * 2), this.ctx.fill();
2748
+ const v = Math.cos(y + Math.sin(t.pulsePhase + x) * 0.4) * (m * 0.6), A = Math.sin(y + Math.cos(t.pulsePhase + x) * 0.4) * (m * 0.6), S = Math.cos(y) * m, L = Math.sin(y) * m;
2749
+ this.ctx.quadraticCurveTo(v, A, S, L), this.ctx.stroke(), this.ctx.fillStyle = o, this.ctx.beginPath(), this.ctx.arc(S, L, 2.5, 0, Math.PI * 2), this.ctx.fill();
2833
2750
  }
2834
2751
  }
2835
- this.ctx.fillStyle = e.effectHighlight, this.ctx.beginPath(), this.ctx.arc(0, 0, t.radius * 0.3, 0, Math.PI * 2), this.ctx.fill(), this.ctx.restore(), this.ctx.restore();
2752
+ const h = Math.max(0, Math.min(1, i)), u = Math.max(0, Math.min(1, s)), g = t.radius * 0.42 * (1 + u * 0.1), b = g - h * g * 2, f = Math.sin(t.pulsePhase * 5) * 1.5, _ = this.ctx.createRadialGradient(0, -g * 0.35, 1, 0, 0, g);
2753
+ if (_.addColorStop(0, e.effectHighlight), _.addColorStop(0.7, this.colorWithAlpha(e.effectHighlight, 0.92)), _.addColorStop(1, this.colorWithAlpha(e.tendrilCyan, 0.55)), this.ctx.fillStyle = _, this.ctx.shadowColor = u > 0 ? o : e.effectHighlight, this.ctx.shadowBlur = 16 + u * 32, this.ctx.beginPath(), this.ctx.arc(0, 0, g, 0, Math.PI * 2), this.ctx.fill(), h > 0) {
2754
+ this.ctx.save(), this.ctx.beginPath(), this.ctx.arc(0, 0, g, 0, Math.PI * 2), this.ctx.clip();
2755
+ const x = this.ctx.createLinearGradient(0, b, 0, g);
2756
+ x.addColorStop(0, this.colorWithAlpha(o, 1)), x.addColorStop(0.7, this.colorWithAlpha(o, 0.9)), x.addColorStop(1, this.colorWithAlpha(e.nebulaMagenta, 0.78)), this.ctx.fillStyle = x, this.ctx.fillRect(-g, b, g * 2, g * 2), this.ctx.strokeStyle = e.effectHighlight, this.ctx.lineWidth = 2, this.ctx.shadowColor = o, this.ctx.shadowBlur = 10, this.ctx.beginPath(), this.ctx.moveTo(-g, b + f), this.ctx.quadraticCurveTo(0, b - 2 - f, g, b + f), this.ctx.stroke(), this.ctx.restore();
2757
+ }
2758
+ if (this.ctx.strokeStyle = this.colorWithAlpha(o, 0.8), this.ctx.lineWidth = 2.5, this.ctx.shadowColor = o, this.ctx.shadowBlur = 12 + u * 24, this.ctx.beginPath(), this.ctx.arc(0, 0, g + 4, -Math.PI / 2, -Math.PI / 2 + Math.PI * 2 * h), this.ctx.stroke(), u > 0) {
2759
+ const x = 1 - u;
2760
+ this.ctx.save(), this.ctx.globalAlpha = u * 0.75, this.ctx.strokeStyle = e.effectHighlight, this.ctx.lineWidth = 2 + u * 2, this.ctx.shadowColor = o, this.ctx.shadowBlur = 18, this.ctx.beginPath(), this.ctx.arc(0, 0, g + 10 + x * 28, 0, Math.PI * 2), this.ctx.stroke();
2761
+ for (let y = 0; y < 8; y++) {
2762
+ const m = y * Math.PI * 2 / 8 + t.pulsePhase * 0.4, v = g + 8, A = v + 10 + x * 16;
2763
+ this.ctx.beginPath(), this.ctx.moveTo(Math.cos(m) * v, Math.sin(m) * v), this.ctx.lineTo(Math.cos(m) * A, Math.sin(m) * A), this.ctx.stroke();
2764
+ }
2765
+ this.ctx.restore();
2766
+ }
2767
+ this.ctx.restore(), this.ctx.restore();
2836
2768
  }
2837
2769
  drawPsionicTendril(t, e, i) {
2838
2770
  if (!this.ctx) return;
2839
2771
  this.ctx.save();
2840
2772
  const s = e.x - t.x, a = e.y - t.y;
2841
2773
  this.ctx.strokeStyle = i.tendrilMagenta, this.ctx.lineWidth = 9, this.ctx.shadowColor = i.tendrilMagenta, this.ctx.shadowBlur = 20, this.ctx.beginPath(), this.ctx.moveTo(t.x, t.y);
2842
- const r = (t.x + e.x) / 2 + Math.sin(Date.now() * 0.02) * 16, o = (t.y + e.y) / 2 + Math.cos(Date.now() * 0.02) * 16;
2843
- this.ctx.quadraticCurveTo(r, o, e.x, e.y), this.ctx.stroke(), this.ctx.strokeStyle = i.tendrilCyan, this.ctx.lineWidth = 3.5, this.ctx.shadowColor = i.tendrilCyan, this.ctx.shadowBlur = 12, this.ctx.beginPath(), this.ctx.moveTo(t.x, t.y), this.ctx.lineTo(e.x, e.y), this.ctx.stroke();
2844
- for (let n = 0; n < 6; n++) {
2845
- const l = Math.random(), h = t.x + s * l + (Math.random() - 0.5) * 24, c = t.y + a * l + (Math.random() - 0.5) * 24;
2846
- this.ctx.fillStyle = i.effectHighlight, this.ctx.beginPath(), this.ctx.arc(h, c, 2.5 + Math.random() * 2.5, 0, Math.PI * 2), this.ctx.fill();
2774
+ const n = (t.x + e.x) / 2 + Math.sin(Date.now() * 0.02) * 16, o = (t.y + e.y) / 2 + Math.cos(Date.now() * 0.02) * 16;
2775
+ this.ctx.quadraticCurveTo(n, o, e.x, e.y), this.ctx.stroke(), this.ctx.strokeStyle = i.tendrilCyan, this.ctx.lineWidth = 3.5, this.ctx.shadowColor = i.tendrilCyan, this.ctx.shadowBlur = 12, this.ctx.beginPath(), this.ctx.moveTo(t.x, t.y), this.ctx.lineTo(e.x, e.y), this.ctx.stroke();
2776
+ for (let r = 0; r < 6; r++) {
2777
+ const c = Math.random(), l = t.x + s * c + (Math.random() - 0.5) * 24, h = t.y + a * c + (Math.random() - 0.5) * 24;
2778
+ this.ctx.fillStyle = i.effectHighlight, this.ctx.beginPath(), this.ctx.arc(l, h, 2.5 + Math.random() * 2.5, 0, Math.PI * 2), this.ctx.fill();
2847
2779
  }
2848
2780
  this.ctx.restore();
2849
2781
  }
@@ -2851,8 +2783,8 @@ class xt {
2851
2783
  if (this.ctx)
2852
2784
  for (const a of i) {
2853
2785
  if (!a.active || a.isGrabbed || a.isThrown || a.wasManipulated || a.isDying) continue;
2854
- const r = e.x - a.position.x, o = e.y - a.position.y;
2855
- if (Math.hypot(r, o) <= a.getHitRadius()) {
2786
+ const n = e.x - a.position.x, o = e.y - a.position.y;
2787
+ if (Math.hypot(n, o) <= a.getHitRadius()) {
2856
2788
  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();
2857
2789
  break;
2858
2790
  }
@@ -2862,29 +2794,27 @@ class xt {
2862
2794
  if (this.ctx)
2863
2795
  for (const s of t) {
2864
2796
  if (!s.active) continue;
2865
- let a = s.color;
2866
- s.type === "piercer" ? a = i.piercerColor : s.type === "spore" ? a = i.sporeColor : s.type === "cluster" ? a = i.clusterColor : s.type === "parasite" ? a = i.parasiteColor : s.type === "micro" && (a = i.microColor);
2867
- const { x: r, y: o } = s.position;
2868
- if (this.ctx.save(), this.ctx.translate(r, o), s.wasManipulated && !s.isDying) {
2869
- const n = s.radius * 1.5 + Math.sin(e * 6) * 4;
2870
- this.ctx.strokeStyle = i.tendrilMagenta, this.ctx.lineWidth = 2.5, this.ctx.shadowColor = i.tendrilMagenta, this.ctx.shadowBlur = 18, this.ctx.beginPath(), this.ctx.arc(0, 0, n, 0, Math.PI * 2), this.ctx.stroke();
2871
- const l = s.radius * 1.8 + Math.cos(e * 8) * 3;
2872
- this.ctx.strokeStyle = i.tendrilCyan, this.ctx.lineWidth = 1.5, this.ctx.beginPath(), this.ctx.arc(0, 0, l, 0, Math.PI * 2), this.ctx.stroke();
2797
+ const a = s.color, { x: n, y: o } = s.position;
2798
+ if (this.ctx.save(), this.ctx.translate(n, o), s.wasManipulated && !s.isDying) {
2799
+ const r = s.radius * 1.5 + Math.sin(e * 6) * 4;
2800
+ this.ctx.strokeStyle = i.tendrilMagenta, this.ctx.lineWidth = 2.5, this.ctx.shadowColor = i.tendrilMagenta, this.ctx.shadowBlur = 18, this.ctx.beginPath(), this.ctx.arc(0, 0, r, 0, Math.PI * 2), this.ctx.stroke();
2801
+ const c = s.radius * 1.8 + Math.cos(e * 8) * 3;
2802
+ this.ctx.strokeStyle = i.tendrilCyan, this.ctx.lineWidth = 1.5, this.ctx.beginPath(), this.ctx.arc(0, 0, c, 0, Math.PI * 2), this.ctx.stroke();
2873
2803
  }
2874
2804
  if (s.isDying) {
2875
- const n = s.deathTimer / s.maxDeathTimer, l = Math.max(0, 1 - n);
2876
- if (this.ctx.globalAlpha = l, s.deathType === "dissolve") {
2877
- const h = s.radius * (1 - n * 0.7);
2878
- this.ctx.fillStyle = i.sporeColor, this.ctx.shadowColor = i.sporeColor, this.ctx.shadowBlur = 20, this.ctx.beginPath(), this.ctx.arc(0, 0, h, 0, Math.PI * 2), this.ctx.fill();
2879
- for (let c = 0; c < 4; c++) {
2880
- const p = c * Math.PI * 0.5 + n * 4, g = h * 0.8 * n;
2881
- this.ctx.fillStyle = i.effectHighlight, this.ctx.beginPath(), this.ctx.arc(Math.cos(p) * g, Math.sin(p) * g, 3, 0, Math.PI * 2), this.ctx.fill();
2805
+ const r = s.deathTimer / s.maxDeathTimer, c = Math.max(0, 1 - r);
2806
+ if (this.ctx.globalAlpha = c, s.deathType === "dissolve") {
2807
+ const l = s.radius * (1 - r * 0.7);
2808
+ this.ctx.fillStyle = i.sporeColor, this.ctx.shadowColor = i.sporeColor, this.ctx.shadowBlur = 20, this.ctx.beginPath(), this.ctx.arc(0, 0, l, 0, Math.PI * 2), this.ctx.fill();
2809
+ for (let h = 0; h < 4; h++) {
2810
+ const u = h * Math.PI * 0.5 + r * 4, d = l * 0.8 * r;
2811
+ this.ctx.fillStyle = i.effectHighlight, this.ctx.beginPath(), this.ctx.arc(Math.cos(u) * d, Math.sin(u) * d, 3, 0, Math.PI * 2), this.ctx.fill();
2882
2812
  }
2883
2813
  this.ctx.restore();
2884
2814
  continue;
2885
2815
  } else if (s.deathType === "sliced") {
2886
- const h = n * 24, c = s.sliceAngle + Math.PI / 2, p = Math.cos(c) * h, g = Math.sin(c) * h;
2887
- this.ctx.shadowColor = i.piercerColor, this.ctx.shadowBlur = 22, this.ctx.fillStyle = a, this.ctx.save(), this.ctx.translate(p, g), 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, -g), 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();
2816
+ const l = r * 24, h = s.sliceAngle + Math.PI / 2, u = Math.cos(h) * l, d = Math.sin(h) * l;
2817
+ this.ctx.shadowColor = i.piercerColor, this.ctx.shadowBlur = 22, this.ctx.fillStyle = a, this.ctx.save(), this.ctx.translate(u, d), 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(-u, -d), 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();
2888
2818
  continue;
2889
2819
  }
2890
2820
  }
@@ -2906,66 +2836,60 @@ class xt {
2906
2836
  }
2907
2837
  drawOrbitingModifierOrbs(t, e, i, s = !0, a = 1) {
2908
2838
  if (!this.ctx) return;
2909
- const r = this.themeManager.getPalette(), o = this.themeManager.getTheme() === "light";
2910
- for (const n of t) {
2911
- if (!n.active) continue;
2912
- const { x: l, y: h } = n.position, c = n.definition.color, p = n.definition.rarity, g = ft[p], _ = n.radius + Math.sin(e * 6 + n.orbitAngle) * 3;
2913
- if (this.ctx.save(), this.ctx.shadowColor = g, this.ctx.shadowBlur = n.isGrabbed ? 36 : p === "legendary" ? 28 : 16, p === "legendary" || p === "epic") {
2914
- const d = _ + 12, x = this.ctx.createRadialGradient(l, h, _, l, h, d);
2915
- x.addColorStop(0, g), x.addColorStop(1, "rgba(0, 0, 0, 0)"), this.ctx.fillStyle = x, this.ctx.beginPath(), this.ctx.arc(l, h, d, 0, Math.PI * 2), this.ctx.fill();
2839
+ const n = this.themeManager.getPalette(), o = this.themeManager.getTheme() === "light";
2840
+ for (const r of t) {
2841
+ if (!r.active) continue;
2842
+ const { x: c, y: l } = r.position, h = r.definition.color, u = r.definition.rarity, d = At[u], g = r.radius + Math.sin(e * 6 + r.orbitAngle) * 3;
2843
+ if (this.ctx.save(), this.ctx.shadowColor = d, this.ctx.shadowBlur = r.isGrabbed ? 36 : u === "legendary" ? 28 : 16, u === "legendary" || u === "epic") {
2844
+ const _ = g + 12, x = this.ctx.createRadialGradient(c, l, g, c, l, _);
2845
+ x.addColorStop(0, d), x.addColorStop(1, "rgba(0, 0, 0, 0)"), this.ctx.fillStyle = x, this.ctx.beginPath(), this.ctx.arc(c, l, _, 0, Math.PI * 2), this.ctx.fill();
2916
2846
  }
2917
- const m = this.ctx.createRadialGradient(l, h, 2, l, h, _ * 1.4);
2918
- m.addColorStop(0, r.effectHighlight), m.addColorStop(0.4, c), m.addColorStop(1, o ? "rgba(23, 50, 77, 0.24)" : "rgba(0, 0, 0, 0.5)"), this.ctx.fillStyle = m, this.ctx.beginPath(), this.ctx.arc(l, h, _, 0, Math.PI * 2), this.ctx.fill(), this.ctx.strokeStyle = g, this.ctx.lineWidth = p === "legendary" ? 3.5 : 2.5, this.ctx.beginPath(), this.ctx.arc(l, h, _ + 4, e * 3, e * 3 + Math.PI * 1.2), this.ctx.stroke(), (p === "legendary" || p === "epic") && (this.ctx.strokeStyle = o ? g : r.effectHighlight, this.ctx.lineWidth = 1.5, this.ctx.beginPath(), this.ctx.arc(l, h, _ + 8, -e * 2, -e * 2 + Math.PI * 0.9), this.ctx.stroke()), this.ctx.font = "900 14px Orbitron, sans-serif", this.ctx.textAlign = "center", this.ctx.textBaseline = "middle", this.ctx.fillStyle = r.effectInk, this.ctx.shadowColor = r.effectShadow, this.ctx.shadowBlur = 6, this.ctx.fillText(n.definition.badge, l, h);
2919
- const u = i ? i.translate(n.definition.titleKey) : n.definition.badge;
2920
- this.ctx.textBaseline = "alphabetic", this.ctx.font = "900 16px Orbitron, sans-serif", this.ctx.fillStyle = r.effectInk, this.ctx.shadowColor = g, this.ctx.shadowBlur = 14, this.ctx.fillText(u, l, h - _ - 14), this.ctx.restore();
2847
+ const b = this.ctx.createRadialGradient(c, l, 2, c, l, g * 1.4);
2848
+ b.addColorStop(0, n.effectHighlight), b.addColorStop(0.4, h), b.addColorStop(1, o ? "rgba(23, 50, 77, 0.24)" : "rgba(0, 0, 0, 0.5)"), this.ctx.fillStyle = b, this.ctx.beginPath(), this.ctx.arc(c, l, g, 0, Math.PI * 2), this.ctx.fill(), this.ctx.strokeStyle = d, this.ctx.lineWidth = u === "legendary" ? 3.5 : 2.5, this.ctx.beginPath(), this.ctx.arc(c, l, g + 4, e * 3, e * 3 + Math.PI * 1.2), this.ctx.stroke(), (u === "legendary" || u === "epic") && (this.ctx.strokeStyle = o ? d : n.effectHighlight, this.ctx.lineWidth = 1.5, this.ctx.beginPath(), this.ctx.arc(c, l, g + 8, -e * 2, -e * 2 + Math.PI * 0.9), this.ctx.stroke()), this.ctx.font = "900 14px Orbitron, sans-serif", this.ctx.textAlign = "center", this.ctx.textBaseline = "middle", this.ctx.fillStyle = n.effectInk, this.ctx.shadowColor = n.effectShadow, this.ctx.shadowBlur = 6, this.ctx.fillText(r.definition.badge, c, l);
2849
+ const f = i ? i.translate(r.definition.titleKey) : r.definition.badge;
2850
+ this.ctx.textBaseline = "alphabetic", this.ctx.font = "900 16px Orbitron, sans-serif", this.ctx.fillStyle = n.effectInk, this.ctx.shadowColor = d, this.ctx.shadowBlur = 14, this.ctx.fillText(f, c, l - g - 14), this.ctx.restore();
2921
2851
  }
2922
2852
  if (i && s) {
2923
- const n = this.canvas.width / 2, l = this.canvas.height / 2 + 210, h = i.translate("rerollButton", { count: a });
2924
- this.ctx.save(), this.ctx.font = "900 14px Orbitron, sans-serif", this.ctx.textAlign = "center", this.ctx.textBaseline = "middle", this.ctx.fillStyle = r.effectPanel, this.ctx.strokeStyle = r.tendrilCyan, this.ctx.lineWidth = 2, this.ctx.shadowColor = r.tendrilCyan, this.ctx.shadowBlur = 12;
2925
- const g = this.ctx.measureText(h).width + 20 * 2, _ = 38;
2926
- this.ctx.beginPath(), this.ctx.roundRect(n - g / 2, l - _ / 2, g, _, 8), this.ctx.fill(), this.ctx.stroke(), this.ctx.fillStyle = r.effectInk, this.ctx.shadowColor = r.effectShadow, this.ctx.shadowBlur = 4, this.ctx.fillText(h, n, l), this.ctx.restore();
2853
+ const r = this.canvas.width / 2, c = this.canvas.height / 2 + 210, l = i.translate("rerollButton", { count: a });
2854
+ this.ctx.save(), this.ctx.font = "900 14px Orbitron, sans-serif", this.ctx.textAlign = "center", this.ctx.textBaseline = "middle", this.ctx.fillStyle = n.effectPanel, this.ctx.strokeStyle = n.tendrilCyan, this.ctx.lineWidth = 2, this.ctx.shadowColor = n.tendrilCyan, this.ctx.shadowBlur = 12;
2855
+ const d = this.ctx.measureText(l).width + 20 * 2, g = 38;
2856
+ this.ctx.beginPath(), this.ctx.roundRect(r - d / 2, c - g / 2, d, g, 8), this.ctx.fill(), this.ctx.stroke(), this.ctx.fillStyle = n.effectInk, this.ctx.shadowColor = n.effectShadow, this.ctx.shadowBlur = 4, this.ctx.fillText(l, r, c), this.ctx.restore();
2927
2857
  }
2928
2858
  }
2929
2859
  colorWithAlpha(t, e) {
2930
2860
  const i = t.replace("#", "");
2931
2861
  if (i.length !== 6) return t;
2932
- const s = Number.parseInt(i.slice(0, 2), 16), a = Number.parseInt(i.slice(2, 4), 16), r = Number.parseInt(i.slice(4, 6), 16);
2933
- return `rgba(${s}, ${a}, ${r}, ${e})`;
2862
+ const s = Number.parseInt(i.slice(0, 2), 16), a = Number.parseInt(i.slice(2, 4), 16), n = Number.parseInt(i.slice(4, 6), 16);
2863
+ return `rgba(${s}, ${a}, ${n}, ${e})`;
2934
2864
  }
2935
2865
  }
2936
- class yt {
2866
+ class St {
2937
2867
  container;
2938
- i18n;
2939
- waveLabelElement;
2940
- progressSlot;
2941
2868
  comboElement;
2942
2869
  settingsButton;
2943
- constructor(t, e, i) {
2944
- this.i18n = e, 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 = `
2870
+ constructor(t, e) {
2871
+ this.container = document.createElement("div"), this.container.className = "axon-hud", 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 = `
2945
2872
  <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
2946
2873
  <circle cx="12" cy="12" r="3"></circle>
2947
2874
  <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>
2948
2875
  </svg>
2949
- `, this.settingsButton.addEventListener("click", i), this.renderLabels(), this.container.appendChild(this.waveLabelElement), this.container.appendChild(this.comboElement), this.container.appendChild(this.settingsButton), t.appendChild(this.container);
2876
+ `, this.settingsButton.addEventListener("click", e), this.renderLabels(), this.container.appendChild(this.comboElement), this.container.appendChild(this.settingsButton), t.appendChild(this.container);
2950
2877
  }
2951
2878
  renderLabels() {
2952
- let t = this.waveLabelElement.querySelector(".axon-level-title");
2953
- 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));
2954
- let e = this.waveLabelElement.querySelector("#axon-wave-val");
2955
- e || (e = document.createElement("span"), e.id = "axon-wave-val", e.textContent = "1", this.waveLabelElement.insertBefore(e, this.progressSlot)), this.comboElement.innerHTML = '<span id="axon-combo-val"></span>';
2879
+ this.comboElement.innerHTML = '<span id="axon-combo-val"></span>';
2956
2880
  }
2957
- update(t, e) {
2958
- const i = this.container.querySelector("#axon-wave-val"), s = this.container.querySelector("#axon-combo-val");
2959
- i && (i.textContent = t.toString()), s && (e >= 2 ? (s.textContent = `x${e}`, s.style.display = "block") : s.style.display = "none");
2881
+ update(t) {
2882
+ const e = this.container.querySelector("#axon-combo-val");
2883
+ e && (t >= 2 ? (e.textContent = `x${t}`, e.style.display = "block") : e.style.display = "none");
2960
2884
  }
2961
2885
  show() {
2962
- this.renderLabels(), this.container.style.display = "flex";
2886
+ this.container.style.display = "flex";
2963
2887
  }
2964
2888
  hide() {
2965
2889
  this.container.style.display = "none";
2966
2890
  }
2967
2891
  }
2968
- class Et {
2892
+ class It {
2969
2893
  container;
2970
2894
  i18n;
2971
2895
  onStartCallback;
@@ -2991,7 +2915,7 @@ class Et {
2991
2915
  this.container.style.display = "none";
2992
2916
  }
2993
2917
  }
2994
- class At {
2918
+ class Tt {
2995
2919
  modal;
2996
2920
  card;
2997
2921
  i18n;
@@ -3002,12 +2926,12 @@ class At {
3002
2926
  hapticsEnabled = !0;
3003
2927
  fpsLimit = 60;
3004
2928
  onFpsLimitChangedCallback;
3005
- constructor(t, e, i, s, a, r, o) {
3006
- this.i18n = e, this.themeManager = i, this.platform = s, this.onLanguageChangedCallback = a, this.onCloseCallback = r, this.onFpsLimitChangedCallback = o;
3007
- const n = localStorage.getItem("axon_surge_haptics");
3008
- n !== null && (this.hapticsEnabled = n === "true");
3009
- const l = Number(localStorage.getItem("axon_surge_fps_limit"));
3010
- (l === 30 || l === 60 || l === 120) && (this.fpsLimit = l), 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", () => {
2929
+ constructor(t, e, i, s, a, n, o) {
2930
+ this.i18n = e, this.themeManager = i, this.platform = s, this.onLanguageChangedCallback = a, this.onCloseCallback = n, this.onFpsLimitChangedCallback = o;
2931
+ const r = localStorage.getItem("axon_surge_haptics");
2932
+ r !== null && (this.hapticsEnabled = r === "true");
2933
+ const c = Number(localStorage.getItem("axon_surge_fps_limit"));
2934
+ (c === 30 || c === 60 || c === 120) && (this.fpsLimit = c), 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", () => {
3011
2935
  this.onCloseCallback && this.onCloseCallback();
3012
2936
  }), this.renderContent();
3013
2937
  }
@@ -3023,7 +2947,7 @@ class At {
3023
2947
  s.className = "axon-select-wrapper";
3024
2948
  const a = document.createElement("select");
3025
2949
  a.className = "axon-select";
3026
- const r = {
2950
+ const n = {
3027
2951
  es: "ESPAÑOL (ES)",
3028
2952
  en: "ENGLISH (EN)",
3029
2953
  fr: "FRANÇAIS (FR)",
@@ -3040,92 +2964,92 @@ class At {
3040
2964
  ko: "한국어 (KO)",
3041
2965
  zh: "中文 (ZH)"
3042
2966
  };
3043
- for (const S of W) {
2967
+ for (const I of tt) {
3044
2968
  const M = document.createElement("option");
3045
- M.value = S, M.textContent = r[S], this.i18n.getLanguage() === S && (M.selected = !0), a.appendChild(M);
2969
+ M.value = I, M.textContent = n[I], this.i18n.getLanguage() === I && (M.selected = !0), a.appendChild(M);
3046
2970
  }
3047
2971
  a.addEventListener("change", () => {
3048
- const S = a.value;
3049
- this.i18n.setLanguage(S), this.onLanguageChangedCallback && this.onLanguageChangedCallback(S), this.renderContent();
2972
+ const I = a.value;
2973
+ this.i18n.setLanguage(I), this.onLanguageChangedCallback && this.onLanguageChangedCallback(I), this.renderContent();
3050
2974
  });
3051
2975
  const o = document.createElement("span");
3052
2976
  o.className = "axon-select-arrow", o.textContent = "▼", s.appendChild(a), s.appendChild(o), e.appendChild(i), e.appendChild(s);
3053
- const n = document.createElement("div");
3054
- n.className = "axon-setting-row";
3055
- const l = document.createElement("span");
3056
- l.textContent = this.i18n.translate("themeLabel");
3057
- const h = document.createElement("div");
3058
- h.className = "axon-toggle-group";
3059
- const c = [
2977
+ const r = document.createElement("div");
2978
+ r.className = "axon-setting-row";
2979
+ const c = document.createElement("span");
2980
+ c.textContent = this.i18n.translate("themeLabel");
2981
+ const l = document.createElement("div");
2982
+ l.className = "axon-toggle-group";
2983
+ const h = [
3060
2984
  { id: "bioluminescent", label: "BIO" },
3061
2985
  { id: "dark", label: "DARK" },
3062
2986
  { id: "light", label: "LIGHT" }
3063
2987
  ];
3064
- for (const S of c) {
2988
+ for (const I of h) {
3065
2989
  const M = document.createElement("button");
3066
- M.type = "button", M.className = `axon-toggle-btn ${this.themeManager.getTheme() === S.id ? "active" : ""}`, M.textContent = S.label, M.addEventListener("click", () => {
3067
- this.themeManager.setTheme(S.id), this.renderContent();
3068
- }), h.appendChild(M);
2990
+ M.type = "button", M.className = `axon-toggle-btn ${this.themeManager.getTheme() === I.id ? "active" : ""}`, M.textContent = I.label, M.addEventListener("click", () => {
2991
+ this.themeManager.setTheme(I.id), this.renderContent();
2992
+ }), l.appendChild(M);
3069
2993
  }
3070
- n.appendChild(l), n.appendChild(h);
3071
- const p = document.createElement("div");
3072
- p.className = "axon-setting-row";
3073
- const g = document.createElement("span");
3074
- g.textContent = this.i18n.translate("fpsLimitLabel");
3075
- const _ = document.createElement("div");
3076
- _.className = "axon-toggle-group";
3077
- const m = [
2994
+ r.appendChild(c), r.appendChild(l);
2995
+ const u = document.createElement("div");
2996
+ u.className = "axon-setting-row";
2997
+ const d = document.createElement("span");
2998
+ d.textContent = this.i18n.translate("fpsLimitLabel");
2999
+ const g = document.createElement("div");
3000
+ g.className = "axon-toggle-group";
3001
+ const b = [
3078
3002
  { limit: 30, label: "30 FPS" },
3079
3003
  { limit: 60, label: "60 FPS" },
3080
3004
  { limit: 120, label: "120 FPS" }
3081
3005
  ];
3082
- for (const S of m) {
3006
+ for (const I of b) {
3083
3007
  const M = document.createElement("button");
3084
- M.type = "button", M.className = `axon-toggle-btn ${this.fpsLimit === S.limit ? "active" : ""}`, M.textContent = S.label, M.addEventListener("click", () => {
3085
- this.fpsLimit = S.limit, localStorage.setItem("axon_surge_fps_limit", String(S.limit)), this.onFpsLimitChangedCallback?.(S.limit), this.renderContent();
3086
- }), _.appendChild(M);
3008
+ M.type = "button", M.className = `axon-toggle-btn ${this.fpsLimit === I.limit ? "active" : ""}`, M.textContent = I.label, M.addEventListener("click", () => {
3009
+ this.fpsLimit = I.limit, localStorage.setItem("axon_surge_fps_limit", String(I.limit)), this.onFpsLimitChangedCallback?.(I.limit), this.renderContent();
3010
+ }), g.appendChild(M);
3087
3011
  }
3088
- p.appendChild(g), p.appendChild(_);
3089
- const u = document.createElement("div");
3090
- u.className = "axon-setting-row";
3091
- const d = document.createElement("span");
3092
- d.textContent = this.i18n.translate("hapticsLabel");
3012
+ u.appendChild(d), u.appendChild(g);
3013
+ const f = document.createElement("div");
3014
+ f.className = "axon-setting-row";
3015
+ const _ = document.createElement("span");
3016
+ _.textContent = this.i18n.translate("hapticsLabel");
3093
3017
  const x = document.createElement("div");
3094
3018
  x.className = "axon-toggle-group";
3095
3019
  const y = [
3096
3020
  { enabled: !0, label: this.i18n.translate("hapticsOn") },
3097
3021
  { enabled: !1, label: this.i18n.translate("hapticsOff") }
3098
3022
  ];
3099
- for (const S of y) {
3023
+ for (const I of y) {
3100
3024
  const M = document.createElement("button");
3101
- M.type = "button", M.className = `axon-toggle-btn ${this.hapticsEnabled === S.enabled ? "active" : ""}`, M.textContent = S.label, M.addEventListener("click", () => {
3102
- this.hapticsEnabled = S.enabled, localStorage.setItem("axon_surge_haptics", String(S.enabled)), this.hapticsEnabled && this.platform.haptics.selectionChanged(), this.renderContent();
3025
+ M.type = "button", M.className = `axon-toggle-btn ${this.hapticsEnabled === I.enabled ? "active" : ""}`, M.textContent = I.label, M.addEventListener("click", () => {
3026
+ this.hapticsEnabled = I.enabled, localStorage.setItem("axon_surge_haptics", String(I.enabled)), this.hapticsEnabled && this.platform.haptics.selectionChanged(), this.renderContent();
3103
3027
  }), x.appendChild(M);
3104
3028
  }
3105
- u.appendChild(d), u.appendChild(x);
3106
- const E = document.createElement("div");
3107
- E.className = "axon-setting-row";
3108
- const I = document.createElement("span");
3109
- I.textContent = this.i18n.translate("tutorialSettingLabel");
3110
- const T = document.createElement("div");
3111
- T.className = "axon-toggle-group";
3112
- const L = localStorage.getItem("axon_surge_show_tutorial") !== "false", A = [
3029
+ f.appendChild(_), f.appendChild(x);
3030
+ const m = document.createElement("div");
3031
+ m.className = "axon-setting-row";
3032
+ const v = document.createElement("span");
3033
+ v.textContent = this.i18n.translate("tutorialSettingLabel");
3034
+ const A = document.createElement("div");
3035
+ A.className = "axon-toggle-group";
3036
+ const S = localStorage.getItem("axon_surge_show_tutorial") !== "false", L = [
3113
3037
  { enabled: !0, label: this.i18n.translate("hapticsOn") },
3114
3038
  { enabled: !1, label: this.i18n.translate("hapticsOff") }
3115
3039
  ];
3116
- for (const S of A) {
3040
+ for (const I of L) {
3117
3041
  const M = document.createElement("button");
3118
- M.type = "button", M.className = `axon-toggle-btn ${L === S.enabled ? "active" : ""}`, M.textContent = S.label, M.addEventListener("click", () => {
3119
- localStorage.setItem("axon_surge_show_tutorial", String(S.enabled)), this.renderContent();
3120
- }), T.appendChild(M);
3042
+ M.type = "button", M.className = `axon-toggle-btn ${S === I.enabled ? "active" : ""}`, M.textContent = I.label, M.addEventListener("click", () => {
3043
+ localStorage.setItem("axon_surge_show_tutorial", String(I.enabled)), this.renderContent();
3044
+ }), A.appendChild(M);
3121
3045
  }
3122
- E.appendChild(I), E.appendChild(T);
3123
- const R = document.createElement("div");
3124
- R.className = "axon-settings-credits", R.textContent = this.i18n.translate("creditsJam");
3125
- const C = document.createElement("button");
3126
- C.type = "button", C.className = "axon-start-button", C.style.padding = "12px 36px", C.style.fontSize = "14px", C.textContent = this.i18n.translate("closeButton"), C.addEventListener("click", () => {
3046
+ m.appendChild(v), m.appendChild(A);
3047
+ const T = document.createElement("div");
3048
+ T.className = "axon-settings-credits", T.textContent = this.i18n.translate("creditsJam");
3049
+ const O = document.createElement("button");
3050
+ O.type = "button", O.className = "axon-start-button", O.style.padding = "12px 36px", O.style.fontSize = "14px", O.textContent = this.i18n.translate("closeButton"), O.addEventListener("click", () => {
3127
3051
  this.modal.close();
3128
- }), this.card.appendChild(t), this.card.appendChild(e), this.card.appendChild(n), this.card.appendChild(p), this.card.appendChild(u), this.card.appendChild(E), this.card.appendChild(R), this.card.appendChild(C);
3052
+ }), this.card.appendChild(t), this.card.appendChild(e), this.card.appendChild(r), this.card.appendChild(u), this.card.appendChild(f), this.card.appendChild(m), this.card.appendChild(T), this.card.appendChild(O);
3129
3053
  }
3130
3054
  isHapticsEnabled() {
3131
3055
  return this.hapticsEnabled;
@@ -3140,8 +3064,29 @@ class At {
3140
3064
  this.modal.close();
3141
3065
  }
3142
3066
  }
3143
- const F = "axon_surge_show_tutorial";
3144
- class bt {
3067
+ class Rt {
3068
+ constructor(t) {
3069
+ this.content = t;
3070
+ }
3071
+ createEnemy(t, e, i) {
3072
+ const s = `enemy_${Date.now()}_${Math.random()}`, a = new F(s);
3073
+ return this.configureEnemy(a, t, e, i), a;
3074
+ }
3075
+ configureEnemy(t, e, i, s) {
3076
+ const a = this.content.enemies.require(e);
3077
+ t.type = e, t.position = { ...i }, t.active = !0, t.isGrabbed = !1, t.isThrown = !1, t.isGrabbable = a.canBeGrabbed;
3078
+ const n = s.x - i.x, o = s.y - i.y, r = Math.atan2(o, n);
3079
+ t.radius = a.radius, t.hitRadiusPadding = a.hitRadiusPadding ?? 0.2, t.color = a.color, t.strategy = a.impactStrategyFactory?.() ?? null, t.behavior = a.behavior, t.synergyKey = a.synergyKey ?? a.behavior.synergyKey?.(t) ?? a.id, t.maxSpeed = a.maxSpeed, t.rotation = a.initialRotation === "random" ? Math.random() * Math.PI * 2 : 0, t.velocity = {
3080
+ x: Math.cos(r) * a.speed,
3081
+ y: Math.sin(r) * a.speed
3082
+ };
3083
+ }
3084
+ }
3085
+ const Q = "axon_surge_show_tutorial";
3086
+ class Lt {
3087
+ constructor(t, e, i) {
3088
+ this.factory = t, this.launcherType = e, this.targetType = i;
3089
+ }
3145
3090
  isActive = !1;
3146
3091
  showWarning = !1;
3147
3092
  dummyLauncher = null;
@@ -3150,14 +3095,14 @@ class bt {
3150
3095
  initialTargetPos = { x: 0, y: 0 };
3151
3096
  isTutorialEnabled() {
3152
3097
  try {
3153
- return localStorage.getItem(F) !== "false";
3098
+ return localStorage.getItem(Q) !== "false";
3154
3099
  } catch {
3155
3100
  return !0;
3156
3101
  }
3157
3102
  }
3158
3103
  setTutorialEnabled(t) {
3159
3104
  try {
3160
- localStorage.setItem(F, String(t));
3105
+ localStorage.setItem(Q, String(t));
3161
3106
  } catch {
3162
3107
  }
3163
3108
  }
@@ -3175,39 +3120,39 @@ class bt {
3175
3120
  this.isActive = !1;
3176
3121
  return;
3177
3122
  }
3178
- this.isActive = !0, this.showWarning = !1, i.length = 0, this.initialLauncherPos = { x: t * 0.28, y: e * 0.28 }, this.initialTargetPos = { x: t * 0.72, y: e * 0.28 }, this.dummyLauncher = P.createEnemy(
3179
- "piercer",
3123
+ this.isActive = !0, this.showWarning = !1, i.length = 0, this.initialLauncherPos = { x: t * 0.28, y: e * 0.28 }, this.initialTargetPos = { x: t * 0.72, y: e * 0.28 }, this.dummyLauncher = this.factory.createEnemy(
3124
+ this.launcherType,
3180
3125
  this.initialLauncherPos,
3181
3126
  this.initialTargetPos
3182
- ), this.dummyLauncher.velocity = { x: 0, y: 0 }, this.dummyTarget = P.createEnemy(
3183
- "spore",
3127
+ ), this.dummyLauncher.velocity = { x: 0, y: 0 }, this.dummyTarget = this.factory.createEnemy(
3128
+ this.targetType,
3184
3129
  this.initialTargetPos,
3185
3130
  this.initialLauncherPos
3186
3131
  ), this.dummyTarget.velocity = { x: 0, y: 0 }, i.push(this.dummyLauncher), i.push(this.dummyTarget);
3187
3132
  }
3188
- update(t, e, i, s, a, r) {
3133
+ update(t, e, i, s, a, n) {
3189
3134
  if (!this.isActive || !this.dummyLauncher || !this.dummyTarget) return;
3190
- const o = this.dummyLauncher, n = this.dummyTarget;
3191
- e.includes(o) || e.push(o), e.includes(n) || e.push(n);
3192
- const l = n.position.x - o.position.x, h = n.position.y - o.position.y, c = Math.hypot(l, h);
3135
+ const o = this.dummyLauncher, r = this.dummyTarget;
3136
+ e.includes(o) || e.push(o), e.includes(r) || e.push(r);
3137
+ const c = r.position.x - o.position.x, l = r.position.y - o.position.y, h = Math.hypot(c, l);
3193
3138
  if (o.isGrabbed) {
3194
- if (this.showWarning = !1, c <= o.radius + n.radius + 60) {
3195
- r && r(), o.isGrabbed = !1, this.showWarning = !0, this.resetDummies(o, n);
3139
+ if (this.showWarning = !1, h <= o.radius + r.radius + 60) {
3140
+ n && n(), o.isGrabbed = !1, this.showWarning = !0, this.resetDummies(o, r);
3196
3141
  return;
3197
3142
  }
3198
3143
  return;
3199
3144
  }
3200
3145
  if (o.wasManipulated) {
3201
- const p = Math.hypot(o.velocity.x, o.velocity.y);
3202
- if (!o.isThrown || p < 70) {
3203
- r && r(), this.showWarning = !0, this.resetDummies(o, n);
3146
+ const u = Math.hypot(o.velocity.x, o.velocity.y);
3147
+ if (!o.isThrown || u < 70) {
3148
+ n && n(), this.showWarning = !0, this.resetDummies(o, r);
3204
3149
  return;
3205
3150
  }
3206
- if (c <= o.getHitRadius() + n.getHitRadius()) {
3207
- o.triggerDissolveDeath(!0), n.triggerDissolveDeath(!0), this.showWarning = !1, this.isActive = !1, a();
3151
+ if (h <= o.getHitRadius() + r.getHitRadius()) {
3152
+ o.triggerDissolveDeath(!0), r.triggerDissolveDeath(!0), this.showWarning = !1, this.isActive = !1, a();
3208
3153
  return;
3209
3154
  }
3210
- (o.position.x < -60 || o.position.x > i + 60 || o.position.y < -60 || o.position.y > s + 60 || p < 40) && (r && r(), this.showWarning = !0, this.resetDummies(o, n));
3155
+ (o.position.x < -60 || o.position.x > i + 60 || o.position.y < -60 || o.position.y > s + 60 || u < 40) && (n && n(), this.showWarning = !0, this.resetDummies(o, r));
3211
3156
  }
3212
3157
  }
3213
3158
  resetDummies(t, e) {
@@ -3217,7 +3162,7 @@ class bt {
3217
3162
  this.isActive = !1, this.showWarning = !1;
3218
3163
  }
3219
3164
  }
3220
- class vt {
3165
+ class Ct {
3221
3166
  container;
3222
3167
  i18n;
3223
3168
  tutorialManager;
@@ -3253,15 +3198,15 @@ class vt {
3253
3198
  this.container.style.display = "none";
3254
3199
  }
3255
3200
  }
3256
- class It {
3257
- fillElement;
3201
+ class Pt {
3258
3202
  experienceCount = 0;
3259
3203
  currentLevel = 1;
3204
+ displayedProgress = 0;
3205
+ targetProgress = 0;
3206
+ levelUpPulse = 0;
3260
3207
  onLevelUpCallback;
3261
- constructor(t, e) {
3262
- this.onLevelUpCallback = e;
3263
- const i = document.createElement("div");
3264
- i.className = "axon-hud-level-track", this.fillElement = document.createElement("div"), this.fillElement.className = "axon-hud-level-fill", i.appendChild(this.fillElement), t.appendChild(i);
3208
+ constructor(t) {
3209
+ this.onLevelUpCallback = t;
3265
3210
  }
3266
3211
  getExperienceRequiredForLevel(t) {
3267
3212
  return t === 1 ? 3 : t === 2 ? 6 : t === 3 ? 10 : 10 + (t - 3) * 6;
@@ -3270,9 +3215,18 @@ class It {
3270
3215
  this.experienceCount += Math.max(0, t);
3271
3216
  let e = this.getExperienceRequiredForLevel(this.currentLevel);
3272
3217
  for (; this.experienceCount >= e; )
3273
- this.experienceCount -= e, this.currentLevel++, this.onLevelUpCallback && this.onLevelUpCallback(this.currentLevel), e = this.getExperienceRequiredForLevel(this.currentLevel);
3274
- const i = Math.min(100, this.experienceCount / e * 100);
3275
- this.fillElement.style.width = `${i}%`;
3218
+ this.experienceCount -= e, this.currentLevel++, this.displayedProgress = 1, this.levelUpPulse = 1, this.onLevelUpCallback && this.onLevelUpCallback(this.currentLevel), e = this.getExperienceRequiredForLevel(this.currentLevel);
3219
+ this.targetProgress = this.getRawProgress();
3220
+ }
3221
+ update(t) {
3222
+ const e = 1 - Math.exp(-Math.max(0, t) * 11);
3223
+ this.displayedProgress += (this.targetProgress - this.displayedProgress) * e, this.levelUpPulse = Math.max(0, this.levelUpPulse - Math.max(0, t) * 1.8);
3224
+ }
3225
+ getProgress() {
3226
+ return this.displayedProgress;
3227
+ }
3228
+ getLevelUpPulse() {
3229
+ return this.levelUpPulse;
3276
3230
  }
3277
3231
  addKill() {
3278
3232
  this.addExperience(1);
@@ -3281,17 +3235,56 @@ class It {
3281
3235
  return this.currentLevel;
3282
3236
  }
3283
3237
  reset() {
3284
- this.experienceCount = 0, this.currentLevel = 1, this.fillElement.style.width = "0%";
3238
+ this.experienceCount = 0, this.currentLevel = 1, this.displayedProgress = 0, this.targetProgress = 0, this.levelUpPulse = 0;
3285
3239
  }
3286
- show() {
3287
- this.fillElement && this.fillElement.parentElement && (this.fillElement.parentElement.style.display = "block");
3240
+ getRawProgress() {
3241
+ const t = this.getExperienceRequiredForLevel(this.currentLevel);
3242
+ return Math.min(1, this.experienceCount / t);
3288
3243
  }
3289
- hide() {
3290
- this.fillElement && this.fillElement.parentElement && (this.fillElement.parentElement.style.display = "none");
3244
+ }
3245
+ class P {
3246
+ constructor(t) {
3247
+ this.kind = t;
3248
+ }
3249
+ definitions = /* @__PURE__ */ new Map();
3250
+ register(t) {
3251
+ const e = t.id.trim();
3252
+ if (!e)
3253
+ throw new Error(`Cannot register ${this.kind} definition without an id`);
3254
+ if (this.definitions.has(e))
3255
+ throw new Error(`Duplicate ${this.kind} definition: ${e}`);
3256
+ this.definitions.set(e, t);
3257
+ }
3258
+ registerMany(t) {
3259
+ for (const e of t)
3260
+ this.register(e);
3261
+ }
3262
+ has(t) {
3263
+ return this.definitions.has(t);
3264
+ }
3265
+ get(t) {
3266
+ return this.definitions.get(t);
3267
+ }
3268
+ require(t) {
3269
+ const e = this.get(t);
3270
+ if (!e)
3271
+ throw new Error(`Unknown ${this.kind} definition: ${t}`);
3272
+ return e;
3273
+ }
3274
+ values() {
3275
+ return [...this.definitions.values()];
3276
+ }
3277
+ get size() {
3278
+ return this.definitions.size;
3291
3279
  }
3292
3280
  }
3293
- class V {
3294
- static powerUps = [
3281
+ class wt {
3282
+ constructor(t) {
3283
+ this.configManager = t;
3284
+ }
3285
+ registry = new P("power-up");
3286
+ defaultsRegistered = !1;
3287
+ defaultPowerUps = [
3295
3288
  {
3296
3289
  id: "spore_radius",
3297
3290
  titleKey: "pu_spore_radius_title",
@@ -3300,9 +3293,9 @@ class V {
3300
3293
  category: "radius",
3301
3294
  rarity: "common",
3302
3295
  rarityWeight: 35,
3303
- color: f.spore,
3296
+ color: E.spore,
3304
3297
  apply: () => {
3305
- const t = v.getInstance(), e = t.getConfig().toxicPool;
3298
+ const t = this.configManager, e = t.getConfig().toxicPool;
3306
3299
  t.updateConfig({
3307
3300
  toxicPool: {
3308
3301
  ...e,
@@ -3320,9 +3313,9 @@ class V {
3320
3313
  category: "duration",
3321
3314
  rarity: "common",
3322
3315
  rarityWeight: 35,
3323
- color: f.spore,
3316
+ color: E.spore,
3324
3317
  apply: () => {
3325
- const t = v.getInstance(), e = t.getConfig().toxicPool;
3318
+ const t = this.configManager, e = t.getConfig().toxicPool;
3326
3319
  t.updateConfig({
3327
3320
  toxicPool: {
3328
3321
  ...e,
@@ -3340,9 +3333,9 @@ class V {
3340
3333
  category: "radius",
3341
3334
  rarity: "common",
3342
3335
  rarityWeight: 35,
3343
- color: f.parasite,
3336
+ color: E.parasite,
3344
3337
  apply: () => {
3345
- const t = v.getInstance(), e = t.getConfig().gravityVortex;
3338
+ const t = this.configManager, e = t.getConfig().gravityVortex;
3346
3339
  t.updateConfig({
3347
3340
  gravityVortex: {
3348
3341
  ...e,
@@ -3360,9 +3353,9 @@ class V {
3360
3353
  category: "duration",
3361
3354
  rarity: "common",
3362
3355
  rarityWeight: 35,
3363
- color: f.parasite,
3356
+ color: E.parasite,
3364
3357
  apply: () => {
3365
- const t = v.getInstance(), e = t.getConfig().gravityVortex;
3358
+ const t = this.configManager, e = t.getConfig().gravityVortex;
3366
3359
  t.updateConfig({
3367
3360
  gravityVortex: {
3368
3361
  ...e,
@@ -3380,9 +3373,9 @@ class V {
3380
3373
  category: "power",
3381
3374
  rarity: "rare",
3382
3375
  rarityWeight: 25,
3383
- color: f.parasite,
3376
+ color: E.parasite,
3384
3377
  apply: () => {
3385
- const t = v.getInstance(), e = t.getConfig().gravityVortex;
3378
+ const t = this.configManager, e = t.getConfig().gravityVortex;
3386
3379
  t.updateConfig({
3387
3380
  gravityVortex: {
3388
3381
  ...e,
@@ -3394,15 +3387,16 @@ class V {
3394
3387
  },
3395
3388
  {
3396
3389
  id: "vortex_pocket",
3390
+ isAvailable: ({ config: t }) => !t.gravityVortex.hasImplosionLaunch,
3397
3391
  titleKey: "pu_vortex_pocket_title",
3398
3392
  descKey: "pu_vortex_pocket_desc",
3399
3393
  badge: "IMPLODE LAUNCH",
3400
3394
  category: "power",
3401
3395
  rarity: "legendary",
3402
3396
  rarityWeight: 5,
3403
- color: f.parasite,
3397
+ color: E.parasite,
3404
3398
  apply: () => {
3405
- const t = v.getInstance(), e = t.getConfig().gravityVortex;
3399
+ const t = this.configManager, e = t.getConfig().gravityVortex;
3406
3400
  t.updateConfig({
3407
3401
  gravityVortex: {
3408
3402
  ...e,
@@ -3413,15 +3407,16 @@ class V {
3413
3407
  },
3414
3408
  {
3415
3409
  id: "shield_fan",
3410
+ isAvailable: ({ config: t }) => !t.shield.isFanBlast,
3416
3411
  titleKey: "pu_shield_fan_title",
3417
3412
  descKey: "pu_shield_fan_desc",
3418
3413
  badge: "FAN BLAST",
3419
3414
  category: "power",
3420
3415
  rarity: "legendary",
3421
3416
  rarityWeight: 5,
3422
- color: f.heavy,
3417
+ color: E.heavy,
3423
3418
  apply: () => {
3424
- const t = v.getInstance(), e = t.getConfig().shield;
3419
+ const t = this.configManager, e = t.getConfig().shield;
3425
3420
  t.updateConfig({
3426
3421
  shield: {
3427
3422
  ...e,
@@ -3432,15 +3427,16 @@ class V {
3432
3427
  },
3433
3428
  {
3434
3429
  id: "shield_fan_upgrade",
3430
+ isAvailable: ({ config: t }) => t.shield.isFanBlast && !t.shield.hasFanBlastUpgrade,
3435
3431
  titleKey: "pu_shield_fan_upgrade_title",
3436
3432
  descKey: "pu_shield_fan_upgrade_desc",
3437
3433
  badge: "+0.35s / +15°",
3438
3434
  category: "power",
3439
3435
  rarity: "epic",
3440
3436
  rarityWeight: 15,
3441
- color: f.heavy,
3437
+ color: E.heavy,
3442
3438
  apply: () => {
3443
- const t = v.getInstance(), e = t.getConfig().shield;
3439
+ const t = this.configManager, e = t.getConfig().shield;
3444
3440
  t.updateConfig({
3445
3441
  shield: {
3446
3442
  ...e,
@@ -3459,9 +3455,9 @@ class V {
3459
3455
  category: "defense",
3460
3456
  rarity: "common",
3461
3457
  rarityWeight: 35,
3462
- color: f.heavy,
3458
+ color: E.heavy,
3463
3459
  apply: () => {
3464
- const t = v.getInstance(), e = t.getConfig().shield;
3460
+ const t = this.configManager, e = t.getConfig().shield;
3465
3461
  t.updateConfig({
3466
3462
  shield: {
3467
3463
  ...e,
@@ -3478,9 +3474,9 @@ class V {
3478
3474
  category: "power",
3479
3475
  rarity: "rare",
3480
3476
  rarityWeight: 25,
3481
- color: f.cluster,
3477
+ color: E.cluster,
3482
3478
  apply: () => {
3483
- const t = v.getInstance(), e = t.getConfig().cluster;
3479
+ const t = this.configManager, e = t.getConfig().cluster;
3484
3480
  t.updateConfig({
3485
3481
  cluster: {
3486
3482
  ...e,
@@ -3491,15 +3487,16 @@ class V {
3491
3487
  },
3492
3488
  {
3493
3489
  id: "cluster_homing",
3490
+ isAvailable: ({ config: t }) => !t.cluster.hasHoming,
3494
3491
  titleKey: "pu_cluster_homing_title",
3495
3492
  descKey: "pu_cluster_homing_desc",
3496
3493
  badge: "SEEKER FRAGS",
3497
3494
  category: "power",
3498
3495
  rarity: "legendary",
3499
3496
  rarityWeight: 5,
3500
- color: f.cluster,
3497
+ color: E.cluster,
3501
3498
  apply: () => {
3502
- const t = v.getInstance(), e = t.getConfig().cluster;
3499
+ const t = this.configManager, e = t.getConfig().cluster;
3503
3500
  t.updateConfig({
3504
3501
  cluster: {
3505
3502
  ...e,
@@ -3516,9 +3513,9 @@ class V {
3516
3513
  category: "power",
3517
3514
  rarity: "epic",
3518
3515
  rarityWeight: 15,
3519
- color: f.piercer,
3516
+ color: E.piercer,
3520
3517
  apply: () => {
3521
- const t = v.getInstance(), e = t.getConfig().piercer;
3518
+ const t = this.configManager, e = t.getConfig().piercer;
3522
3519
  t.updateConfig({
3523
3520
  piercer: {
3524
3521
  ...e,
@@ -3529,15 +3526,16 @@ class V {
3529
3526
  },
3530
3527
  {
3531
3528
  id: "piercer_homing",
3529
+ isAvailable: ({ config: t }) => !t.piercer.hasHoming,
3532
3530
  titleKey: "pu_piercer_homing_title",
3533
3531
  descKey: "pu_piercer_homing_desc",
3534
3532
  badge: "SEEKER",
3535
3533
  category: "power",
3536
3534
  rarity: "legendary",
3537
3535
  rarityWeight: 5,
3538
- color: f.piercer,
3536
+ color: E.piercer,
3539
3537
  apply: () => {
3540
- const t = v.getInstance(), e = t.getConfig().piercer;
3538
+ const t = this.configManager, e = t.getConfig().piercer;
3541
3539
  t.updateConfig({
3542
3540
  piercer: {
3543
3541
  ...e,
@@ -3548,15 +3546,16 @@ class V {
3548
3546
  },
3549
3547
  {
3550
3548
  id: "offscreen_radar",
3549
+ isAvailable: ({ config: t }) => !t.core.hasOffscreenIndicators,
3551
3550
  titleKey: "pu_offscreen_radar_title",
3552
3551
  descKey: "pu_offscreen_radar_desc",
3553
3552
  badge: "RADAR",
3554
3553
  category: "defense",
3555
3554
  rarity: "legendary",
3556
3555
  rarityWeight: 5,
3557
- color: f.core,
3556
+ color: E.core,
3558
3557
  apply: () => {
3559
- const t = v.getInstance(), e = t.getConfig().core;
3558
+ const t = this.configManager, e = t.getConfig().core;
3560
3559
  t.updateConfig({
3561
3560
  core: {
3562
3561
  ...e,
@@ -3567,15 +3566,16 @@ class V {
3567
3566
  },
3568
3567
  {
3569
3568
  id: "piercer_homing_target",
3569
+ isAvailable: ({ config: t }) => t.piercer.hasHoming,
3570
3570
  titleKey: "pu_piercer_homing_target_title",
3571
3571
  descKey: "pu_piercer_homing_target_desc",
3572
3572
  badge: "+1 TARGET",
3573
3573
  category: "power",
3574
3574
  rarity: "epic",
3575
3575
  rarityWeight: 15,
3576
- color: f.piercer,
3576
+ color: E.piercer,
3577
3577
  apply: () => {
3578
- const t = v.getInstance(), e = t.getConfig().piercer;
3578
+ const t = this.configManager, e = t.getConfig().piercer;
3579
3579
  t.updateConfig({
3580
3580
  piercer: {
3581
3581
  ...e,
@@ -3586,15 +3586,16 @@ class V {
3586
3586
  },
3587
3587
  {
3588
3588
  id: "vampirism_unlock",
3589
+ isAvailable: ({ config: t }) => t.core.vampirismHealProgressRate <= 0,
3589
3590
  titleKey: "pu_vampirism_unlock_title",
3590
3591
  descKey: "pu_vampirism_unlock_desc",
3591
3592
  badge: "+0.5% REPAIR",
3592
3593
  category: "defense",
3593
3594
  rarity: "epic",
3594
3595
  rarityWeight: 15,
3595
- color: f.core,
3596
+ color: E.core,
3596
3597
  apply: () => {
3597
- const t = v.getInstance(), e = t.getConfig().core;
3598
+ const t = this.configManager, e = t.getConfig().core;
3598
3599
  t.updateConfig({
3599
3600
  core: {
3600
3601
  ...e,
@@ -3605,15 +3606,16 @@ class V {
3605
3606
  },
3606
3607
  {
3607
3608
  id: "vampirism_boost",
3609
+ isAvailable: ({ config: t }) => t.core.vampirismHealProgressRate > 0,
3608
3610
  titleKey: "pu_vampirism_boost_title",
3609
3611
  descKey: "pu_vampirism_boost_desc",
3610
3612
  badge: "+0.3% HEAL",
3611
3613
  category: "defense",
3612
3614
  rarity: "rare",
3613
3615
  rarityWeight: 25,
3614
- color: f.core,
3616
+ color: E.core,
3615
3617
  apply: () => {
3616
- const t = v.getInstance(), e = t.getConfig().core;
3618
+ const t = this.configManager, e = t.getConfig().core;
3617
3619
  t.updateConfig({
3618
3620
  core: {
3619
3621
  ...e,
@@ -3630,9 +3632,9 @@ class V {
3630
3632
  category: "defense",
3631
3633
  rarity: "rare",
3632
3634
  rarityWeight: 20,
3633
- color: f.core,
3635
+ color: E.core,
3634
3636
  apply: (t) => {
3635
- v.getInstance().addCoreRing(1), t && t.addMaxRing(1);
3637
+ this.configManager.addCoreRing(1), t && t.addMaxRing(1);
3636
3638
  }
3637
3639
  },
3638
3640
  {
@@ -3643,9 +3645,9 @@ class V {
3643
3645
  category: "magnet",
3644
3646
  rarity: "common",
3645
3647
  rarityWeight: 35,
3646
- color: f.core,
3648
+ color: E.core,
3647
3649
  apply: () => {
3648
- const t = v.getInstance(), e = t.getConfig().magnet;
3650
+ const t = this.configManager, e = t.getConfig().magnet;
3649
3651
  t.updateConfig({
3650
3652
  magnet: {
3651
3653
  ...e,
@@ -3662,9 +3664,9 @@ class V {
3662
3664
  category: "magnet",
3663
3665
  rarity: "rare",
3664
3666
  rarityWeight: 25,
3665
- color: f.core,
3667
+ color: E.core,
3666
3668
  apply: () => {
3667
- const t = v.getInstance(), e = t.getConfig().magnet;
3669
+ const t = this.configManager, e = t.getConfig().magnet;
3668
3670
  t.updateConfig({
3669
3671
  magnet: {
3670
3672
  ...e,
@@ -3674,26 +3676,32 @@ class V {
3674
3676
  }
3675
3677
  }
3676
3678
  ];
3677
- static getRandomOptions(t = 3) {
3678
- const e = v.getInstance().getConfig(), i = this.powerUps.filter((a) => !(a.id === "vampirism_unlock" && e.core.vampirismHealProgressRate > 0 || a.id === "vampirism_boost" && e.core.vampirismHealProgressRate <= 0 || a.id === "piercer_homing" && e.piercer.hasHoming || a.id === "piercer_homing_target" && !e.piercer.hasHoming || a.id === "vortex_pocket" && e.gravityVortex.hasImplosionLaunch || a.id === "shield_fan" && e.shield.isFanBlast || a.id === "shield_fan_upgrade" && (!e.shield.isFanBlast || e.shield.hasFanBlastUpgrade) || a.id === "cluster_homing" && e.cluster.hasHoming || a.id === "offscreen_radar" && e.core.hasOffscreenIndicators)), s = [];
3679
+ getDefinitions() {
3680
+ return this.defaultsRegistered || (this.registry.registerMany(this.defaultPowerUps), this.defaultsRegistered = !0), this.registry.values();
3681
+ }
3682
+ getAll() {
3683
+ return this.getDefinitions();
3684
+ }
3685
+ getRandomOptions(t = 3) {
3686
+ const e = this.configManager.getConfig(), i = this.getDefinitions().filter((a) => a.isAvailable?.({ config: e }) ?? !0), s = [];
3679
3687
  for (let a = 0; a < t && i.length > 0; a++) {
3680
- const r = i.reduce((n, l) => n + l.rarityWeight, 0);
3681
- let o = Math.random() * r;
3682
- for (let n = 0; n < i.length; n++) {
3683
- const l = i[n];
3684
- if (o -= l.rarityWeight, o <= 0) {
3685
- s.push(l), i.splice(n, 1);
3688
+ const n = i.reduce((r, c) => r + c.rarityWeight, 0);
3689
+ let o = Math.random() * n;
3690
+ for (let r = 0; r < i.length; r++) {
3691
+ const c = i[r];
3692
+ if (o -= c.rarityWeight, o <= 0) {
3693
+ s.push(c), i.splice(r, 1);
3686
3694
  break;
3687
3695
  }
3688
3696
  }
3689
3697
  }
3690
3698
  return s;
3691
3699
  }
3692
- static registerPowerUp(t) {
3693
- this.powerUps.push(t);
3700
+ registerPowerUp(t) {
3701
+ this.getDefinitions(), this.registry.register(t);
3694
3702
  }
3695
3703
  }
3696
- class St {
3704
+ class Ot {
3697
3705
  haptics = {
3698
3706
  impact: async (t) => {
3699
3707
  if ("vibrate" in navigator) {
@@ -3733,7 +3741,562 @@ class St {
3733
3741
  }
3734
3742
  };
3735
3743
  }
3736
- class Mt {
3744
+ class Dt {
3745
+ enemies = new P("enemy");
3746
+ variants = new P("enemy variant");
3747
+ powerUps = new P("power-up");
3748
+ synergies = new P("synergy");
3749
+ areas = new P("area");
3750
+ bosses = new P("boss");
3751
+ bossRewards = new P("boss reward");
3752
+ cores = new P("core");
3753
+ spawnerPatterns = new P("spawner pattern");
3754
+ tutorial;
3755
+ constructor(t = {}) {
3756
+ this.tutorial = t.tutorial, this.enemies.registerMany(t.enemies ?? []), this.variants.registerMany(t.variants ?? []), this.powerUps.registerMany(t.powerUps ?? []), this.synergies.registerMany(t.synergies ?? []), this.areas.registerMany(t.areas ?? []), this.bosses.registerMany(t.bosses ?? []), this.bossRewards.registerMany(t.bossRewards ?? []), this.cores.registerMany(t.cores ?? []), this.spawnerPatterns.registerMany(t.spawnerPatterns ?? []);
3757
+ }
3758
+ /** Validate references once a complete catalog has been assembled. */
3759
+ validate() {
3760
+ for (const t of this.variants.values())
3761
+ this.enemies.require(t.baseEnemyId);
3762
+ for (const t of this.areas.values()) {
3763
+ for (const e of [...t.baseEnemyIds, ...t.additionalEnemyIds])
3764
+ this.enemies.require(e);
3765
+ t.bossId && this.bosses.require(t.bossId);
3766
+ }
3767
+ for (const t of this.bosses.values())
3768
+ t.areaId && this.areas.require(t.areaId), t.rewardId && this.bossRewards.require(t.rewardId);
3769
+ for (const t of this.bossRewards.values())
3770
+ for (const e of t.temporaryPowerUpIds)
3771
+ this.powerUps.require(e);
3772
+ for (const t of this.spawnerPatterns.values()) {
3773
+ if (t.enemyIds.length === 0) throw new Error(`Spawner pattern "${t.id}" has no enemy IDs`);
3774
+ for (const e of t.enemyIds) this.enemies.require(e);
3775
+ }
3776
+ this.tutorial && (this.enemies.require(this.tutorial.launcherEnemyId), this.enemies.require(this.tutorial.targetEnemyId));
3777
+ }
3778
+ }
3779
+ class Nt {
3780
+ execute(t) {
3781
+ const { thrownEnemy: e, targetEnemy: i, allEnemies: s, shockwaves: a, particles: n, floatingTexts: o } = t, r = i.position;
3782
+ e.experienceDropPending = !0, i.experienceDropPending = !0, e.active = !1, i.active = !1;
3783
+ const c = t.config, l = c.cluster.fragmentCount, h = c.cluster.hasHoming;
3784
+ a.length < c.cluster.maxExplosionShockwaves && a.push({
3785
+ id: Math.random().toString(),
3786
+ position: { ...r },
3787
+ radius: 15,
3788
+ maxRadius: 280,
3789
+ color: E.cluster,
3790
+ alpha: 1,
3791
+ lifetime: 0,
3792
+ maxLifetime: 0.6
3793
+ });
3794
+ for (let d = 0; d < l; d++) {
3795
+ const g = d * Math.PI * 2 / l, b = 800 + Math.random() * 300, f = {
3796
+ x: r.x + Math.cos(g) * 45,
3797
+ y: r.y + Math.sin(g) * 45
3798
+ };
3799
+ let _ = g;
3800
+ if (h) {
3801
+ let m = null, v = 1 / 0;
3802
+ for (const A of s) {
3803
+ if (A === e || A === i || !A.active || A.isGrabbed || A.isDying) continue;
3804
+ const S = Math.hypot(A.position.x - f.x, A.position.y - f.y);
3805
+ S < v && (v = S, m = A);
3806
+ }
3807
+ m && (_ = Math.atan2(m.position.y - f.y, m.position.x - f.x));
3808
+ }
3809
+ const x = e.behavior.spawnedEnemyIds?.[0];
3810
+ if (!x) continue;
3811
+ const y = t.factory.createEnemy(x, f, {
3812
+ x: f.x + Math.cos(_) * 500,
3813
+ y: f.y + Math.sin(_) * 500
3814
+ });
3815
+ y.isThrown = !0, y.wasManipulated = !0, y.velocity = {
3816
+ x: Math.cos(_) * b,
3817
+ y: Math.sin(_) * b
3818
+ }, s.push(y);
3819
+ }
3820
+ const u = Math.min(
3821
+ c.cluster.explosionParticleCount,
3822
+ Math.max(0, 96 - n.length)
3823
+ );
3824
+ for (let d = 0; d < u; d++) {
3825
+ const g = Math.random() * Math.PI * 2, b = 200 + Math.random() * 300;
3826
+ n.push({
3827
+ id: Math.random().toString(),
3828
+ position: { ...r },
3829
+ velocity: { x: Math.cos(g) * b, y: Math.sin(g) * b },
3830
+ color: E.cluster,
3831
+ radius: 4 + Math.random() * 4,
3832
+ alpha: 1,
3833
+ lifetime: 0,
3834
+ maxLifetime: 0.6
3835
+ });
3836
+ }
3837
+ o.length < c.cluster.maxExplosionFloatingTexts && o.push({
3838
+ id: Math.random().toString(),
3839
+ text: "CLUSTER DETONATION",
3840
+ position: { ...r },
3841
+ velocity: { x: 0, y: -60 },
3842
+ color: E.cluster,
3843
+ alpha: 1,
3844
+ lifetime: 0,
3845
+ maxLifetime: 1,
3846
+ size: 24
3847
+ });
3848
+ }
3849
+ }
3850
+ class kt {
3851
+ execute(t) {
3852
+ const { thrownEnemy: e, targetEnemy: i, vortices: s, shockwaves: a } = t, n = t.config, o = {
3853
+ x: (e.position.x + i.position.x) / 2,
3854
+ y: (e.position.y + i.position.y) / 2
3855
+ };
3856
+ s.push({
3857
+ id: Math.random().toString(),
3858
+ position: o,
3859
+ radius: Math.round(n.gravityVortex.baseRadius * 2.2),
3860
+ duration: 0,
3861
+ maxDuration: n.gravityVortex.baseDuration * 1.5,
3862
+ pullForce: n.gravityVortex.basePullForce * 1.6
3863
+ }), a.push({
3864
+ id: Math.random().toString(),
3865
+ position: o,
3866
+ radius: 20,
3867
+ maxRadius: Math.round(n.gravityVortex.baseRadius * 2.2),
3868
+ color: E.parasite,
3869
+ alpha: 1,
3870
+ lifetime: 0,
3871
+ maxLifetime: 0.65
3872
+ }), e.triggerDissolveDeath(!0), i.triggerDissolveDeath(!0);
3873
+ }
3874
+ }
3875
+ class Ut {
3876
+ execute(t) {
3877
+ const { thrownEnemy: e, targetEnemy: i, allEnemies: s, shockwaves: a, particles: n, floatingTexts: o } = t, r = i.position.x - e.position.x, c = i.position.y - e.position.y, l = Math.atan2(c, r), h = t.config.shield, u = h.blastSpeed || 1400, d = h.isFanBlast ? [0, -h.fanBlastAngle, h.fanBlastAngle] : [0];
3878
+ for (const [g, b] of d.entries()) {
3879
+ const f = l + b, _ = g === 0 ? e : t.factory.createEnemy(
3880
+ e.type,
3881
+ {
3882
+ x: e.position.x + Math.cos(f) * 30,
3883
+ y: e.position.y + Math.sin(f) * 30
3884
+ },
3885
+ { x: 0, y: 0 }
3886
+ );
3887
+ _.isStationaryShield = !1, _.isThrown = !0, _.wasManipulated = !0, _.shieldAngle = f, _.rotation = f, _.launchDelay = h.isFanBlast ? g * h.fanBlastInterval : 0, _.velocity = {
3888
+ x: Math.cos(f) * u,
3889
+ y: Math.sin(f) * u
3890
+ }, _ !== e && s.push(_);
3891
+ }
3892
+ i.active = !1, i.triggerDissolveDeath(!0), o.push({
3893
+ id: Math.random().toString(),
3894
+ text: "ARC BLAST!",
3895
+ position: { ...e.position },
3896
+ velocity: { x: 0, y: -50 },
3897
+ color: E.heavy,
3898
+ alpha: 1,
3899
+ lifetime: 0,
3900
+ maxLifetime: 0.9,
3901
+ size: 24
3902
+ });
3903
+ for (let g = 0; g < 50; g++) {
3904
+ const b = (Math.random() - 0.5) * 1.5, f = l + b, _ = 300 + Math.random() * 500;
3905
+ n.push({
3906
+ id: Math.random().toString(),
3907
+ position: { ...e.position },
3908
+ velocity: { x: Math.cos(f) * _, y: Math.sin(f) * _ },
3909
+ color: E.heavy,
3910
+ radius: 4 + Math.random() * 6,
3911
+ alpha: 1,
3912
+ lifetime: 0,
3913
+ maxLifetime: 0.7
3914
+ });
3915
+ }
3916
+ o.push({
3917
+ id: Math.random().toString(),
3918
+ text: "ARC BLAST!",
3919
+ position: { ...e.position },
3920
+ velocity: { x: 0, y: -50 },
3921
+ color: E.heavy,
3922
+ alpha: 1,
3923
+ lifetime: 0,
3924
+ maxLifetime: 0.9,
3925
+ size: 24
3926
+ });
3927
+ }
3928
+ }
3929
+ class Gt {
3930
+ execute(t) {
3931
+ const { thrownEnemy: e, targetEnemy: i, shockwaves: s, particles: a, floatingTexts: n } = t;
3932
+ i.experienceDropPending = !0, i.active = !1, s.push({
3933
+ id: Math.random().toString(),
3934
+ position: { ...i.position },
3935
+ radius: 10,
3936
+ maxRadius: 180,
3937
+ color: E.piercer,
3938
+ alpha: 1,
3939
+ lifetime: 0,
3940
+ maxLifetime: 0.5
3941
+ });
3942
+ for (let o = 0; o < 30; o++) {
3943
+ const r = Math.random() * Math.PI * 2, c = 180 + Math.random() * 320;
3944
+ a.push({
3945
+ id: Math.random().toString(),
3946
+ position: { ...i.position },
3947
+ velocity: { x: Math.cos(r) * c, y: Math.sin(r) * c },
3948
+ color: E.piercer,
3949
+ radius: 3 + Math.random() * 4,
3950
+ alpha: 1,
3951
+ lifetime: 0,
3952
+ maxLifetime: 0.5
3953
+ });
3954
+ }
3955
+ n.push({
3956
+ id: Math.random().toString(),
3957
+ text: "PIERCING SLICE",
3958
+ position: { ...i.position },
3959
+ velocity: { x: 0, y: -50 },
3960
+ color: E.piercer,
3961
+ alpha: 1,
3962
+ lifetime: 0,
3963
+ maxLifetime: 0.8,
3964
+ size: 20
3965
+ });
3966
+ }
3967
+ }
3968
+ class Bt {
3969
+ execute(t) {
3970
+ const { thrownEnemy: e, pools: i, shockwaves: s, particles: a, floatingTexts: n, eventBus: o } = t, r = e.position, c = t.config;
3971
+ i.push({
3972
+ id: Math.random().toString(),
3973
+ position: { ...r },
3974
+ radius: Math.round(c.toxicPool.baseRadius * 2),
3975
+ duration: 0,
3976
+ maxDuration: c.toxicPool.baseDuration * 1.5,
3977
+ damage: c.toxicPool.damage
3978
+ }), s.push({
3979
+ id: Math.random().toString(),
3980
+ position: { ...r },
3981
+ radius: 10,
3982
+ maxRadius: Math.round(c.toxicPool.baseRadius * 2.2),
3983
+ color: E.spore,
3984
+ alpha: 1,
3985
+ lifetime: 0,
3986
+ maxLifetime: 0.6
3987
+ });
3988
+ for (let l = 0; l < 45; l++) {
3989
+ const h = Math.random() * Math.PI * 2, u = 120 + Math.random() * 260;
3990
+ a.push({
3991
+ id: Math.random().toString(),
3992
+ position: { ...r },
3993
+ velocity: { x: Math.cos(h) * u, y: Math.sin(h) * u },
3994
+ color: E.spore,
3995
+ radius: 4 + Math.random() * 5,
3996
+ alpha: 1,
3997
+ lifetime: 0,
3998
+ maxLifetime: 0.9
3999
+ });
4000
+ }
4001
+ n.push({
4002
+ id: Math.random().toString(),
4003
+ text: "MASSIVE SPORE NEBULA",
4004
+ position: { ...r },
4005
+ velocity: { x: 0, y: -60 },
4006
+ color: E.spore,
4007
+ alpha: 1,
4008
+ lifetime: 0,
4009
+ maxLifetime: 1.2,
4010
+ size: 26
4011
+ }), e.experienceDropPending = !0, e.active = !1, o.emit("onPoolCreated", { position: r });
4012
+ }
4013
+ }
4014
+ const W = (p, t, e = []) => {
4015
+ let i = null, s = 1 / 0;
4016
+ for (const a of t) {
4017
+ if (a === p || e.includes(a) || !a.active || a.isGrabbed || a.isDying) continue;
4018
+ const n = Math.hypot(a.position.x - p.position.x, a.position.y - p.position.y);
4019
+ n < s && (s = n, i = a);
4020
+ }
4021
+ return i;
4022
+ }, Y = (p, t, e, i, s = t.color) => {
4023
+ p.shockwaves.push({
4024
+ id: Math.random().toString(),
4025
+ position: { ...t.position },
4026
+ radius: 10,
4027
+ maxRadius: e,
4028
+ color: s,
4029
+ alpha: 1,
4030
+ lifetime: 0,
4031
+ maxLifetime: i
4032
+ });
4033
+ }, et = (p, t, e, i = t.color) => {
4034
+ for (let s = 0; s < e; s++) {
4035
+ const a = Math.random() * Math.PI * 2, n = 180 + Math.random() * 320;
4036
+ p.particles.push({
4037
+ id: Math.random().toString(),
4038
+ position: { ...t.position },
4039
+ velocity: { x: Math.cos(a) * n, y: Math.sin(a) * n },
4040
+ color: i,
4041
+ radius: 3 + Math.random() * 4,
4042
+ alpha: 1,
4043
+ lifetime: 0,
4044
+ maxLifetime: 0.5
4045
+ });
4046
+ }
4047
+ }, Ht = (p, t) => {
4048
+ p.shieldAngle = p.rotation, p.velocity = { x: 0, y: 0 }, p.isStationaryShield = !0, p.isThrown = !1;
4049
+ }, Kt = (p, t) => {
4050
+ t.config.piercer.hasHoming && (p.remainingHomingKills = t.config.piercer.homingTargets);
4051
+ }, Ft = (p, t) => {
4052
+ if (!p.isThrown || !t.config.piercer.hasHoming || p.remainingHomingKills <= 0) return;
4053
+ const e = W(p, t.enemies);
4054
+ if (!e) return;
4055
+ const i = Math.atan2(e.position.y - p.position.y, e.position.x - p.position.x), s = Math.max(Math.hypot(p.velocity.x, p.velocity.y), 1e3), a = Math.atan2(p.velocity.y, p.velocity.x);
4056
+ let n = i - a;
4057
+ for (; n < -Math.PI; ) n += Math.PI * 2;
4058
+ for (; n > Math.PI; ) n -= Math.PI * 2;
4059
+ const o = a + Math.sign(n) * Math.min(Math.abs(n), 25 * t.dt);
4060
+ p.rotation = o, p.velocity = { x: Math.cos(o) * s, y: Math.sin(o) * s };
4061
+ }, Vt = (p, t) => {
4062
+ Y(t, p, 350, 0.6), et(t, p, 40);
4063
+ }, Wt = (p, t) => {
4064
+ const e = t.config.piercer.terminalAoERadius;
4065
+ if (!(e <= 0)) {
4066
+ Y(t, p, e, 0.6);
4067
+ for (const i of t.spatialHash.getNearby(p.position, e)) {
4068
+ if (!i.active || i.isGrabbed || i.isDying) continue;
4069
+ const s = i.position.x - p.position.x, a = i.position.y - p.position.y;
4070
+ s * s + a * a <= e * e && t.killEnemy(i, Math.atan2(a, s));
4071
+ }
4072
+ }
4073
+ }, Yt = (p) => {
4074
+ const { thrownEnemy: t, targetEnemy: e } = p;
4075
+ return t.strategy ? (t.strategy.execute({
4076
+ thrownEnemy: t,
4077
+ targetEnemy: e,
4078
+ allEnemies: p.enemies,
4079
+ pools: p.pools,
4080
+ vortices: p.vortices,
4081
+ shockwaves: p.shockwaves,
4082
+ particles: p.particles,
4083
+ floatingTexts: p.floatingTexts,
4084
+ eventBus: p.eventBus,
4085
+ width: p.width,
4086
+ height: p.height,
4087
+ factory: p.factory,
4088
+ config: p.config
4089
+ }), !t.behavior.continuesThroughTargets && t.active && !t.isDying && t.triggerDissolveDeath(!0), e.active && !e.isDying && e.triggerDissolveDeath(!0), p.currentThrowState.kills += t.behavior.continuesThroughTargets ? 1 : 2, p.onKill?.(), !0) : !1;
4090
+ }, $t = (p) => (p.killEnemy(p.targetEnemy, p.thrownEnemy.rotation), p.thrownEnemy.active && !p.thrownEnemy.isDying && p.thrownEnemy.triggerDissolveDeath(!0), p.currentThrowState.kills += 1, p.juice.triggerHitstop(0.04), p.juice.triggerScreenShake({
4091
+ x: p.targetEnemy.position.x - p.thrownEnemy.position.x,
4092
+ y: p.targetEnemy.position.y - p.thrownEnemy.position.y
4093
+ }, 8), p.onKill(), !0), Zt = (p) => {
4094
+ if (p.killEnemy(p.targetEnemy, p.impactAngle), !Yt(p)) return !1;
4095
+ const { thrownEnemy: t, targetEnemy: e } = p;
4096
+ if (p.juice.triggerHitstop(0.05), p.juice.triggerScreenShake({
4097
+ x: e.position.x - t.position.x,
4098
+ y: e.position.y - t.position.y
4099
+ }, 7), Y(p, e, 180, 0.45), et(p, e, 16), t.remainingHomingKills > 0) {
4100
+ t.remainingHomingKills--;
4101
+ const i = W(t, p.enemies, [e]);
4102
+ if (i) {
4103
+ const s = Math.atan2(i.position.y - t.position.y, i.position.x - t.position.x), a = Math.hypot(t.velocity.x, t.velocity.y) || 1200;
4104
+ t.rotation = s, t.velocity = { x: Math.cos(s) * a, y: Math.sin(s) * a };
4105
+ }
4106
+ }
4107
+ return !0;
4108
+ }, zt = (p) => {
4109
+ p.enemy.triggerDissolveDeath(!0);
4110
+ const t = p.config.toxicPool;
4111
+ p.pools.push({
4112
+ id: Math.random().toString(),
4113
+ position: { ...p.enemy.position },
4114
+ radius: t.baseRadius,
4115
+ duration: 0,
4116
+ maxDuration: t.baseDuration,
4117
+ damage: t.damage
4118
+ });
4119
+ }, Xt = (p) => {
4120
+ p.enemy.triggerDissolveDeath(!0);
4121
+ const t = p.config.cluster, e = p.enemy.behavior.spawnedEnemyIds?.[0];
4122
+ if (e)
4123
+ for (let i = 0; i < t.fragmentCount; i++) {
4124
+ const s = i * Math.PI * 2 / t.fragmentCount, a = {
4125
+ x: p.enemy.position.x + Math.cos(s) * 40,
4126
+ y: p.enemy.position.y + Math.sin(s) * 40
4127
+ };
4128
+ let n = s;
4129
+ if (t.hasHoming) {
4130
+ const r = W(p.enemy, p.enemies);
4131
+ r && (n = Math.atan2(r.position.y - a.y, r.position.x - a.x));
4132
+ }
4133
+ const o = p.factory.createEnemy(e, a, {
4134
+ x: a.x + Math.cos(n) * 500,
4135
+ y: a.y + Math.sin(n) * 500
4136
+ });
4137
+ o.isThrown = !0, o.wasManipulated = !0, o.velocity = { x: Math.cos(n) * (750 + Math.random() * 250), y: Math.sin(n) * (750 + Math.random() * 250) }, p.enemies.push(o);
4138
+ }
4139
+ }, Jt = (p) => {
4140
+ p.enemy.triggerDissolveDeath(!0);
4141
+ const t = p.config.gravityVortex;
4142
+ p.vortices.push({
4143
+ id: Math.random().toString(),
4144
+ position: { ...p.enemy.position },
4145
+ radius: t.baseRadius,
4146
+ duration: 0,
4147
+ maxDuration: t.baseDuration,
4148
+ pullForce: t.basePullForce
4149
+ });
4150
+ }, jt = (p) => {
4151
+ p.enemy.triggerSliceDeath(p.angle, !0);
4152
+ }, qt = (p, t) => t !== "toxic-pool" && t !== "gravity-vortex", Qt = {
4153
+ piercer: {
4154
+ rendererId: "piercer",
4155
+ rotatesWithVelocity: !0,
4156
+ canBeChainReactionTarget: !0,
4157
+ continuesThroughTargets: !0,
4158
+ onRelease: Kt,
4159
+ onThrownUpdate: Ft,
4160
+ onOutOfBounds: Wt,
4161
+ onCollision: Zt,
4162
+ onChainReaction: jt,
4163
+ canInteractWithHazard: qt,
4164
+ synergyKey: (p) => p.color
4165
+ },
4166
+ spore: {
4167
+ rendererId: "spore",
4168
+ rotatesWithVelocity: !0,
4169
+ canBeChainReactionTarget: !0,
4170
+ onChainReaction: zt,
4171
+ synergyKey: (p) => p.color
4172
+ },
4173
+ cluster: {
4174
+ rendererId: "cluster",
4175
+ rotatesWithVelocity: !0,
4176
+ canBeChainReactionTarget: !0,
4177
+ onChainReaction: Xt,
4178
+ spawnedEnemyIds: ["micro"],
4179
+ synergyKey: (p) => p.color
4180
+ },
4181
+ parasite: {
4182
+ rendererId: "parasite",
4183
+ rotatesWithVelocity: !0,
4184
+ canBeChainReactionTarget: !0,
4185
+ onChainReaction: Jt,
4186
+ synergyKey: (p) => p.color
4187
+ },
4188
+ heavy: {
4189
+ rendererId: "heavy",
4190
+ rotatesWithVelocity: !1,
4191
+ canBeChainReactionTarget: !0,
4192
+ onRelease: Ht,
4193
+ onOutOfBounds: Vt,
4194
+ onCollision: $t,
4195
+ synergyKey: (p) => p.color
4196
+ },
4197
+ micro: {
4198
+ rendererId: "circle",
4199
+ rotatesWithVelocity: !0,
4200
+ canBeChainReactionTarget: !1,
4201
+ autoDeflectFromCore: !0,
4202
+ synergyKey: (p) => p.color
4203
+ }
4204
+ }, D = (p) => Qt[p] ?? {
4205
+ rendererId: "circle",
4206
+ rotatesWithVelocity: !0,
4207
+ canBeChainReactionTarget: !0,
4208
+ synergyKey: (t) => t.color
4209
+ }, te = [
4210
+ {
4211
+ id: "piercer",
4212
+ speed: 95,
4213
+ maxSpeed: 140,
4214
+ radius: 18,
4215
+ color: E.piercer,
4216
+ canBeGrabbed: !0,
4217
+ initialRotation: "none",
4218
+ impactStrategyFactory: () => new Gt(),
4219
+ behavior: D("piercer"),
4220
+ spawnWeight: 0.2,
4221
+ ambientSpawn: !0
4222
+ },
4223
+ {
4224
+ id: "spore",
4225
+ speed: 65,
4226
+ maxSpeed: 90,
4227
+ radius: 24,
4228
+ color: E.spore,
4229
+ canBeGrabbed: !0,
4230
+ initialRotation: "none",
4231
+ impactStrategyFactory: () => new Bt(),
4232
+ behavior: D("spore"),
4233
+ spawnWeight: 0.2,
4234
+ ambientSpawn: !0
4235
+ },
4236
+ {
4237
+ id: "cluster",
4238
+ speed: 50,
4239
+ maxSpeed: 75,
4240
+ radius: 26,
4241
+ color: E.cluster,
4242
+ canBeGrabbed: !0,
4243
+ initialRotation: "none",
4244
+ impactStrategyFactory: () => new Nt(),
4245
+ behavior: D("cluster"),
4246
+ spawnWeight: 0.2,
4247
+ ambientSpawn: !0
4248
+ },
4249
+ {
4250
+ id: "parasite",
4251
+ speed: 80,
4252
+ maxSpeed: 110,
4253
+ radius: 22,
4254
+ color: E.parasite,
4255
+ canBeGrabbed: !0,
4256
+ initialRotation: "none",
4257
+ impactStrategyFactory: () => new kt(),
4258
+ behavior: D("parasite"),
4259
+ spawnWeight: 0.2,
4260
+ ambientSpawn: !0
4261
+ },
4262
+ {
4263
+ id: "heavy",
4264
+ speed: 35,
4265
+ maxSpeed: 50,
4266
+ radius: 34,
4267
+ color: E.heavy,
4268
+ canBeGrabbed: !0,
4269
+ initialRotation: "random",
4270
+ impactStrategyFactory: () => new Ut(),
4271
+ behavior: D("heavy"),
4272
+ spawnWeight: 0.2,
4273
+ ambientSpawn: !0
4274
+ },
4275
+ {
4276
+ id: "micro",
4277
+ speed: 130,
4278
+ maxSpeed: 160,
4279
+ radius: 12,
4280
+ color: E.micro,
4281
+ canBeGrabbed: !1,
4282
+ initialRotation: "none",
4283
+ behavior: D("micro"),
4284
+ spawnWeight: 0,
4285
+ ambientSpawn: !1
4286
+ }
4287
+ ], ee = new Dt({
4288
+ enemies: te,
4289
+ spawnerPatterns: [
4290
+ { id: "circle", algorithmId: "circle", enemyIds: ["piercer", "spore", "cluster", "parasite"], weight: 1 },
4291
+ { id: "dense", algorithmId: "dense", enemyIds: ["spore"], weight: 1 },
4292
+ { id: "sine", algorithmId: "sine", enemyIds: ["cluster"], weight: 1 },
4293
+ { id: "marching", algorithmId: "marching", enemyIds: ["piercer"], weight: 1 },
4294
+ { id: "spiral", algorithmId: "spiral", enemyIds: ["parasite"], weight: 0.5 },
4295
+ { id: "crossfire", algorithmId: "crossfire", enemyIds: ["spore", "cluster"], weight: 0.5 }
4296
+ ],
4297
+ tutorial: { launcherEnemyId: "piercer", targetEnemyId: "spore" }
4298
+ });
4299
+ class ie {
3737
4300
  enabled;
3738
4301
  overlay;
3739
4302
  copyButton;
@@ -3851,7 +4414,7 @@ HEAP ${(t.usedJSHeapSize / 1024 / 1024).toFixed(1)} MB` : "";
3851
4414
  `), this.overlay.textContent = this.lastReport;
3852
4415
  }
3853
4416
  }
3854
- class Tt {
4417
+ class se {
3855
4418
  container;
3856
4419
  canvas;
3857
4420
  i18n;
@@ -3871,6 +4434,10 @@ class Tt {
3871
4434
  tutorialOverlay;
3872
4435
  progressBar;
3873
4436
  performanceAudit;
4437
+ content = ee;
4438
+ entityFactory;
4439
+ configManager = new N();
4440
+ powerUpRegistry = new wt(this.configManager);
3874
4441
  core;
3875
4442
  enemies = [];
3876
4443
  ambientEnemies = [];
@@ -3891,24 +4458,27 @@ class Tt {
3891
4458
  isRunning = !1;
3892
4459
  isPaused = !1;
3893
4460
  constructor(t) {
3894
- this.container = t.root, this.container.classList.add("axon-game-root"), this.i18n = new j(t.language), this.themeManager = new ut(t.theme, this.container), this.platform = t.platform || new St(), 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 Y(), this.core = new $(this.canvas.width / 2, this.canvas.height / 2), this.inputManager = new z(this.canvas), this.physicsEngine = new lt(this.eventBus, this.i18n), this.waveDirector = new ht(), this.renderer = new xt(this.canvas, this.themeManager), this.juice = new X(), this.settingsModal = new At(
4461
+ this.container = t.root, this.container.classList.add("axon-game-root"), this.i18n = new ct(t.language), this.themeManager = new yt(t.theme, this.container), this.platform = t.platform || new Ot(), 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 it(), this.entityFactory = new Rt(this.content), this.core = new at(this.canvas.width / 2, this.canvas.height / 2, this.configManager), this.inputManager = new ot(this.canvas, this.configManager), this.physicsEngine = new gt(this.eventBus, this.i18n, this.entityFactory, this.configManager), this.waveDirector = new _t(this.entityFactory, this.content), this.renderer = new Mt(this.canvas, this.themeManager, this.configManager), this.juice = new rt(), this.settingsModal = new Tt(
3895
4462
  this.container,
3896
4463
  this.i18n,
3897
4464
  this.themeManager,
3898
4465
  this.platform,
3899
- (e) => this.onLanguageChanged(e),
4466
+ (i) => this.onLanguageChanged(i),
3900
4467
  () => {
3901
4468
  this.isPaused = !1;
3902
4469
  },
3903
- (e) => {
3904
- this.gameLoop.setFpsLimit(e), this.performanceAudit.setFpsLimit(e);
4470
+ (i) => {
4471
+ this.gameLoop.setFpsLimit(i), this.performanceAudit.setFpsLimit(i);
3905
4472
  }
3906
- ), this.interactiveTutorial = new bt(), this.tutorialOverlay = new vt(this.container, this.i18n, this.interactiveTutorial), this.hud = new yt(this.container, this.i18n, () => {
4473
+ );
4474
+ const e = this.content.tutorial;
4475
+ if (!e) throw new Error("Content catalog must define tutorial enemy IDs");
4476
+ this.interactiveTutorial = new Lt(this.entityFactory, e.launcherEnemyId, e.targetEnemyId), this.tutorialOverlay = new Ct(this.container, this.i18n, this.interactiveTutorial), this.hud = new St(this.container, () => {
3907
4477
  this.isPaused = !0, this.settingsModal.show();
3908
- }), this.hud.show(), this.progressBar = new It(this.hud.progressSlot, (e) => {
3909
- this.waveDirector.wave = e, this.triggerLevelUp(e);
3910
- }), this.performanceAudit = new Mt(this.container, this.debugPerformanceEnabled), this.startMenu = new Et(this.container, this.i18n, () => this.startGame()), this.initAmbientArena(), this.gameLoop = new Z(
3911
- (e) => this.update(e),
4478
+ }), this.hud.show(), this.progressBar = new Pt((i) => {
4479
+ this.waveDirector.wave = i, this.triggerLevelUp(i);
4480
+ }), this.performanceAudit = new ie(this.container, this.debugPerformanceEnabled), this.startMenu = new It(this.container, this.i18n, () => this.startGame()), this.initAmbientArena(), this.gameLoop = new st(
4481
+ (i) => this.update(i),
3912
4482
  () => this.render()
3913
4483
  ), this.gameLoop.setFpsLimit(this.settingsModal.getFpsLimit()), this.performanceAudit.setFpsLimit(this.settingsModal.getFpsLimit()), this.setupEvents(), this.gameLoop.start();
3914
4484
  }
@@ -3925,18 +4495,17 @@ class Tt {
3925
4495
  return this.themeManager.getTheme();
3926
4496
  }
3927
4497
  onLanguageChanged(t) {
3928
- this.startMenu.renderContent(), this.hud.renderLabels(), this.tutorialOverlay.updateLanguage();
4498
+ this.startMenu.renderContent(), this.tutorialOverlay.updateLanguage();
3929
4499
  }
3930
4500
  initAmbientArena() {
3931
4501
  this.ambientEnemies = [];
3932
- const t = ["piercer", "spore", "cluster", "parasite"];
3933
- for (let e = 0; e < 16; e++) {
3934
- const i = e === 0 ? "heavy" : t[(e - 1) % t.length], s = e * Math.PI * 2 / 16, a = 180 + Math.random() * 220, r = {
4502
+ for (let t = 0; t < 16; t++) {
4503
+ const e = this.content.enemies.values().filter((r) => r.ambientSpawn).map((r) => r.id), i = e[t % e.length], s = t * Math.PI * 2 / 16, a = 180 + Math.random() * 220, n = {
3935
4504
  x: this.canvas.width / 2 + Math.cos(s) * a,
3936
4505
  y: this.canvas.height / 2 + Math.sin(s) * a
3937
- }, o = P.createEnemy(i, r, {
3938
- x: r.x + Math.sin(s) * 100,
3939
- y: r.y - Math.cos(s) * 100
4506
+ }, o = this.entityFactory.createEnemy(i, n, {
4507
+ x: n.x + Math.sin(s) * 100,
4508
+ y: n.y - Math.cos(s) * 100
3940
4509
  });
3941
4510
  this.ambientEnemies.push(o);
3942
4511
  }
@@ -3949,7 +4518,7 @@ class Tt {
3949
4518
  this.eventBus.on("onCoreDamaged", () => {
3950
4519
  this.settingsModal.isHapticsEnabled() && this.platform.haptics.notification("error");
3951
4520
  }), this.eventBus.on("onGameOver", () => {
3952
- this.isRunning = !1, this.experienceOrbs = [], this.pendingLevelUps = [], this.tutorialOverlay.hide(), this.progressBar.hide(), this.initAmbientArena(), this.startMenu.show();
4521
+ this.isRunning = !1, this.clearTransientRunState(), this.experienceOrbs = [], this.pendingLevelUps = [], this.tutorialOverlay.hide(), this.initAmbientArena(), this.startMenu.show();
3953
4522
  });
3954
4523
  const t = (i = !1) => {
3955
4524
  if (!this.isRunning || this.isPaused || this.isLevelUpActive) return;
@@ -3965,7 +4534,10 @@ class Tt {
3965
4534
  }), this.canvas.addEventListener("touchstart", () => t(!0), { passive: !0 }), this.canvas.addEventListener("touchend", e, { passive: !0 }), this.canvas.addEventListener("touchcancel", e, { passive: !0 });
3966
4535
  }
3967
4536
  startGame() {
3968
- v.getInstance().resetToDefault(), this.score.value = 0, this.combo.value = 0, this.enemies = [], this.ambientEnemies = [], this.pools = [], this.vortices = [], this.shockwaves = [], this.particles = [], this.floatingTexts = [], this.experienceOrbs = [], this.orbitingOrbs = [], this.isLevelUpActive = !1, this.pendingLevelUps = [], this.rerollsRemaining = this.getRerollLimit(), 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.interactiveTutorial.isTutorialEnabled() ? (this.interactiveTutorial.start(this.canvas.width, this.canvas.height, this.enemies), this.tutorialOverlay.show()) : (this.interactiveTutorial.isActive = !1, this.tutorialOverlay.hide());
4537
+ this.configManager.resetToDefault(), this.score.value = 0, this.combo.value = 0, this.clearTransientRunState(), this.enemies = [], this.ambientEnemies = [], this.experienceOrbs = [], this.orbitingOrbs = [], this.isLevelUpActive = !1, this.pendingLevelUps = [], this.rerollsRemaining = this.getRerollLimit(), this.core.reset(this.canvas.width / 2, this.canvas.height / 2), this.waveDirector.reset(), this.inputManager.reset(), this.hud.show(), this.hud.update(0), this.progressBar.reset(), this.isPaused = !1, this.isRunning = !0, this.interactiveTutorial.isTutorialEnabled() ? (this.interactiveTutorial.start(this.canvas.width, this.canvas.height, this.enemies), this.tutorialOverlay.show()) : (this.interactiveTutorial.isActive = !1, this.tutorialOverlay.hide());
4538
+ }
4539
+ clearTransientRunState() {
4540
+ this.enemies = [], this.pools = [], this.vortices = [], this.shockwaves = [], this.particles = [], this.floatingTexts = [], this.experienceOrbs = [], this.orbitingOrbs = [], this.pendingLevelUps = [], this.inputManager?.forceRelease();
3969
4541
  }
3970
4542
  update(t) {
3971
4543
  if (this.performanceAudit.beginFrame(), this.performanceAudit.setState(this.isRunning ? this.isPaused ? "PAUSED" : "GAME" : "MENU"), this.core.update(t), !this.isRunning || this.isPaused) {
@@ -4008,20 +4580,20 @@ class Tt {
4008
4580
  !this.inputManager.isPointerDown && i && (i.isGrabbed = !1, this.inputManager.grabbedOrb = null);
4009
4581
  const s = this.inputManager.pointerPosition;
4010
4582
  if (this.inputManager.isPointerDown && !this.inputManager.grabbedOrb && this.rerollsRemaining > 0) {
4011
- const a = this.canvas.width / 2, r = this.canvas.height / 2 + 210;
4012
- Math.hypot(s.x - a, s.y - r) <= 80 && (this.triggerReroll(), this.inputManager.isPointerDown = !1);
4583
+ const a = this.canvas.width / 2, n = this.canvas.height / 2 + 210;
4584
+ Math.hypot(s.x - a, s.y - n) <= 80 && (this.triggerReroll(), this.inputManager.isPointerDown = !1);
4013
4585
  }
4014
4586
  for (const a of this.orbitingOrbs) {
4015
- const r = s.x - a.position.x, o = s.y - a.position.y;
4016
- if (a.isHovered = Math.hypot(r, o) <= a.radius * 1.5, a === i && this.inputManager.isPointerDown) {
4587
+ const n = s.x - a.position.x, o = s.y - a.position.y;
4588
+ if (a.isHovered = Math.hypot(n, o) <= a.radius * 1.5, a === i && this.inputManager.isPointerDown) {
4017
4589
  a.position = { ...this.inputManager.pointerPosition };
4018
- const n = this.core.position.x - a.position.x, l = this.core.position.y - a.position.y;
4019
- if (Math.hypot(n, l) <= this.core.radius + a.radius) {
4020
- a.definition.apply(this.core), this.core.absorbPowerUpColor(a.definition.color, 0.4), this.juice.triggerFlash(0.8), this.juice.triggerScreenShake({ x: n, y: l }, 24);
4021
- const c = this.i18n.translate(a.definition.titleKey);
4590
+ const r = this.core.position.x - a.position.x, c = this.core.position.y - a.position.y;
4591
+ if (Math.hypot(r, c) <= this.core.radius + a.radius) {
4592
+ a.definition.apply(this.core), this.core.absorbPowerUpColor(a.definition.color, 0.4), this.juice.triggerFlash(0.8), this.juice.triggerScreenShake({ x: r, y: c }, 24);
4593
+ const h = this.i18n.translate(a.definition.titleKey);
4022
4594
  this.floatingTexts.push({
4023
4595
  id: Math.random().toString(),
4024
- text: `+ ${c}`,
4596
+ text: `+ ${h}`,
4025
4597
  position: { ...this.core.position },
4026
4598
  velocity: { x: 0, y: -80 },
4027
4599
  color: a.definition.color,
@@ -4030,12 +4602,12 @@ class Tt {
4030
4602
  maxLifetime: 1.6,
4031
4603
  size: 26
4032
4604
  });
4033
- for (let p = 0; p < 45; p++) {
4034
- const g = Math.random() * Math.PI * 2, _ = 200 + Math.random() * 400;
4605
+ for (let u = 0; u < 45; u++) {
4606
+ const d = Math.random() * Math.PI * 2, g = 200 + Math.random() * 400;
4035
4607
  this.particles.push({
4036
4608
  id: Math.random().toString(),
4037
4609
  position: { ...this.core.position },
4038
- velocity: { x: Math.cos(g) * _, y: Math.sin(g) * _ },
4610
+ velocity: { x: Math.cos(d) * g, y: Math.sin(d) * g },
4039
4611
  color: a.definition.color,
4040
4612
  radius: 4 + Math.random() * 5,
4041
4613
  alpha: 1,
@@ -4072,7 +4644,7 @@ class Tt {
4072
4644
  text: "RING RESTORED!",
4073
4645
  position: { ...this.core.position },
4074
4646
  velocity: { x: 0, y: -60 },
4075
- color: f.core,
4647
+ color: E.core,
4076
4648
  alpha: 1,
4077
4649
  lifetime: 0,
4078
4650
  maxLifetime: 1.2,
@@ -4081,7 +4653,7 @@ class Tt {
4081
4653
  }
4082
4654
  ), e = this.debugPerformanceEnabled ? performance.now() - i : 0;
4083
4655
  }
4084
- this.spawnExperienceDrops(), this.isLevelUpActive || this.updateExperienceOrbs(t), this.hud.update(this.progressBar.getLevel(), this.combo.value), this.juice.update(t, this.floatingTexts, this.particles), this.enemies = this.enemies.filter((i) => i.active), this.performanceAudit.finishUpdate(e, {
4656
+ this.spawnExperienceDrops(), this.isLevelUpActive || this.updateExperienceOrbs(t), this.progressBar.update(t), this.hud.update(this.combo.value), this.juice.update(t, this.floatingTexts, this.particles), this.enemies = this.enemies.filter((i) => i.active), this.performanceAudit.finishUpdate(e, {
4085
4657
  enemies: this.enemies.length,
4086
4658
  particles: this.particles.length,
4087
4659
  shockwaves: this.shockwaves.length,
@@ -4104,7 +4676,7 @@ class Tt {
4104
4676
  text: this.i18n.translate("levelUpChoose", { level: t }),
4105
4677
  position: { ...this.core.position },
4106
4678
  velocity: { x: 0, y: -100 },
4107
- color: f.core,
4679
+ color: E.core,
4108
4680
  alpha: 1,
4109
4681
  lifetime: 0,
4110
4682
  maxLifetime: 2,
@@ -4116,55 +4688,60 @@ class Tt {
4116
4688
  id: Math.random().toString(),
4117
4689
  position: { ...this.core.position },
4118
4690
  velocity: { x: Math.cos(s) * a, y: Math.sin(s) * a },
4119
- color: f.core,
4691
+ color: E.core,
4120
4692
  radius: 2 + Math.random() * 3,
4121
4693
  alpha: 1,
4122
4694
  lifetime: 0,
4123
4695
  maxLifetime: 0.7
4124
4696
  });
4125
4697
  }
4126
- const e = V.getRandomOptions(3);
4698
+ const e = this.powerUpRegistry.getRandomOptions(3);
4127
4699
  this.orbitingOrbs = e.map((i, s) => {
4128
4700
  const a = s * Math.PI * 2 / e.length;
4129
- return new B(`orb_${Date.now()}_${s}`, i, a);
4701
+ return new j(`orb_${Date.now()}_${s}`, i, a);
4130
4702
  }), this.rerollsRemaining = this.getRerollLimit();
4131
4703
  }
4132
4704
  spawnExperienceDrops() {
4133
4705
  for (const t of this.enemies)
4134
- t.experienceDropPending && (t.experienceDropPending = !1, this.experienceOrbs.push(new pt(t.position)));
4706
+ t.experienceDropPending && (t.experienceDropPending = !1, this.experienceOrbs.push(new k(t.position, 1, this.configManager.getConfig().experience)));
4135
4707
  }
4136
4708
  updateExperienceOrbs(t) {
4137
- const e = v.getInstance().getConfig().magnet;
4138
- for (const i of this.experienceOrbs)
4139
- if (i.active) {
4140
- if (i.isAbsorbing || Math.hypot(
4141
- this.core.position.x - i.position.x,
4142
- this.core.position.y - i.position.y
4143
- ) <= this.core.getHitboxRadius() + e.corePickupRadius && i.beginAbsorption(), !i.isAbsorbing) {
4144
- const s = this.inputManager.pointerPosition.x - i.position.x, a = this.inputManager.pointerPosition.y - i.position.y, r = e.psionicRadius + e.pickupRadius + i.radius;
4145
- Math.hypot(s, a) <= r && i.beginAbsorption();
4709
+ const e = this.configManager.getConfig(), i = e.magnet;
4710
+ k.attractNearby(this.experienceOrbs, e.experience, t), k.mergeNearby(this.experienceOrbs, e.experience.mergeDistance);
4711
+ for (const s of this.experienceOrbs)
4712
+ if (s.active) {
4713
+ if (s.isMerging) {
4714
+ s.update(t, this.core.position, this.core.getHitboxRadius(), i.absorptionSpeed);
4715
+ continue;
4716
+ }
4717
+ if (s.isAbsorbing || Math.hypot(
4718
+ this.core.position.x - s.position.x,
4719
+ this.core.position.y - s.position.y
4720
+ ) <= this.core.getHitboxRadius() + i.corePickupRadius && s.beginAbsorption(), !s.isAbsorbing) {
4721
+ const a = this.inputManager.pointerPosition.x - s.position.x, n = this.inputManager.pointerPosition.y - s.position.y, o = i.psionicRadius + i.pickupRadius + s.radius;
4722
+ Math.hypot(a, n) <= o && s.beginAbsorption();
4146
4723
  }
4147
- i.update(t, this.core.position, this.core.getHitboxRadius(), e.absorptionSpeed), i.active || (this.progressBar.addExperience(i.value), this.juice.triggerFlash(0.12), this.floatingTexts.push({
4724
+ s.update(t, this.core.position, this.core.getHitboxRadius(), i.absorptionSpeed), !s.active && s.absorbedByCore && (this.progressBar.addExperience(s.value), this.juice.triggerFlash(0.12), this.floatingTexts.push({
4148
4725
  id: Math.random().toString(),
4149
- text: `+${i.value} XP`,
4726
+ text: `+${s.value} XP`,
4150
4727
  position: { ...this.core.position },
4151
4728
  velocity: { x: 0, y: -55 },
4152
- color: f.experience,
4729
+ color: s.color,
4153
4730
  alpha: 1,
4154
4731
  lifetime: 0,
4155
4732
  maxLifetime: 0.8,
4156
4733
  size: 18
4157
4734
  }));
4158
4735
  }
4159
- this.experienceOrbs = this.experienceOrbs.filter((i) => i.active);
4736
+ this.experienceOrbs = this.experienceOrbs.filter((s) => s.active);
4160
4737
  }
4161
4738
  triggerReroll() {
4162
4739
  if (this.rerollsRemaining <= 0) return;
4163
4740
  this.rerollsRemaining -= 1, this.juice.triggerFlash(0.4);
4164
- const t = V.getRandomOptions(3);
4741
+ const t = this.powerUpRegistry.getRandomOptions(3);
4165
4742
  this.orbitingOrbs = t.map((e, i) => {
4166
4743
  const s = i * Math.PI * 2 / t.length;
4167
- return new B(`orb_${Date.now()}_${i}`, e, s);
4744
+ return new j(`orb_${Date.now()}_${i}`, e, s);
4168
4745
  });
4169
4746
  }
4170
4747
  render() {
@@ -4182,6 +4759,8 @@ class Tt {
4182
4759
  this.inputManager.grabbedEnemy,
4183
4760
  this.inputManager.pointerPosition,
4184
4761
  this.progressBar.getLevel(),
4762
+ this.progressBar.getProgress(),
4763
+ this.progressBar.getLevelUpPulse(),
4185
4764
  this.interactiveTutorial.isActive ? this.interactiveTutorial : void 0
4186
4765
  ), this.isLevelUpActive && this.orbitingOrbs.length > 0 && this.renderer.drawOrbitingModifierOrbs(
4187
4766
  this.orbitingOrbs,
@@ -4198,14 +4777,14 @@ class Tt {
4198
4777
  this.gameLoop.stop(), this.performanceAudit.destroy(), this.canvas.remove();
4199
4778
  }
4200
4779
  }
4201
- function Lt(b) {
4202
- return new Tt(b);
4780
+ function ae(p) {
4781
+ return new se(p);
4203
4782
  }
4204
4783
  export {
4205
- St as BrowserPlatform,
4206
- Tt as GameEngine,
4207
- W as LANGUAGES,
4208
- ut as ThemeManager,
4209
- Lt as createAxonSurge,
4210
- k as isLanguage
4784
+ Ot as BrowserPlatform,
4785
+ se as GameEngine,
4786
+ tt as LANGUAGES,
4787
+ yt as ThemeManager,
4788
+ ae as createAxonSurge,
4789
+ B as isLanguage
4211
4790
  };