@minicode-dev/chat 0.1.12 → 0.1.14

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 (107) hide show
  1. package/CHANGELOG.md +112 -5
  2. package/README.md +401 -309
  3. package/assets/sounds/effects/avalanche.mp3 +0 -0
  4. package/assets/sounds/racing/car_boost.mp3 +0 -0
  5. package/assets/sounds/racing/car_boost.ogg +0 -0
  6. package/assets/sounds/racing/car_bump.mp3 +0 -0
  7. package/assets/sounds/racing/car_bump.ogg +0 -0
  8. package/assets/sounds/racing/car_drift_loop.mp3 +0 -0
  9. package/assets/sounds/racing/car_drift_loop.ogg +0 -0
  10. package/assets/sounds/racing/car_engine_loop.mp3 +0 -0
  11. package/assets/sounds/racing/car_engine_loop.ogg +0 -0
  12. package/assets/sounds/racing/car_engine_start.mp3 +0 -0
  13. package/assets/sounds/racing/car_engine_start.ogg +0 -0
  14. package/assets/sounds/racing/countdown_beep.mp3 +0 -0
  15. package/assets/sounds/racing/countdown_beep.ogg +0 -0
  16. package/assets/sounds/racing/countdown_go.mp3 +0 -0
  17. package/assets/sounds/racing/countdown_go.ogg +0 -0
  18. package/assets/sounds/racing/final_lap.mp3 +0 -0
  19. package/assets/sounds/racing/final_lap.ogg +0 -0
  20. package/assets/sounds/racing/finish_line.mp3 +0 -0
  21. package/assets/sounds/racing/finish_line.ogg +0 -0
  22. package/assets/sounds/racing/lap_complete.mp3 +0 -0
  23. package/assets/sounds/racing/lap_complete.ogg +0 -0
  24. package/assets/sounds/racing/music_circuit.mp3 +0 -0
  25. package/assets/sounds/racing/music_circuit.ogg +0 -0
  26. package/assets/sounds/racing/music_final_lap.mp3 +0 -0
  27. package/assets/sounds/racing/music_final_lap.ogg +0 -0
  28. package/assets/sounds/racing/race_defeat.mp3 +0 -0
  29. package/assets/sounds/racing/race_defeat.ogg +0 -0
  30. package/assets/sounds/racing/race_victory.mp3 +0 -0
  31. package/assets/sounds/racing/race_victory.ogg +0 -0
  32. package/assets/sounds/tanks/barrel_explode.mp3 +0 -0
  33. package/assets/sounds/tanks/barrel_explode.ogg +0 -0
  34. package/assets/sounds/tanks/crate_break.mp3 +0 -0
  35. package/assets/sounds/tanks/crate_break.ogg +0 -0
  36. package/assets/sounds/tanks/health_pickup.mp3 +0 -0
  37. package/assets/sounds/tanks/health_pickup.ogg +0 -0
  38. package/assets/sounds/tanks/last_life.mp3 +0 -0
  39. package/assets/sounds/tanks/last_life.ogg +0 -0
  40. package/assets/sounds/tanks/life_lost.mp3 +0 -0
  41. package/assets/sounds/tanks/life_lost.ogg +0 -0
  42. package/assets/sounds/tanks/respawn.mp3 +0 -0
  43. package/assets/sounds/tanks/respawn.ogg +0 -0
  44. package/assets/sounds/tanks/shield_end.mp3 +0 -0
  45. package/assets/sounds/tanks/shield_end.ogg +0 -0
  46. package/assets/sounds/tanks/shield_loop.mp3 +0 -0
  47. package/assets/sounds/tanks/shield_loop.ogg +0 -0
  48. package/assets/sounds/tanks/wall_hit.mp3 +0 -0
  49. package/assets/sounds/tanks/wall_hit.ogg +0 -0
  50. package/dist/chunks/{BattleshipGameCard-iRk8d4vR.js → BattleshipGameCard-B-B4r7lK.js} +146 -144
  51. package/dist/chunks/{BattleshipGameCard-iRk8d4vR.js.map → BattleshipGameCard-B-B4r7lK.js.map} +1 -1
  52. package/dist/chunks/{ChatContext-DjIEifGY.js → ChatContext-DQtKsR6Z.js} +2 -2
  53. package/dist/chunks/{ChatContext-DjIEifGY.js.map → ChatContext-DQtKsR6Z.js.map} +1 -1
  54. package/dist/chunks/RacingLiveGameCard-c1G7uoDI.js +1654 -0
  55. package/dist/chunks/RacingLiveGameCard-c1G7uoDI.js.map +1 -0
  56. package/dist/chunks/{TanksGameCard-B47ZQcSr.js → TanksGameCard-CvTaF7tu.js} +164 -162
  57. package/dist/chunks/{TanksGameCard-B47ZQcSr.js.map → TanksGameCard-CvTaF7tu.js.map} +1 -1
  58. package/dist/chunks/TanksLiveGameCard-COr9Oay5.js +1011 -0
  59. package/dist/chunks/TanksLiveGameCard-COr9Oay5.js.map +1 -0
  60. package/dist/chunks/avalancheScene3d-Z5QyZIid.js +1299 -0
  61. package/dist/chunks/avalancheScene3d-Z5QyZIid.js.map +1 -0
  62. package/dist/chunks/connect4Sounds-DmD-E9kX.js +235 -0
  63. package/dist/chunks/connect4Sounds-DmD-E9kX.js.map +1 -0
  64. package/dist/chunks/connectionStore-DwgIUl30.js +13 -0
  65. package/dist/chunks/connectionStore-DwgIUl30.js.map +1 -0
  66. package/dist/chunks/createLiveScene-CWBunxPi.js +367 -0
  67. package/dist/chunks/createLiveScene-CWBunxPi.js.map +1 -0
  68. package/dist/chunks/createRaceScene-C7Rw89kj.js +305 -0
  69. package/dist/chunks/createRaceScene-C7Rw89kj.js.map +1 -0
  70. package/dist/chunks/{createTankScene-CV7Brxmt.js → createTankScene-yhX6la27.js} +150 -147
  71. package/dist/chunks/{createTankScene-CV7Brxmt.js.map → createTankScene-yhX6la27.js.map} +1 -1
  72. package/dist/chunks/decor-CyyCnmct.js +418 -0
  73. package/dist/chunks/decor-CyyCnmct.js.map +1 -0
  74. package/dist/chunks/fx-1ZwzmPWj.js +458 -0
  75. package/dist/chunks/fx-1ZwzmPWj.js.map +1 -0
  76. package/dist/chunks/fx-UZwhOmdl.js +584 -0
  77. package/dist/chunks/fx-UZwhOmdl.js.map +1 -0
  78. package/dist/chunks/gameStatus-BChd29yI.js +62 -0
  79. package/dist/chunks/gameStatus-BChd29yI.js.map +1 -0
  80. package/dist/chunks/{connect4Sounds-Cv0q31VW.js → games-BvYTWgaR.js} +814 -951
  81. package/dist/chunks/games-BvYTWgaR.js.map +1 -0
  82. package/dist/chunks/rolldown-runtime-CGnMp29N.js +10 -0
  83. package/dist/chunks/tank-DjEQ4FXF.js +553 -0
  84. package/dist/chunks/tank-DjEQ4FXF.js.map +1 -0
  85. package/dist/chunks/tanks-live-BcKmrhnV.js +261 -0
  86. package/dist/chunks/tanks-live-BcKmrhnV.js.map +1 -0
  87. package/dist/chunks/{tanksSounds-CUNDIOal.js → tanksSounds-DwjfSp3W.js} +43 -11
  88. package/dist/chunks/tanksSounds-DwjfSp3W.js.map +1 -0
  89. package/dist/chunks/track-BcnnpnAm.js +259 -0
  90. package/dist/chunks/track-BcnnpnAm.js.map +1 -0
  91. package/dist/chunks/util-DwI9bfS7.js +57 -0
  92. package/dist/chunks/util-DwI9bfS7.js.map +1 -0
  93. package/dist/index.js +2176 -1592
  94. package/dist/index.js.map +1 -1
  95. package/dist/styles.css +1 -1
  96. package/index.d.ts +4 -2
  97. package/package.json +1 -1
  98. package/dist/chunks/TanksLiveGameCard-DGsnMD3j.js +0 -1225
  99. package/dist/chunks/TanksLiveGameCard-DGsnMD3j.js.map +0 -1
  100. package/dist/chunks/connect4Sounds-Cv0q31VW.js.map +0 -1
  101. package/dist/chunks/createLiveScene-BqI7qV4n.js +0 -364
  102. package/dist/chunks/createLiveScene-BqI7qV4n.js.map +0 -1
  103. package/dist/chunks/fx-BHsl4S_J.js +0 -1470
  104. package/dist/chunks/fx-BHsl4S_J.js.map +0 -1
  105. package/dist/chunks/gameStatus-Cu1Z8un9.js +0 -69
  106. package/dist/chunks/gameStatus-Cu1Z8un9.js.map +0 -1
  107. package/dist/chunks/tanksSounds-CUNDIOal.js.map +0 -1
@@ -0,0 +1,1011 @@
1
+ import { t as e } from "./rolldown-runtime-CGnMp29N.js";
2
+ import { a as t } from "./games-BvYTWgaR.js";
3
+ import { n, o as r, s as i } from "./createPeerLink-DBVs_yvQ.js";
4
+ import { t as a } from "./ChatContext-DQtKsR6Z.js";
5
+ import { o } from "./connect4Sounds-DmD-E9kX.js";
6
+ import { n as s, r as c, t as l } from "./tanks-live-BcKmrhnV.js";
7
+ import { a as u, i as d, n as f, r as p, t as m } from "./tanksSounds-DwjfSp3W.js";
8
+ import { memo as h, useContext as g, useEffect as _, useRef as v, useState as y } from "react";
9
+ import { AlertTriangle as b, CheckCircle2 as x, Link2 as S, Loader2 as ee, Settings2 as C } from "lucide-react";
10
+ import { Fragment as w, jsx as T, jsxs as E } from "react/jsx-runtime";
11
+ // src/games/tanks-live/logic/simulation.js
12
+ var D = Object.freeze({
13
+ speed: 16,
14
+ reverse: 9,
15
+ turn: 1.8,
16
+ acceleration: 28,
17
+ radius: 2,
18
+ reloadMs: 1500,
19
+ shellSpeed: 60,
20
+ damage: 25
21
+ }), O = (e, t, n) => Math.max(t, Math.min(n, e)), k = (e, t) => Math.atan2(Math.sin(t - e), Math.cos(t - e));
22
+ function A() {
23
+ return {
24
+ size: 120,
25
+ bounds: {
26
+ minX: 0,
27
+ maxX: 120,
28
+ minZ: 0,
29
+ maxZ: 120
30
+ },
31
+ obstacles: [
32
+ [
33
+ 42,
34
+ 35,
35
+ 4
36
+ ],
37
+ [
38
+ 78,
39
+ 85,
40
+ 4
41
+ ],
42
+ [
43
+ 60,
44
+ 30,
45
+ 3
46
+ ],
47
+ [
48
+ 60,
49
+ 90,
50
+ 3
51
+ ],
52
+ [
53
+ 35,
54
+ 65,
55
+ 3
56
+ ],
57
+ [
58
+ 85,
59
+ 55,
60
+ 3
61
+ ],
62
+ [
63
+ 60,
64
+ 60,
65
+ 5
66
+ ]
67
+ ].map(([e, t, n], r) => ({
68
+ x: e,
69
+ z: t,
70
+ r: n,
71
+ kind: r % 2 ? "tree" : "rock"
72
+ }))
73
+ };
74
+ }
75
+ function j(e, t) {
76
+ return {
77
+ id: String(e),
78
+ x: t ? 102 : 18,
79
+ z: 60,
80
+ yaw: t ? Math.PI : 0,
81
+ turretYaw: t ? Math.PI : 0,
82
+ speed: 0,
83
+ hp: 100,
84
+ alive: !0,
85
+ color: t ? "#d7463f" : "#54a34a"
86
+ };
87
+ }
88
+ Object.freeze({
89
+ radius: 6,
90
+ damage: 20
91
+ });
92
+ var M = (e) => !!e && e.alive !== !1 && (e.hp === void 0 || e.hp > 0);
93
+ function N(e, t, n) {
94
+ let r = t - e.x, i = n - e.z, a = Math.cos(e.rot || 0), o = Math.sin(e.rot || 0);
95
+ return [r * a + i * o, -r * o + i * a];
96
+ }
97
+ function P(e, t, n, r) {
98
+ if (r.shape !== "rect") return Math.hypot(e - r.x, t - r.z) < r.r + n;
99
+ let [i, a] = N(r, e, t), o = r.w / 2, s = r.d / 2;
100
+ return Math.hypot(i - O(i, -o, o), a - O(a, -s, s)) < n || Math.abs(i) <= o && Math.abs(a) <= s;
101
+ }
102
+ function F(e, t, n, r = D.radius) {
103
+ let i = n.bounds;
104
+ return e >= i.minX + r && e <= i.maxX - r && t >= i.minZ + r && t <= i.maxZ - r && !n.obstacles.some((n) => P(e, t, r, n)) && !(n.destructibles || []).some((n) => M(n) && P(e, t, r, n));
105
+ }
106
+ function te(e, t, n, r) {
107
+ if (!e.alive) return;
108
+ let i = O(Number(t.throttle) || 0, -1, 1), a = O(Number(t.steer) || 0, -1, 1), o = i * (i < 0 ? D.reverse : D.speed);
109
+ e.speed += O(o - e.speed, -D.acceleration * n, D.acceleration * n), e.yaw += a * D.turn * n, Number.isFinite(t.turretYaw) && (e.turretYaw = t.turretYaw);
110
+ let s = e.x + Math.cos(e.yaw) * e.speed * n, c = e.z + Math.sin(e.yaw) * e.speed * n;
111
+ F(s, e.z, r) ? e.x = s : e.speed = 0, F(e.x, c, r) ? e.z = c : e.speed = 0;
112
+ }
113
+ function I(e, t, n, r, i, a, o) {
114
+ let s = n - e, c = r - t, l = s * s + c * c, u = l ? O(((i - e) * s + (a - t) * c) / l, 0, 1) : 0;
115
+ return Math.hypot(e + s * u - i, t + c * u - a) <= o ? u : null;
116
+ }
117
+ function L(e, t, n, r, i) {
118
+ let [a, o] = N(i, e, t), [s, c] = N(i, n, r), l = [s - a, c - o], u = [a, o], d = [i.w / 2, i.d / 2], f = 0, p = 1;
119
+ for (let e = 0; e < 2; e++) {
120
+ if (Math.abs(l[e]) < 1e-12) {
121
+ if (Math.abs(u[e]) > d[e]) return null;
122
+ continue;
123
+ }
124
+ let t = (-d[e] - u[e]) / l[e], n = (d[e] - u[e]) / l[e];
125
+ if (t > n && ([t, n] = [n, t]), f = Math.max(f, t), p = Math.min(p, n), f > p) return null;
126
+ }
127
+ return f;
128
+ }
129
+ var R = (e, t, n, r, i) => i.shape === "rect" ? L(e, t, n, r, i) : I(e, t, n, r, i.x, i.z, i.r);
130
+ function ne(e, t, n, r) {
131
+ let i = e.x + Math.cos(e.yaw) * D.shellSpeed * t, a = e.z + Math.sin(e.yaw) * D.shellSpeed * t, o = null;
132
+ for (let t of n.obstacles) {
133
+ let n = R(e.x, e.z, i, a, t);
134
+ n !== null && (!o || n < o.t) && (o = t.shape === "rect" ? {
135
+ t: n,
136
+ kind: "obstacle",
137
+ shape: "rect",
138
+ id: t.id,
139
+ obstacleKind: t.kind
140
+ } : {
141
+ t: n,
142
+ kind: "obstacle"
143
+ });
144
+ }
145
+ for (let t of n.destructibles || []) {
146
+ if (!M(t)) continue;
147
+ let n = R(e.x, e.z, i, a, t);
148
+ n !== null && (!o || n < o.t) && (o = {
149
+ t: n,
150
+ kind: "destructible",
151
+ id: t.id,
152
+ destructibleKind: t.kind
153
+ });
154
+ }
155
+ for (let t of r) {
156
+ if (!t.alive || t.id === e.owner) continue;
157
+ let n = I(e.x, e.z, i, a, t.x, t.z, D.radius);
158
+ n !== null && (!o || n < o.t) && (o = {
159
+ t: n,
160
+ kind: "tank",
161
+ target: t.id
162
+ });
163
+ }
164
+ return o ? (e.x += (i - e.x) * o.t, e.z += (a - e.z) * o.t, o) : (e.x = i, e.z = a, e.age += t, !F(i, a, {
165
+ ...n,
166
+ obstacles: [],
167
+ destructibles: []
168
+ }, 0) || e.age > 3 ? { kind: "terrain" } : null);
169
+ }
170
+ function re(e, t, n) {
171
+ let r = O(n, 0, 1);
172
+ return {
173
+ ...t,
174
+ x: e.x + (t.x - e.x) * r,
175
+ z: e.z + (t.z - e.z) * r,
176
+ yaw: e.yaw + k(e.yaw, t.yaw) * r,
177
+ turretYaw: e.turretYaw + k(e.turretYaw, t.turretYaw) * r
178
+ };
179
+ }
180
+ // src/games/tanks-live/net/createLiveMatch.js
181
+ var ie = (e) => typeof e == "number" && Number.isFinite(e), ae = (e) => typeof e == "string" && e.length > 0 && e.length < 160;
182
+ function z({ game: e, selfId: t, isHost: a = String(t) === String(e.hostId), signaling: o, onChange: s = () => {}, peerFactory: c = n, iceServers: l, iceTransportPolicy: u, RTCPeerConnectionImpl: d } = {}) {
183
+ t = String(t);
184
+ let f = [String(e.hostId), String(e.guestId)];
185
+ if (!f.includes(t) || f[0] === f[1]) throw Error("Invalid live match players");
186
+ let p = (l || []).some((e) => [e.urls].flat().some((e) => /^turns?:/i.test(String(e)))), m = f.find((e) => e !== t), h = A(), g = f.map(j), _ = [], v = [], y = {}, b = 0, x = 0, S = 0, ee = 0, C = "connecting", w = null, T = !1, E = {
187
+ phase: "idle",
188
+ rtt: null,
189
+ route: null
190
+ }, O = !1, k = !1, M = null, N = [], P = null, I = null, L = /* @__PURE__ */ new Map(), R = /* @__PURE__ */ new Set(), z = /* @__PURE__ */ new Set(), B = () => g.find((e) => e.id === t), V = () => g.find((e) => e.id === m), H = () => {
191
+ T || s({
192
+ status: C,
193
+ winner: w,
194
+ net: E
195
+ });
196
+ }, U = (e) => {
197
+ v.push(e), v.length > 200 && v.shift();
198
+ }, W = (t) => Z.sendEvent({
199
+ ...t,
200
+ g: e.gameId,
201
+ r: S
202
+ }), G = (e) => {
203
+ R.add(e), R.size > 2048 && R.delete(R.values().next().value);
204
+ }, K = () => ({
205
+ k: "snapshot",
206
+ hp: g.map((e) => e.hp),
207
+ status: C,
208
+ winner: w,
209
+ reason: M
210
+ });
211
+ function q() {
212
+ g = f.map(j), _ = [], N = [], P = null, I = null, L.clear(), R.clear(), z.clear(), k = !1, M = null, w = null, C = E.phase === "connected" ? "playing" : "connecting", U({ k: "rematch" }), H();
213
+ }
214
+ function J(e, t = !1) {
215
+ (C !== "over" || t && w !== e) && (C = "over", w = e, _ = [], Z.clearManualTurn?.(), U({
216
+ k: "over",
217
+ winner: w
218
+ }), H());
219
+ }
220
+ function Y(e, t, n) {
221
+ if (C !== "playing" || !ae(t.id) || R.has(t.id)) return !1;
222
+ let r = g.find((t) => t.id === e);
223
+ if (!r?.alive || b - (L.get(e) ?? -Infinity) < D.reloadMs - 20 || ![
224
+ t.x,
225
+ t.z,
226
+ t.yaw
227
+ ].every(ie) || Math.hypot(t.x - (e === m && I ? I.x : r.x), t.z - (e === m && I ? I.z : r.z)) > 6) return !1;
228
+ G(t.id), L.set(e, b);
229
+ let i = {
230
+ ...t,
231
+ k: "fire",
232
+ owner: e,
233
+ x: t.x + Math.cos(t.yaw) * 2.8,
234
+ z: t.z + Math.sin(t.yaw) * 2.8,
235
+ y: 1.4,
236
+ age: 0
237
+ };
238
+ return _.push(i), U(i), n && W({
239
+ ...t,
240
+ k: "fire"
241
+ }), !0;
242
+ }
243
+ function X(t) {
244
+ if (T || C !== "playing" || t?.g !== e.gameId || t.r !== S || !Array.isArray(t.p) || t.p.length !== 5 || !t.p.every(ie)) return;
245
+ let [n, r, i, a, o] = t.p;
246
+ if (!F(n, r, h) || Math.abs(o) > D.speed + .1 || Math.abs(i) > 1e6 || Math.abs(a) > 1e6) return;
247
+ let s = P === null ? .1 : Math.max(0, (b - P) / 1e3), c = I || V();
248
+ if (Math.hypot(n - c.x, r - c.z) > D.speed * s + 3) return;
249
+ let l = {
250
+ ...V(),
251
+ x: n,
252
+ z: r,
253
+ yaw: i,
254
+ turretYaw: a,
255
+ speed: o
256
+ };
257
+ I = l, P = b, N.push({
258
+ time: b,
259
+ pose: l
260
+ }), N.length > 30 && N.shift();
261
+ }
262
+ function oe(n) {
263
+ if (!T && n && n.g === e.gameId && Number.isInteger(n.r)) {
264
+ if (n.k === "round" && !a && C === "over" && z.has(t) && n.r === S + 1) S = n.r, q();
265
+ else if (n.r === S) {
266
+ if (n.k === "sync" && a) W(K());
267
+ else if (n.k === "snapshot" && !a && Array.isArray(n.hp) && n.hp.length === 2 && n.hp.every((e) => Number.isInteger(e) && e >= 0 && e <= 100)) {
268
+ let e = n.status === "playing" && n.winner === null && n.hp.every((e) => e > 0), t = n.status === "over" && f.includes(n.winner) && (n.hp[1 - f.indexOf(n.winner)] === 0 || n.reason === "resigned");
269
+ if (!e && !t) return;
270
+ g.forEach((e, t) => {
271
+ e.hp = n.hp[t], e.alive = e.hp > 0;
272
+ }), t && (k = !1, M = n.reason, J(n.winner, !0));
273
+ } else n.k === "resign" ? (M = "resigned", J(t, a), a && W(K())) : n.k === "rematch" && C === "over" ? (z.add(m), se()) : C === "playing" && (n.k === "fire" && Y(m, n, !1), !a && n.k === "hit" && ae(n.id) && !R.has(`hit:${n.id}`) && f.includes(n.target) && Array.isArray(n.hp) && n.hp.length === 2 && n.hp.every((e, t) => Number.isInteger(e) && e >= 0 && e <= g[t].hp) && [n.x, n.z].every(ie) && (G(`hit:${n.id}`), g.forEach((e, t) => {
274
+ e.hp = n.hp[t], e.alive = e.hp > 0;
275
+ }), _ = _.filter((e) => e.id !== n.id), U(n)), !a && n.k === "destroyed" && f.includes(n.target) && !R.has(`destroyed:${n.target}`) && g.find((e) => e.id === n.target).hp === 0 && (G(`destroyed:${n.target}`), U(n)), !a && n.k === "over" && f.includes(n.winner) && g.find((e) => e.id !== n.winner).hp === 0 && J(n.winner));
276
+ }
277
+ }
278
+ }
279
+ let Z = c({
280
+ configurationAuthority: a,
281
+ signaling: o && {
282
+ send(t) {
283
+ let n = r(t);
284
+ if (!n) return Promise.reject(/* @__PURE__ */ Error("Invalid live signal"));
285
+ let a = i({
286
+ ...n,
287
+ liveGame: e.gameId
288
+ });
289
+ return a ? o.send(a) : Promise.reject(/* @__PURE__ */ Error("Live signal too large"));
290
+ },
291
+ subscribe(t) {
292
+ return o.subscribe((n) => {
293
+ r(n?.text)?.liveGame === e.gameId && t(n);
294
+ });
295
+ }
296
+ },
297
+ selfId: t,
298
+ peerId: m,
299
+ roomId: e.roomId,
300
+ iceServers: l,
301
+ iceTransportPolicy: u,
302
+ RTCPeerConnectionImpl: d,
303
+ onMove: X,
304
+ onEvent: oe,
305
+ onChange(e) {
306
+ let t = E.phase;
307
+ if (E = e, e.phase === "connected") {
308
+ let e = O;
309
+ O = !0, C !== "over" && (C = "playing"), t !== "connected" && queueMicrotask(() => {
310
+ T || (k && W({ k: "resign" }), a && e ? W(K()) : a || W({ k: "sync" }));
311
+ });
312
+ } else C !== "over" && (C = O ? "disconnected" : "connecting");
313
+ H();
314
+ }
315
+ });
316
+ function se() {
317
+ a && z.size === 2 && (S++, W({ k: "round" }), q());
318
+ }
319
+ return a ? Z.connect() : Z.setListening(!0), {
320
+ setInput(e) {
321
+ y = { ...e };
322
+ },
323
+ step(n) {
324
+ if (T) return;
325
+ let r = Math.max(0, Math.min(Number(n) || 0, 100));
326
+ if (b += r, C !== "playing") return;
327
+ let i = r / 1e3, o = b - 100;
328
+ for (; N.length > 1 && N[1].time <= o;) N.shift();
329
+ if (N.length) {
330
+ let e = N[0], t = N[1] || e, n = re(e.pose, t.pose, t.time === e.time ? 1 : (o - e.time) / (t.time - e.time));
331
+ for (let e of [
332
+ "x",
333
+ "z",
334
+ "yaw",
335
+ "turretYaw",
336
+ "speed"
337
+ ]) V()[e] = n[e];
338
+ }
339
+ for (let e = i; e > 0; e -= .016) te(B(), y, Math.min(e, .016), h);
340
+ y.fire && Y(t, {
341
+ id: `${t}:${S}:${++ee}`,
342
+ x: B().x,
343
+ z: B().z,
344
+ yaw: B().turretYaw,
345
+ t: b
346
+ }, !0);
347
+ let s = E.rtt > 250 || E.move?.lossPct > 15 ? 10 : E.rtt > 100 ? 15 : 20;
348
+ if (b >= x) {
349
+ x = b + 1e3 / s;
350
+ let t = B();
351
+ Z.sendMove({
352
+ g: e.gameId,
353
+ r: S,
354
+ p: [
355
+ t.x,
356
+ t.z,
357
+ t.yaw,
358
+ t.turretYaw,
359
+ t.speed
360
+ ],
361
+ t: b
362
+ });
363
+ }
364
+ _ = _.filter((e) => {
365
+ let t = ne(e, i, h, g);
366
+ if (!t) return !0;
367
+ if (a && t.target && C === "playing") {
368
+ let n = g.find((e) => e.id === t.target);
369
+ n.hp = Math.max(0, n.hp - D.damage), n.alive = n.hp > 0;
370
+ let r = {
371
+ k: "hit",
372
+ id: e.id,
373
+ target: n.id,
374
+ dmg: D.damage,
375
+ hp: g.map((e) => e.hp),
376
+ x: e.x,
377
+ z: e.z
378
+ };
379
+ if (W(r), U(r), !n.alive) {
380
+ let t = {
381
+ k: "destroyed",
382
+ target: n.id
383
+ };
384
+ W(t), U(t), W({
385
+ k: "over",
386
+ winner: e.owner
387
+ }), J(e.owner);
388
+ }
389
+ } else U({
390
+ k: "impact",
391
+ kind: t.kind,
392
+ x: e.x,
393
+ z: e.z
394
+ });
395
+ return !1;
396
+ });
397
+ },
398
+ getRender() {
399
+ let e = {
400
+ arena: h,
401
+ tanks: g.map((e) => ({
402
+ ...e,
403
+ self: e.id === t,
404
+ reload: Math.min(1, (b - (L.get(e.id) ?? -Infinity)) / D.reloadMs)
405
+ })),
406
+ shells: _.map((e) => ({ ...e })),
407
+ events: v,
408
+ status: C,
409
+ winner: w,
410
+ net: {
411
+ ...E,
412
+ turnConfigured: E.turnConfigured ?? p
413
+ }
414
+ };
415
+ return v = [], e;
416
+ },
417
+ configureTurn(e, t) {
418
+ return T || C === "over" ? Promise.reject(/* @__PURE__ */ Error("La partida ya terminó.")) : Z.configureTurn(e, t);
419
+ },
420
+ reconnect() {
421
+ !T && C !== "over" && (Z.requestReconnect ? Z.requestReconnect() : Z.connect());
422
+ },
423
+ rematch() {
424
+ !T && C === "over" && (z.add(t), W({ k: "rematch" }), se());
425
+ },
426
+ resign() {
427
+ !T && C !== "over" && (k = !0, M = "resigned", W({ k: "resign" }), J(m));
428
+ },
429
+ destroy() {
430
+ T || (T = !0, Z.destroy(), _ = [], N = [], v = []);
431
+ }
432
+ };
433
+ }
434
+ var B = 180 / Math.PI, V = (e, t) => Number.isFinite(e) ? e : t;
435
+ function H(e) {
436
+ let t = e || {}, n = t.bounds || t;
437
+ if (Number.isFinite(n.minX) && Number.isFinite(n.maxX) && Number.isFinite(n.minZ) && Number.isFinite(n.maxZ)) return U({
438
+ minX: n.minX,
439
+ minZ: n.minZ,
440
+ maxX: n.maxX,
441
+ maxZ: n.maxZ
442
+ });
443
+ let r = V(t.width, V(t.size, 120)), i = V(t.depth, V(t.height, V(t.size, r)));
444
+ return U(t.centered === !0 || t.origin === "center" ? {
445
+ minX: -r / 2,
446
+ minZ: -i / 2,
447
+ maxX: r / 2,
448
+ maxZ: i / 2
449
+ } : {
450
+ minX: 0,
451
+ minZ: 0,
452
+ maxX: r,
453
+ maxZ: i
454
+ });
455
+ }
456
+ function U(e) {
457
+ return {
458
+ ...e,
459
+ width: e.maxX - e.minX,
460
+ depth: e.maxZ - e.minZ,
461
+ cx: (e.minX + e.maxX) / 2,
462
+ cz: (e.minZ + e.maxZ) / 2
463
+ };
464
+ }
465
+ function W(e) {
466
+ return (e?.obstacles || []).filter((e) => Number.isFinite(e?.x) && Number.isFinite(e?.z)).map((e) => ({
467
+ x: e.x,
468
+ z: e.z,
469
+ r: V(e.r, V(e.radius, 1.5)),
470
+ kind: e.kind === "tree" ? "tree" : "rock"
471
+ }));
472
+ }
473
+ var G = (e) => e ? e.k ?? e.type ?? null : null;
474
+ function K(e, t) {
475
+ let n = t || [], r = e?.tank ?? e?.by ?? e?.owner ?? e?.from;
476
+ if (r != null) {
477
+ let e = n.find((e) => String(e.id) === String(r));
478
+ if (e) return e;
479
+ }
480
+ if (!Number.isFinite(e?.x) || !Number.isFinite(e?.z)) return null;
481
+ let i = null, a = Infinity;
482
+ for (let t of n) {
483
+ let n = (t.x - e.x) ** 2 + (t.z - e.z) ** 2;
484
+ n < a && (a = n, i = t);
485
+ }
486
+ return i;
487
+ }
488
+ var q = (e, t) => t == null ? null : (e || []).find((e) => String(e.id) === String(t)) || null, J = (e) => (e || []).find((e) => e.self) || null, Y = (e, t = !0) => !t || e <= 25 ? 2 : +(e <= 50), X = (e) => {
489
+ let t = e % (Math.PI * 2);
490
+ return t > Math.PI && (t -= Math.PI * 2), t < -Math.PI && (t += Math.PI * 2), t;
491
+ };
492
+ function oe({ moveSpeed: e = .6, turnSpeed: t = .35, holdMs: n = 160 } = {}) {
493
+ let r = null, i = !1, a = !1, o = 0, s = 0;
494
+ return {
495
+ update(c, l) {
496
+ let u = [];
497
+ if (!c || c.alive === !1) return i && u.push({ type: "move_end" }), a && u.push({ type: "turret_end" }), i = a = !1, r = null, u;
498
+ let d = Math.max(1, l) / 1e3;
499
+ if (r) {
500
+ let f = Math.hypot(c.x - r.x, c.z - r.z) / d, p = Math.abs(X((c.yaw ?? 0) - r.yaw)) / d, m = Math.abs(X((c.turretYaw ?? 0) - (c.yaw ?? 0) - r.rel)) / d, h = f > e || p > t;
501
+ o = h ? 0 : o + l, h && !i ? (i = !0, u.push({ type: "move_start" })) : !h && i && o >= n && (i = !1, u.push({ type: "move_end" }));
502
+ let g = m > t;
503
+ s = g ? 0 : s + l, g && !a ? (a = !0, u.push({ type: "turret_start" })) : !g && a && s >= n && (a = !1, u.push({ type: "turret_end" }));
504
+ }
505
+ return r = {
506
+ x: c.x,
507
+ z: c.z,
508
+ yaw: c.yaw ?? 0,
509
+ rel: X((c.turretYaw ?? 0) - (c.yaw ?? 0))
510
+ }, u;
511
+ },
512
+ reset() {
513
+ r = null, i = a = !1, o = s = 0;
514
+ },
515
+ get moving() {
516
+ return i;
517
+ },
518
+ get turning() {
519
+ return a;
520
+ }
521
+ };
522
+ }
523
+ function Z(e) {
524
+ switch (G(e)) {
525
+ case "fire": return [{ type: "fire" }, { type: "projectile_start" }];
526
+ case "impact": return [{
527
+ type: "impact",
528
+ kind: e.kind === "obstacle" ? "obstacle" : "terrain"
529
+ }];
530
+ case "hit": return [{ type: "tank_hit" }];
531
+ case "destroyed": return [{ type: "destroyed" }];
532
+ default: return [];
533
+ }
534
+ }
535
+ function se(e) {
536
+ if (!e || e.status !== "over") return null;
537
+ let t = J(e.tanks);
538
+ return !t || e.winner == null ? null : String(e.winner) === String(t.id) ? "victory" : "defeat";
539
+ }
540
+ // src/games/tanks-live/scene/createLiveScene2d.js
541
+ function ce(e, { arena: t } = {}) {
542
+ let n = document.createElement("canvas");
543
+ n.style.cssText = "width:100%;height:100%;display:block", e.appendChild(n);
544
+ let r = n.getContext("2d");
545
+ if (!r) throw n.remove(), Error("Canvas 2D unavailable");
546
+ let i = H(t), a = 1, o = 1, s = 1, c = 0, l = 0;
547
+ function u() {
548
+ a = Math.max(1, e.clientWidth), o = Math.max(1, e.clientHeight);
549
+ let t = Math.min(window.devicePixelRatio || 1, 2);
550
+ n.width = a * t, n.height = o * t, r.setTransform(t, 0, 0, t, 0, 0), s = Math.min(a / i.width, o / i.depth), c = (a - i.width * s) / 2, l = (o - i.depth * s) / 2;
551
+ }
552
+ u();
553
+ let d = typeof ResizeObserver == "function" ? new ResizeObserver(u) : null;
554
+ return d?.observe(e), {
555
+ kind: "2d",
556
+ resize: u,
557
+ screenToGround(e, t) {
558
+ return {
559
+ x: ((e + 1) * a / 2 - c) / s + i.minX,
560
+ z: ((1 - t) * o / 2 - l) / s + i.minZ
561
+ };
562
+ },
563
+ render(e) {
564
+ r.fillStyle = "#152519", r.fillRect(0, 0, a, o), r.save(), r.translate(c, l), r.scale(s, s), r.translate(-i.minX, -i.minZ), r.fillStyle = "#526348", r.fillRect(i.minX, i.minZ, i.width, i.depth);
565
+ for (let e of W(t)) r.fillStyle = e.kind === "tree" ? "#24472d" : "#929285", r.beginPath(), r.arc(e.x, e.z, e.r, 0, Math.PI * 2), r.fill();
566
+ for (let t of e.tanks || []) r.save(), r.translate(t.x, t.z), r.rotate(t.yaw), r.fillStyle = t.alive === !1 ? "#333" : t.color || "#73ce68", r.fillRect(-3, -1.8, 6, 3.6), r.restore(), r.save(), r.translate(t.x, t.z), r.rotate(t.turretYaw), r.strokeStyle = "#dce8cf", r.lineWidth = .8, r.beginPath(), r.moveTo(0, 0), r.lineTo(5, 0), r.stroke(), r.restore(), t.self && (r.strokeStyle = "#fff", r.lineWidth = .3, r.beginPath(), r.arc(t.x, t.z, 4, 0, Math.PI * 2), r.stroke());
567
+ r.fillStyle = "#ffe097";
568
+ for (let t of e.shells || []) r.beginPath(), r.arc(t.x, t.z, .7, 0, Math.PI * 2), r.fill();
569
+ r.restore();
570
+ },
571
+ dispose() {
572
+ d?.disconnect(), n.remove();
573
+ }
574
+ };
575
+ }
576
+ // src/games/tanks-live/TanksLiveGameCard.jsx
577
+ var le = /* @__PURE__ */ e({ default: () => fe }), ue = (e, n) => {
578
+ t.getState().act(e, n).catch(() => {});
579
+ }, Q = (e) => {
580
+ e.throttle = 0, e.steer = 0, e.fire = !1;
581
+ };
582
+ function de(e, t) {
583
+ let n = e?.manualTurn;
584
+ return n?.status === "applying" ? "Aplicando configuración…" : n?.status === "sharing" ? "Sincronizando con el otro jugador…" : n?.status === "waiting_peer" ? "Esperando al otro jugador para compartir la configuración…" : e?.phase === "connected" ? "¡Conexión establecida!" : n?.status === "failed" || e?.phase === "failed" || e?.ice === "failed" ? "No pudimos conectar. Puedes reintentar." : t ? "La conexión está tardando más de lo esperado" : e?.phase === "restarting" || e?.phase === "reconnecting" ? "Reconectando…" : e?.phase === "listening" ? "Esperando la conexión del otro jugador…" : e?.phase === "calling" ? "Buscando al otro jugador…" : e?.phase === "negotiating" ? "Buscando una conexión entre los jugadores…" : "Preparando partida…";
585
+ }
586
+ function $({ gameKey: e, currentUserId: n, onMinimize: r, onDismiss: i, suspended: h = !1 }) {
587
+ let D = g(a)?.config?.webrtc, O = t((t) => t.games[e]), k = v(h);
588
+ k.current = h;
589
+ let A = v(null), j = v(null), M = v(null), N = v({
590
+ throttle: 0,
591
+ steer: 0,
592
+ fire: !1
593
+ }), [P, F] = y(null), [te, I] = y(""), [L, R] = y(!1), [ne, re] = y("loading"), [ie, ae] = y(!1), [B, V] = y(0), H = P?.net?.phase === "connected";
594
+ _(() => {
595
+ if (!O || O.status !== "active" || H) {
596
+ V(0);
597
+ return;
598
+ }
599
+ let e = Date.now(), t = setInterval(() => V(Date.now() - e), 1e3);
600
+ return () => clearInterval(t);
601
+ }, [
602
+ e,
603
+ O?.status,
604
+ H
605
+ ]), _(() => {
606
+ ae(!1);
607
+ }, [e, O?.status]), _(() => {
608
+ h ? (Q(N.current), u()) : M.current?.resize();
609
+ }, [h]);
610
+ let U = ["active", "won"].includes(O?.status), [W, G] = y(null);
611
+ if (_(() => {
612
+ if (!U || !W || !A.current) return;
613
+ let e = !1, t = null, n = {
614
+ arena: W,
615
+ lowPower: matchMedia("(pointer: coarse)").matches,
616
+ reducedMotion: matchMedia("(prefers-reduced-motion: reduce)").matches,
617
+ onEvent: (e) => {
618
+ e.type === "context_lost" && R(!0);
619
+ }
620
+ }, r = () => {
621
+ e || (t = ce(A.current, n), M.current = t, re("2d"));
622
+ };
623
+ return L ? r() : import("./createLiveScene-CWBunxPi.js").then(({ createLiveScene: i }) => {
624
+ if (!e) try {
625
+ t = i(A.current, n), M.current = t, re("3d");
626
+ } catch {
627
+ r();
628
+ }
629
+ }).catch(r), () => {
630
+ e = !0, t?.dispose(), M.current === t && (M.current = null);
631
+ };
632
+ }, [
633
+ U,
634
+ W,
635
+ L
636
+ ]), _(() => {
637
+ if (!U || O.status !== "active" || !A.current) return;
638
+ let r = !1, i = 0, a = performance.now(), o = 0, s = null, c = oe(), l = /* @__PURE__ */ new Set();
639
+ d();
640
+ let m;
641
+ try {
642
+ let r = t.getState().createLiveSignaling(e);
643
+ m = z({
644
+ iceServers: D?.iceServers,
645
+ iceTransportPolicy: D?.iceTransportPolicy,
646
+ game: O,
647
+ selfId: String(n),
648
+ isHost: String(O.hostId) === String(n),
649
+ signaling: r
650
+ }), j.current = m;
651
+ } catch (e) {
652
+ I(e.message || "No se pudo iniciar WebRTC");
653
+ return;
654
+ }
655
+ G(m.getRender().arena);
656
+ function h() {
657
+ l.clear(), Q(N.current), u();
658
+ }
659
+ function g(e, t) {
660
+ /^(INPUT|TEXTAREA|SELECT)$/.test(e.target?.tagName) || [
661
+ "KeyW",
662
+ "KeyA",
663
+ "KeyS",
664
+ "KeyD",
665
+ "ArrowUp",
666
+ "ArrowDown",
667
+ "ArrowLeft",
668
+ "ArrowRight",
669
+ "Space"
670
+ ].includes(e.code) && (e.preventDefault(), t ? l.add(e.code) : l.delete(e.code), N.current.throttle = Number(l.has("KeyW") || l.has("ArrowUp")) - Number(l.has("KeyS") || l.has("ArrowDown")), N.current.steer = Number(l.has("KeyD") || l.has("ArrowRight")) - Number(l.has("KeyA") || l.has("ArrowLeft")), N.current.fire = l.has("Space"));
671
+ }
672
+ let _ = (e) => g(e, !0), v = (e) => g(e, !1), y = A.current;
673
+ y.addEventListener("keydown", _), y.addEventListener("keyup", v), y.addEventListener("blur", h);
674
+ let b = () => {
675
+ document.hidden && h();
676
+ };
677
+ document.addEventListener("visibilitychange", b), f({ type: "engine_start" }, e);
678
+ function x(n) {
679
+ if (r) return;
680
+ let d = Math.min(80, n - a);
681
+ a = n;
682
+ let h = k.current || document.hidden;
683
+ m.setInput(h ? {
684
+ throttle: 0,
685
+ steer: 0,
686
+ fire: !1
687
+ } : N.current), m.step(d);
688
+ let g = m.getRender();
689
+ if (h || M.current?.render(g, d), h && (l.clear(), c.reset(), u()), !h) for (let e of g.events || []) for (let t of Z(e)) f(t, e.id);
690
+ if (!h) for (let e of c.update(J(g.tanks), d)) f(e);
691
+ let _ = se(g);
692
+ _ && !s && (F(g), s = _, h || p(s, e), t.getState().liveFinish?.(e, g.winner)), n - o > 100 && (o = n, F(g)), i = requestAnimationFrame(x);
693
+ }
694
+ return i = requestAnimationFrame(x), () => {
695
+ r = !0, cancelAnimationFrame(i), h(), m.destroy(), j.current = null, y.removeEventListener("keydown", _), y.removeEventListener("keyup", v), y.removeEventListener("blur", h), document.removeEventListener("visibilitychange", b);
696
+ };
697
+ }, [
698
+ U,
699
+ e,
700
+ n
701
+ ]), !O) return null;
702
+ let K = String(n) === String(O.guestId), q = P?.status === "over" || O.status === "won", Y = P?.net, X = Y?.manualTurn, le = [
703
+ "waiting_peer",
704
+ "sharing",
705
+ "applying"
706
+ ].includes(X?.status), $ = !H && (B >= 12e3 || Y?.phase === "failed" || Y?.ice === "failed" || X?.status === "failed" || !!te), fe = H ? Y?.route?.relay === !0 ? "TURN Relay" : Y?.route?.relay === !1 ? "P2P" : null : null, pe = async (e, t) => {
707
+ if (!j.current?.configureTurn) throw Error("La partida aún no está preparada. Espera un momento y vuelve a intentarlo.");
708
+ await j.current.configureTurn(e, t);
709
+ };
710
+ function me(e) {
711
+ let t = A.current?.getBoundingClientRect(), n = J(P?.tanks);
712
+ if (!t || !n) return;
713
+ let r = M.current?.screenToGround((e.clientX - t.left) / t.width * 2 - 1, 1 - (e.clientY - t.top) / t.height * 2);
714
+ r && (N.current.turretYaw = Math.atan2(r.z - n.z, r.x - n.x));
715
+ }
716
+ let he = (e, t) => ({
717
+ onPointerDown: (n) => {
718
+ n.preventDefault(), n.currentTarget.setPointerCapture(n.pointerId), N.current[e] = t;
719
+ },
720
+ onPointerUp: () => {
721
+ N.current[e] = e !== "fire" && 0;
722
+ },
723
+ onPointerCancel: () => {
724
+ N.current[e] = e !== "fire" && 0;
725
+ },
726
+ onLostPointerCapture: () => {
727
+ N.current[e] = e !== "fire" && 0;
728
+ }
729
+ });
730
+ return /* @__PURE__ */ E("section", {
731
+ className: `chat-game-card tl-card${U ? " tl-card--active" : ""}`,
732
+ "aria-label": "Tanques LIVE 3D",
733
+ children: [
734
+ /* @__PURE__ */ E("header", {
735
+ className: "tl-header",
736
+ children: [/* @__PURE__ */ T("strong", { children: "Tanques LIVE 3D" }), /* @__PURE__ */ E("div", {
737
+ className: "tl-header-actions",
738
+ children: [
739
+ /* @__PURE__ */ T(o, { manager: m() }),
740
+ r && /* @__PURE__ */ T("button", {
741
+ onClick: r,
742
+ "aria-label": "Minimizar",
743
+ children: "−"
744
+ }),
745
+ i && /* @__PURE__ */ T("button", {
746
+ onClick: i,
747
+ "aria-label": "Ocultar",
748
+ children: "×"
749
+ })
750
+ ]
751
+ })]
752
+ }),
753
+ O.status === "invited" && /* @__PURE__ */ E("div", {
754
+ className: "tl-invite",
755
+ children: [
756
+ /* @__PURE__ */ T("span", {
757
+ className: "tl-invite-icon",
758
+ "aria-hidden": "true",
759
+ children: "🪖"
760
+ }),
761
+ /* @__PURE__ */ T("strong", { children: K ? "¿Listo para combatir?" : "Invitación enviada" }),
762
+ /* @__PURE__ */ T("p", { children: K ? "Te invitaron a un combate en tiempo real." : "Esperando que el rival acepte…" }),
763
+ K && /* @__PURE__ */ E("div", {
764
+ className: "tl-invite-actions",
765
+ children: [/* @__PURE__ */ T("button", {
766
+ className: "tl-button-primary",
767
+ onClick: () => ue(e, "game_accept"),
768
+ children: "Aceptar combate"
769
+ }), /* @__PURE__ */ T("button", {
770
+ onClick: () => ue(e, "game_decline"),
771
+ children: "Rechazar"
772
+ })]
773
+ })
774
+ ]
775
+ }),
776
+ U && !q && /* @__PURE__ */ E("div", {
777
+ className: `tl-connection tl-connection--${H ? "connected" : $ ? "problem" : "pending"}`,
778
+ children: [
779
+ /* @__PURE__ */ E("div", {
780
+ className: "tl-connection-heading",
781
+ children: [
782
+ H ? /* @__PURE__ */ T(x, {
783
+ size: 18,
784
+ "aria-hidden": "true"
785
+ }) : $ ? /* @__PURE__ */ T(b, {
786
+ size: 18,
787
+ "aria-hidden": "true"
788
+ }) : /* @__PURE__ */ T(ee, {
789
+ size: 18,
790
+ className: "tl-connection-spinner",
791
+ "aria-hidden": "true"
792
+ }),
793
+ /* @__PURE__ */ E("div", { children: [/* @__PURE__ */ T("strong", { children: $ ? "Problemas de conexión" : de(Y, !1) }), $ && /* @__PURE__ */ T("p", { children: "No pudimos establecer una conexión con el otro jugador. Puedes configurar una conexión alternativa para continuar." })] }),
794
+ fe && /* @__PURE__ */ T("span", {
795
+ className: "tl-route-badge",
796
+ children: fe
797
+ })
798
+ ]
799
+ }),
800
+ !H && /* @__PURE__ */ T("p", {
801
+ className: "tl-connection-message",
802
+ role: "status",
803
+ children: $ ? de(Y, B >= 12e3) : s(Y)
804
+ }),
805
+ X?.status === "synchronized" && /* @__PURE__ */ T("p", {
806
+ className: "tl-connection-shared",
807
+ role: "status",
808
+ children: X.received ? "Configuración recibida del otro jugador y aplicada en ambos." : "Configuración compartida y aplicada en ambos jugadores."
809
+ }),
810
+ X?.expiresAt != null && X.expiresAt <= Date.now() && /* @__PURE__ */ T("p", {
811
+ className: "tl-connection-expired",
812
+ role: "status",
813
+ children: "La validez indicada para las credenciales terminó. Introduce una configuración nueva si necesitas reconectar."
814
+ }),
815
+ /* @__PURE__ */ E("div", {
816
+ className: "tl-connection-actions",
817
+ children: [/* @__PURE__ */ E("button", {
818
+ type: "button",
819
+ className: $ ? "tl-button-primary" : "",
820
+ onClick: () => ae(!0),
821
+ children: [/* @__PURE__ */ T(C, {
822
+ size: 15,
823
+ "aria-hidden": "true"
824
+ }), "Configurar conexión alternativa"]
825
+ }), !H && /* @__PURE__ */ E("button", {
826
+ type: "button",
827
+ disabled: le,
828
+ onClick: () => j.current?.reconnect(),
829
+ children: [/* @__PURE__ */ T(S, {
830
+ size: 15,
831
+ "aria-hidden": "true"
832
+ }), "Reintentar conexión"]
833
+ })]
834
+ })
835
+ ]
836
+ }),
837
+ /* @__PURE__ */ T(c, {
838
+ open: ie && U && !q,
839
+ onClose: () => ae(!1),
840
+ onApply: pe,
841
+ manualTurn: X
842
+ }),
843
+ (U || P) && /* @__PURE__ */ E(w, { children: [
844
+ /* @__PURE__ */ E("div", {
845
+ className: "tl-hud",
846
+ children: [(P?.tanks || []).map((e) => /* @__PURE__ */ E("span", { children: [
847
+ e.self ? "Tú" : "Rival",
848
+ " ",
849
+ /* @__PURE__ */ T("meter", {
850
+ min: "0",
851
+ max: "100",
852
+ value: e.hp,
853
+ "aria-label": e.self ? "Tu vida" : "Vida del rival"
854
+ }),
855
+ " ",
856
+ e.hp,
857
+ " HP"
858
+ ] }, e.id)), /* @__PURE__ */ E("span", {
859
+ role: "status",
860
+ children: [
861
+ H ? fe || "Conectado" : de(Y, B >= 12e3),
862
+ " ",
863
+ Number.isFinite(Y?.rtt) ? `· ${Math.round(Y.rtt)} ms` : ""
864
+ ]
865
+ })]
866
+ }),
867
+ /* @__PURE__ */ T("div", {
868
+ className: "tl-stage",
869
+ ref: A,
870
+ tabIndex: 0,
871
+ "aria-label": "Arena. WASD o flechas para conducir, ratón para apuntar, clic o espacio para disparar",
872
+ onPointerMove: me,
873
+ onPointerDown: (e) => {
874
+ me(e), e.pointerType === "mouse" && (e.currentTarget.focus(), e.currentTarget.setPointerCapture(e.pointerId), me(e), N.current.fire = !0);
875
+ },
876
+ onPointerUp: () => {
877
+ N.current.fire = !1;
878
+ },
879
+ onPointerCancel: () => {
880
+ Q(N.current);
881
+ },
882
+ onLostPointerCapture: () => {
883
+ N.current.fire = !1;
884
+ }
885
+ }),
886
+ /* @__PURE__ */ E("div", {
887
+ className: "tl-controls",
888
+ children: [
889
+ /* @__PURE__ */ T("div", {
890
+ className: "tl-joystick",
891
+ role: "group",
892
+ "aria-label": "Joystick de conducción",
893
+ onPointerDown: (e) => {
894
+ e.preventDefault(), e.currentTarget.setPointerCapture(e.pointerId);
895
+ let t = e.currentTarget.getBoundingClientRect();
896
+ N.current.steer = Math.max(-1, Math.min(1, (e.clientX - t.left - t.width / 2) / (t.width / 2))), N.current.throttle = Math.max(-1, Math.min(1, -(e.clientY - t.top - t.height / 2) / (t.height / 2)));
897
+ },
898
+ onPointerMove: (e) => {
899
+ if (!e.currentTarget.hasPointerCapture(e.pointerId)) return;
900
+ let t = e.currentTarget.getBoundingClientRect();
901
+ N.current.steer = Math.max(-1, Math.min(1, (e.clientX - t.left - t.width / 2) / (t.width / 2))), N.current.throttle = Math.max(-1, Math.min(1, -(e.clientY - t.top - t.height / 2) / (t.height / 2)));
902
+ },
903
+ onPointerUp: () => Q(N.current),
904
+ onPointerCancel: () => Q(N.current),
905
+ onLostPointerCapture: () => Q(N.current),
906
+ children: "✥"
907
+ }),
908
+ /* @__PURE__ */ E("div", {
909
+ className: "tl-drive",
910
+ "aria-label": "Controles de conducción",
911
+ children: [
912
+ /* @__PURE__ */ T("button", {
913
+ "aria-label": "Avanzar",
914
+ ...he("throttle", 1),
915
+ children: "▲"
916
+ }),
917
+ /* @__PURE__ */ T("button", {
918
+ "aria-label": "Girar izquierda",
919
+ ...he("steer", -1),
920
+ children: "◀"
921
+ }),
922
+ /* @__PURE__ */ T("button", {
923
+ "aria-label": "Retroceder",
924
+ ...he("throttle", -1),
925
+ children: "▼"
926
+ }),
927
+ /* @__PURE__ */ T("button", {
928
+ "aria-label": "Girar derecha",
929
+ ...he("steer", 1),
930
+ children: "▶"
931
+ })
932
+ ]
933
+ }),
934
+ /* @__PURE__ */ T("button", {
935
+ className: "tl-fire",
936
+ ...he("fire", !0),
937
+ children: "Disparar"
938
+ })
939
+ ]
940
+ }),
941
+ /* @__PURE__ */ T("div", {
942
+ className: "tl-reload",
943
+ children: /* @__PURE__ */ E("label", { children: [
944
+ "Recarga ",
945
+ /* @__PURE__ */ T("progress", {
946
+ max: "1",
947
+ value: J(P?.tanks)?.reload ?? 1
948
+ }),
949
+ " ",
950
+ (J(P?.tanks)?.reload ?? 1) >= 1 ? "Listo" : "Recargando…"
951
+ ] })
952
+ }),
953
+ /* @__PURE__ */ T("small", { children: "WASD / flechas · ratón o toca la arena para apuntar · espacio / clic para disparar" }),
954
+ /* @__PURE__ */ T("button", {
955
+ onClick: () => R((e) => !e),
956
+ children: ne === "2d" ? "Probar 3D" : "Vista 2D"
957
+ })
958
+ ] }),
959
+ q && /* @__PURE__ */ E("p", {
960
+ role: "status",
961
+ children: [
962
+ String(P?.winner ?? O.winnerId) === String(n) ? "¡Victoria!" : "Fin del combate",
963
+ " ",
964
+ /* @__PURE__ */ T("button", {
965
+ onClick: () => {
966
+ Promise.resolve(t.getState().liveRematch?.(e)).catch(() => {});
967
+ },
968
+ children: "Revancha"
969
+ })
970
+ ]
971
+ }),
972
+ U && /* @__PURE__ */ E("details", {
973
+ className: "tl-diagnostics",
974
+ children: [/* @__PURE__ */ T("summary", { children: "Diagnóstico de conexión" }), /* @__PURE__ */ T("pre", { children: JSON.stringify(l(P?.net), null, 2) })]
975
+ }),
976
+ U && !q && /* @__PURE__ */ T("button", {
977
+ onClick: () => j.current?.resign(),
978
+ children: "Rendirse"
979
+ }),
980
+ O.pending && /* @__PURE__ */ T("p", {
981
+ role: "status",
982
+ children: "Enviando…"
983
+ }),
984
+ O.pendingEvent && O.error && /* @__PURE__ */ T("button", {
985
+ onClick: () => {
986
+ t.getState().retry(e).catch(() => {});
987
+ },
988
+ children: "Reintentar envío"
989
+ }),
990
+ te && /* @__PURE__ */ T("p", {
991
+ role: "alert",
992
+ children: te
993
+ }),
994
+ O.error && /* @__PURE__ */ T("p", {
995
+ role: "alert",
996
+ children: O.error
997
+ }),
998
+ !["closed", "declined"].includes(O.status) && /* @__PURE__ */ T("footer", {
999
+ className: "tl-footer",
1000
+ children: /* @__PURE__ */ T("button", {
1001
+ onClick: () => ue(e, "game_end"),
1002
+ children: "Cerrar partida"
1003
+ })
1004
+ })
1005
+ ]
1006
+ });
1007
+ }
1008
+ var fe = h($);
1009
+ export { Y as a, q as c, fe as default, W as i, X as l, B as n, G as o, H as r, K as s, le as t };
1010
+
1011
+ //# sourceMappingURL=TanksLiveGameCard-COr9Oay5.js.map