@minicode-dev/chat 0.0.0-stage → 0.1.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 (45) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +123 -2
  3. package/assets/sounds/battleship_audio_pack/assets/cannon_fire.ogg +0 -0
  4. package/assets/sounds/battleship_audio_pack/assets/cruiser_damage_alarm.ogg +0 -0
  5. package/assets/sounds/battleship_audio_pack/assets/defeat.ogg +0 -0
  6. package/assets/sounds/battleship_audio_pack/assets/ocean_ambient_loop.ogg +0 -0
  7. package/assets/sounds/battleship_audio_pack/assets/projectile_flyby.ogg +0 -0
  8. package/assets/sounds/battleship_audio_pack/assets/ship_heavy_hit.ogg +0 -0
  9. package/assets/sounds/battleship_audio_pack/assets/ship_hit.ogg +0 -0
  10. package/assets/sounds/battleship_audio_pack/assets/ship_place.ogg +0 -0
  11. package/assets/sounds/battleship_audio_pack/assets/ship_rotate.ogg +0 -0
  12. package/assets/sounds/battleship_audio_pack/assets/ship_sinking.ogg +0 -0
  13. package/assets/sounds/battleship_audio_pack/assets/sonar_ping.ogg +0 -0
  14. package/assets/sounds/battleship_audio_pack/assets/ui_click.ogg +0 -0
  15. package/assets/sounds/battleship_audio_pack/assets/victory.ogg +0 -0
  16. package/assets/sounds/battleship_audio_pack/assets/water_splash.ogg +0 -0
  17. package/assets/sounds/connect4/close.ogg +0 -0
  18. package/assets/sounds/connect4/draw.ogg +0 -0
  19. package/assets/sounds/connect4/drop.ogg +0 -0
  20. package/assets/sounds/connect4/invite.ogg +0 -0
  21. package/assets/sounds/connect4/lose.ogg +0 -0
  22. package/assets/sounds/connect4/start.ogg +0 -0
  23. package/assets/sounds/connect4/turn.ogg +0 -0
  24. package/assets/sounds/connect4/win.ogg +0 -0
  25. package/assets/sounds/notification.mp3 +0 -0
  26. package/assets/sounds/notification.ogg +0 -0
  27. package/assets/sounds/ting.mp3 +0 -0
  28. package/assets/sounds/ting.ogg +0 -0
  29. package/dist/chunks/BattleshipGameCard-CW_A8Nim.js +958 -0
  30. package/dist/chunks/BattleshipGameCard-CW_A8Nim.js.map +1 -0
  31. package/dist/chunks/BattleshipPrototype-Duz-S1JE.js +373 -0
  32. package/dist/chunks/BattleshipPrototype-Duz-S1JE.js.map +1 -0
  33. package/dist/chunks/battleship-DXKuIZ1I.js +124 -0
  34. package/dist/chunks/battleship-DXKuIZ1I.js.map +1 -0
  35. package/dist/chunks/connect4Sounds-Do3nvVFx.js +1847 -0
  36. package/dist/chunks/connect4Sounds-Do3nvVFx.js.map +1 -0
  37. package/dist/chunks/createBattleScene-HIAvjixn.js +1621 -0
  38. package/dist/chunks/createBattleScene-HIAvjixn.js.map +1 -0
  39. package/dist/chunks/webglSupport-2WjPEPZ_.js +16 -0
  40. package/dist/chunks/webglSupport-2WjPEPZ_.js.map +1 -0
  41. package/dist/index.js +9519 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/styles.css +2 -0
  44. package/index.d.ts +470 -0
  45. package/package.json +66 -4
@@ -0,0 +1,1847 @@
1
+ import { a as e, c as t, i as n, n as r, r as i, s as a, t as o } from "./battleship-DXKuIZ1I.js";
2
+ import { useSyncExternalStore as s } from "react";
3
+ import { createStore as c } from "zustand/vanilla";
4
+ import { useStore as l } from "zustand";
5
+ import { jsx as u, jsxs as d } from "react/jsx-runtime";
6
+ import { Volume2 as f, VolumeX as p } from "lucide-react";
7
+ // src/games/shared/protocol.js
8
+ var m = "LIRA_GAME_V1:", h = 4096, g = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, _ = (e) => typeof e == "object" && !!e && !Array.isArray(e), v = (e) => typeof e == "string" && e.length > 0 && e.length <= 256 && e.trim() === e, y = (e) => typeof e == "string" && g.test(e), b = (e) => Array.isArray(e) && e.length <= 42 && e.every((e) => Array.isArray(e) && e.length === 2 && Number.isInteger(e[0]) && e[0] >= 0 && e[0] < 7 && y(e[1])) && new Set(e.map((e) => e[1])).size === e.length, x = (e) => b(e.moves) && e.rev === e.moves.length && (e.accept_event_id === void 0 ? e.moves.length === 0 : y(e.accept_event_id)), S = [
9
+ "carrier",
10
+ "battleship",
11
+ "cruiser",
12
+ "submarine",
13
+ "destroyer"
14
+ ], C = (e) => Number.isInteger(e) && e >= 0 && e < 10, w = (e) => typeof e == "string" && /^[0-9a-f]{64}$/.test(e), T = (e) => Number.isInteger(e) && e >= 1 && e <= 200, ee = (e) => e === null || _(e) && S.includes(e.ship_id) && Array.isArray(e.cells) && e.cells.length >= 2 && e.cells.length <= 5 && e.cells.every((e) => Array.isArray(e) && e.length === 2 && C(e[0]) && C(e[1])), E = (e) => Array.isArray(e) && e.length === S.length && e.every((e) => _(e) && S.includes(e.ship_id) && C(e.row) && C(e.col) && (e.orientation === "horizontal" || e.orientation === "vertical")) && new Set(e.map((e) => e.ship_id)).size === e.length, te = (e, t) => Array.isArray(e) && C(e[0]) && C(e[1]) && (e.length === 2 && t || e.length === 3 && (e[2] === 0 || e[2] === 1) || e.length === 7 && e[2] === 2 && Number.isInteger(e[3]) && e[3] >= 0 && e[3] < S.length && C(e[4]) && C(e[5]) && (e[6] === 0 || e[6] === 1)), D = (e) => Array.isArray(e.commits) && e.commits.length === 2 && e.commits.every((e) => e === null || w(e)) && Array.isArray(e.log) && e.log.length <= 200 && e.log.every((t, n) => te(t, n === e.log.length - 1)) && y(e.head) && (e.accept_event_id === void 0 ? e.commits.every((e) => e === null) && e.log.length === 0 : y(e.accept_event_id)) && (e.log.length === 0 || e.commits.every(Boolean));
15
+ function ne(e) {
16
+ let t = e.data;
17
+ switch (e.type) {
18
+ case "game_invite": return v(t.opponent_id) && t.rules_version === 1;
19
+ case "game_accept":
20
+ case "game_decline": return y(t.invite_event_id);
21
+ case "game_end": return ["closed", "win"].includes(t.reason) && (t.winner_id === void 0 || v(t.winner_id));
22
+ case "bs_commit": return w(t.commitment);
23
+ case "bs_fire": return T(t.ply) && C(t.row) && C(t.col) && y(t.prev_event_id);
24
+ case "bs_result": return T(t.ply) && C(t.row) && C(t.col) && ["hit", "miss"].includes(t.result) && ee(t.sunk) && typeof t.defeated == "boolean" && (t.result === "hit" || t.sunk === null && !t.defeated);
25
+ case "bs_reveal": return E(t.fleet) && typeof t.salt == "string" && /^[0-9a-f]{32}$/.test(t.salt);
26
+ case "bs_sync_request": return D(t);
27
+ case "bs_sync_state": return D(t) && y(t.request_event_id);
28
+ default: return !1;
29
+ }
30
+ }
31
+ function O(e) {
32
+ return typeof e == "string" && e.startsWith("LIRA_GAME_V1:");
33
+ }
34
+ function k(e) {
35
+ if (!_(e) || e.version !== 1 || !["connect4", "battleship"].includes(e.game) || !y(e.game_id) || !y(e.event_id) || !_(e.data)) return !1;
36
+ if (e.game === "battleship") return ne(e);
37
+ let t = e.data;
38
+ switch (e.type) {
39
+ case "game_invite": return v(t.opponent_id) && t.rules_version === 1;
40
+ case "game_accept":
41
+ case "game_decline": return y(t.invite_event_id);
42
+ case "game_move": return Number.isInteger(t.column) && t.column >= 0 && t.column < 7 && Number.isInteger(t.ply) && t.ply >= 1 && t.ply <= 42 && y(t.prev_event_id);
43
+ case "game_end": return [
44
+ "closed",
45
+ "win",
46
+ "draw"
47
+ ].includes(t.reason) && (t.winner_id === void 0 || v(t.winner_id)) && (t.final_move_event_id === void 0 || y(t.final_move_event_id)) && (t.reason !== "win" || v(t.winner_id) && y(t.final_move_event_id)) && (t.reason !== "draw" || y(t.final_move_event_id));
48
+ case "game_resync_request": return x(t);
49
+ case "game_resync_state": return x(t) && y(t.request_event_id);
50
+ default: return !1;
51
+ }
52
+ }
53
+ function re(e) {
54
+ if (!O(e) || e.length > h) return null;
55
+ try {
56
+ let t = JSON.parse(e.slice(13));
57
+ return k(t) ? t : null;
58
+ } catch {
59
+ return null;
60
+ }
61
+ }
62
+ function A(e) {
63
+ if (!k(e)) throw Error("Evento de juego inválido");
64
+ let t = m + JSON.stringify(e);
65
+ if (t.length > h) throw Error("Evento de juego demasiado grande");
66
+ return t;
67
+ }
68
+ function j(e, { game_id: t, data: n, event_id: r = crypto.randomUUID(), game: i = "connect4" }) {
69
+ let a = {
70
+ version: 1,
71
+ game: i,
72
+ game_id: t,
73
+ event_id: r,
74
+ type: e,
75
+ data: n
76
+ };
77
+ if (!k(a)) throw Error("Evento de juego inválido");
78
+ return a;
79
+ }
80
+ function ie() {
81
+ return Array.from({ length: 6 }, () => Array(7).fill(null));
82
+ }
83
+ var ae = [
84
+ [0, 1],
85
+ [1, 0],
86
+ [1, 1],
87
+ [1, -1]
88
+ ];
89
+ function oe(e) {
90
+ for (let t = 0; t < 6; t += 1) for (let n = 0; n < 7; n += 1) {
91
+ let r = e[t][n];
92
+ if (r != null) for (let [i, a] of ae) {
93
+ let o = [];
94
+ for (let s = 0; s < 4; s += 1) {
95
+ let c = t + i * s, l = n + a * s;
96
+ if (c < 0 || c >= 6 || l < 0 || l >= 7 || e[c][l] !== r) break;
97
+ o.push([c, l]);
98
+ }
99
+ if (o.length === 4) return o;
100
+ }
101
+ }
102
+ return [];
103
+ }
104
+ function se(e) {
105
+ let t = oe(e);
106
+ return t.length ? e[t[0][0]][t[0][1]] : null;
107
+ }
108
+ function ce(e) {
109
+ return e[0].every((e) => e !== null);
110
+ }
111
+ function le(e, t, n) {
112
+ if (!Number.isInteger(t) || t < 0 || t >= 7 || n == null || se(e) !== null) return null;
113
+ let r = 5;
114
+ for (; r >= 0 && e[r][t] !== null;) --r;
115
+ if (r < 0) return null;
116
+ let i = e.map((e) => e.slice());
117
+ i[r][t] = n;
118
+ let a = oe(i), o = a.length ? i[a[0][0]][a[0][1]] : null;
119
+ return {
120
+ board: i,
121
+ row: r,
122
+ column: t,
123
+ winner: o,
124
+ draw: o === null && ce(i),
125
+ winningCells: a
126
+ };
127
+ }
128
+ // src/games/battleship/logic/game.js
129
+ var ue = (e) => typeof e == "string" && e.length > 0 && e.length <= 256 && e.trim() === e;
130
+ function de({ gameId: e, players: t, firstPlayerId: n = t?.[0] } = {}) {
131
+ if (!ue(e) || !Array.isArray(t) || t.length !== 2 || !t.every(ue) || t[0] === t[1] || !t.includes(n)) throw TypeError("Supply a gameId, two distinct player IDs and a valid firstPlayerId.");
132
+ return {
133
+ game: "battleship",
134
+ rulesVersion: 1,
135
+ gameId: e,
136
+ players: t.slice(),
137
+ boards: [r(), r()],
138
+ ready: [!1, !1],
139
+ phase: "placement",
140
+ turnId: null,
141
+ firstPlayerId: n,
142
+ winnerId: null,
143
+ shotCount: 0,
144
+ lastShot: null,
145
+ revision: 0
146
+ };
147
+ }
148
+ function fe(n, r) {
149
+ if (!n || !r || typeof r != "object" || n.phase === "finished" || r.gameId !== void 0 && r.gameId !== n.gameId || r.expectedRevision !== void 0 && r.expectedRevision !== n.revision) return n;
150
+ let o = n.players.indexOf(r.playerId);
151
+ if (o < 0) return n;
152
+ let s = n.boards[o];
153
+ if (n.phase === "placement") {
154
+ if (n.ready[o]) return n;
155
+ if (r.type === "place_ship" || r.type === "remove_ship") {
156
+ let e = r.type === "place_ship" ? a(s, r) : t(s, r.shipId);
157
+ if (!e.ok) return n;
158
+ let i = n.boards.slice();
159
+ return i[o] = e.board, {
160
+ ...n,
161
+ boards: i,
162
+ revision: n.revision + 1
163
+ };
164
+ }
165
+ if (r.type === "ready" && e(s)) {
166
+ let e = n.ready.slice();
167
+ e[o] = !0;
168
+ let t = e.every(Boolean);
169
+ return {
170
+ ...n,
171
+ ready: e,
172
+ phase: t ? "playing" : "placement",
173
+ turnId: t ? n.firstPlayerId : null,
174
+ revision: n.revision + 1
175
+ };
176
+ }
177
+ return n;
178
+ }
179
+ if (n.phase !== "playing" || r.type !== "fire" || r.playerId !== n.turnId) return n;
180
+ let c = 1 - o, l = i(n.boards[c], r);
181
+ if (!l.ok) return n;
182
+ let u = n.boards.slice();
183
+ return u[c] = l.board, {
184
+ ...n,
185
+ boards: u,
186
+ revision: n.revision + 1,
187
+ shotCount: n.shotCount + 1,
188
+ phase: l.defeated ? "finished" : "playing",
189
+ turnId: l.defeated ? null : n.players[c],
190
+ winnerId: l.defeated ? r.playerId : null,
191
+ lastShot: {
192
+ playerId: r.playerId,
193
+ targetId: n.players[c],
194
+ row: r.row,
195
+ col: r.col,
196
+ result: l.result,
197
+ shipId: l.shipId,
198
+ sunk: l.sunk,
199
+ defeated: l.defeated
200
+ }
201
+ };
202
+ }
203
+ // src/games/battleship/net/session.js
204
+ var M = o.reduce((e, t) => e + t.size, 0), pe = /^[0-9a-f]{32}$/, me = [
205
+ "won",
206
+ "closed",
207
+ "declined"
208
+ ], N = "La partida perdió sincronización. Se intentará resincronizar.", he = "Falta la aceptación de la partida. Ciérrala y vuelve a invitar.", ge = "El rival envió un resultado imposible para ese disparo.", _e = "Tu flota no está disponible en este dispositivo; no se pueden responder disparos.", P = () => Array.from({ length: 10 }, () => Array(10).fill(null)), ve = (e, t, n, r) => e.map((e, i) => i === t ? e.map((e, t) => t === n ? r : e) : e), ye = (e) => e.reduce((e, t) => e + t.filter((e) => e === "hit").length, 0), be = (e) => e.reduce((e, t) => e + t.filter((e) => e !== null).length, 0), xe = (e, t) => t % 2 == 1 ? e.hostId : e.guestId, Se = (e, t) => t === e.hostId ? e.guestId : e.hostId, Ce = (e, t) => t === e.hostId ? "hostCommitment" : "guestCommitment", F = (e, t) => ({
209
+ ...e,
210
+ status: "conflict",
211
+ error: t
212
+ }), I = (e) => `${e.row},${e.col}`, we = (e, t) => e.row - t.row || e.col - t.col, Te = (e, t) => e.length === t.length && e.map(I).sort().join("|") === t.map(I).sort().join("|");
213
+ function Ee(e) {
214
+ return {
215
+ ...e,
216
+ game: "battleship",
217
+ status: "invited",
218
+ turnId: null,
219
+ myFleet: [],
220
+ myReady: !1,
221
+ opponentReady: !1,
222
+ incomingShots: P(),
223
+ targetShots: P(),
224
+ sunkEnemyShips: [],
225
+ pendingShot: null,
226
+ lastShot: null,
227
+ winnerId: null,
228
+ verification: null,
229
+ ply: 0,
230
+ shots: [],
231
+ acceptEventId: null,
232
+ hostCommitment: null,
233
+ guestCommitment: null,
234
+ myCommitment: null,
235
+ mySalt: null,
236
+ myRevealSent: !1,
237
+ opponentReveal: null,
238
+ seen: e.seen ?? {},
239
+ pending: !1,
240
+ pendingEvent: null,
241
+ error: "",
242
+ sync: e.sync ?? null
243
+ };
244
+ }
245
+ var L = (e) => e?.game === "battleship" && ["invited", "placement"].includes(e.status) && !e.myReady, De = (e) => e?.status === "active" && e.turnId === e.ownId && !e.pendingShot, R = (e) => ({
246
+ id: e.id,
247
+ size: e.size,
248
+ orientation: e.orientation,
249
+ cells: e.cells.map((e) => ({
250
+ row: e.row,
251
+ col: e.col
252
+ }))
253
+ }), Oe = (e) => ({
254
+ shipId: e.id,
255
+ row: e.cells[0].row,
256
+ col: e.cells[0].col,
257
+ orientation: e.orientation
258
+ });
259
+ function ke(e) {
260
+ return !e || typeof e != "object" ? null : typeof e.ship_id == "string" ? {
261
+ shipId: e.ship_id,
262
+ row: e.row,
263
+ col: e.col,
264
+ orientation: e.orientation
265
+ } : typeof e.id == "string" && Array.isArray(e.cells) && e.cells.length ? Oe(e) : null;
266
+ }
267
+ function z(e) {
268
+ if (!Array.isArray(e)) return null;
269
+ let t = r();
270
+ for (let n of e) {
271
+ let e = ke(n), r = e && a(t, e);
272
+ if (!r?.ok) return null;
273
+ t = r.board;
274
+ }
275
+ return t;
276
+ }
277
+ function B(e) {
278
+ if (!Array.isArray(e)) return null;
279
+ let t = e.map(ke);
280
+ return t.some((e) => !e) ? null : t.map(({ shipId: e, row: t, col: n, orientation: r }) => ({
281
+ ship_id: e,
282
+ row: t,
283
+ col: n,
284
+ orientation: r
285
+ })).sort((e, t) => e.ship_id < t.ship_id ? -1 : +(e.ship_id > t.ship_id));
286
+ }
287
+ function V(t) {
288
+ let n = z(t);
289
+ return n && e(n) ? n.ships.map(R) : null;
290
+ }
291
+ var Ae = (e) => !!V(e);
292
+ function je(t) {
293
+ let n = z(t?.myFleet);
294
+ return n && e(n) ? {
295
+ ...n,
296
+ shots: t.incomingShots.map((e) => e.slice())
297
+ } : null;
298
+ }
299
+ function Me(e, { shipId: t, row: n, col: r, orientation: i } = {}) {
300
+ if (!L(e)) return e;
301
+ let o = z(e.myFleet.filter((e) => e.id !== t)), s = o && a(o, {
302
+ shipId: t,
303
+ row: n,
304
+ col: r,
305
+ orientation: i
306
+ });
307
+ return s?.ok ? {
308
+ ...e,
309
+ myFleet: s.board.ships.map(R)
310
+ } : e;
311
+ }
312
+ function Ne(e, t) {
313
+ return !L(e) || !e.myFleet.some((e) => e.id === t) ? e : {
314
+ ...e,
315
+ myFleet: e.myFleet.filter((e) => e.id !== t)
316
+ };
317
+ }
318
+ function Pe(e) {
319
+ let t = Math.floor(4294967296 / e) * e, n = /* @__PURE__ */ new Uint32Array(1);
320
+ do
321
+ globalThis.crypto.getRandomValues(n);
322
+ while (n[0] >= t);
323
+ return n[0] % e;
324
+ }
325
+ function Fe(t = Pe) {
326
+ for (let n = 0; n < 50; n += 1) {
327
+ let n = r();
328
+ for (let e of o) for (let r = 0; r < 300; r += 1) {
329
+ let r = a(n, {
330
+ shipId: e.id,
331
+ row: t(10),
332
+ col: t(10),
333
+ orientation: t(2) === 0 ? "horizontal" : "vertical"
334
+ });
335
+ if (r.ok) {
336
+ n = r.board;
337
+ break;
338
+ }
339
+ }
340
+ if (e(n)) return n.ships.map(R);
341
+ }
342
+ throw Error("No se pudo generar una flota aleatoria.");
343
+ }
344
+ var Ie = (e, t) => L(e) ? {
345
+ ...e,
346
+ myFleet: Fe(t)
347
+ } : e, Le = (e) => Array.from(e, (e) => e.toString(16).padStart(2, "0")).join("");
348
+ function Re() {
349
+ let e = /* @__PURE__ */ new Uint8Array(16);
350
+ return globalThis.crypto.getRandomValues(e), Le(e);
351
+ }
352
+ function ze(e, t) {
353
+ let n = B(e);
354
+ if (!n || typeof t != "string") throw TypeError("Flota inválida");
355
+ return JSON.stringify({
356
+ fleet: n,
357
+ salt: t
358
+ });
359
+ }
360
+ async function Be(e, t) {
361
+ let n = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(ze(e, t)));
362
+ return Le(new Uint8Array(n));
363
+ }
364
+ function Ve(e, t) {
365
+ if (!e || !t) return null;
366
+ let n = i(e, {
367
+ row: t.row,
368
+ col: t.col
369
+ });
370
+ if (!n.ok) return null;
371
+ let r = n.sunk ? e.ships.find((e) => e.id === n.shipId) : null;
372
+ return {
373
+ ply: t.ply,
374
+ row: t.row,
375
+ col: t.col,
376
+ result: n.result,
377
+ sunk: r ? {
378
+ ship_id: r.id,
379
+ cells: r.cells.map((e) => [e.row, e.col])
380
+ } : null,
381
+ defeated: n.defeated
382
+ };
383
+ }
384
+ function He(e) {
385
+ let t = o.find((t) => t.id === e?.ship_id);
386
+ if (!t || !Array.isArray(e.cells) || e.cells.length !== t.size) return null;
387
+ let r = e.cells.map((e) => Array.isArray(e) ? {
388
+ row: e[0],
389
+ col: e[1]
390
+ } : null);
391
+ if (r.some((e) => !n(e))) return null;
392
+ r.sort(we);
393
+ let i = r.every((e, t) => e.row === r[0].row && e.col === r[0].col + t), a = r.every((e, t) => e.col === r[0].col && e.row === r[0].row + t);
394
+ return !i && !a ? null : {
395
+ id: t.id,
396
+ size: t.size,
397
+ orientation: i ? "horizontal" : "vertical",
398
+ cells: r,
399
+ sunk: !0
400
+ };
401
+ }
402
+ function Ue(e, t) {
403
+ let { row: n, col: r, result: i, sunk: a } = t, s = !!t.defeated;
404
+ if (i !== "hit" && i !== "miss" || e.targetShots[n][r] !== null) return null;
405
+ let c = ve(e.targetShots, n, r, i), l = ye(c), u = null;
406
+ if (a) {
407
+ if (u = i === "hit" ? He(a) : null, !u || e.sunkEnemyShips.some((e) => e.id === u.id)) return null;
408
+ let t = new Set(e.sunkEnemyShips.flatMap((e) => e.cells.map(I)));
409
+ if (!u.cells.some((e) => e.row === n && e.col === r) || u.cells.some((e) => c[e.row][e.col] !== "hit" || t.has(I(e)))) return null;
410
+ }
411
+ let d = e.sunkEnemyShips.length + +!!u;
412
+ return l > M || s !== (l === M) || s !== (d === o.length) || !s && M - l > 100 - be(c) ? null : {
413
+ shots: c,
414
+ ship: u
415
+ };
416
+ }
417
+ function We(e, t) {
418
+ let n = Ve(je(e), t);
419
+ if (!n || n.result !== t.result || n.defeated !== !!t.defeated || !!n.sunk != !!t.sunk) return null;
420
+ let r = n.sunk ? He(n.sunk) : null;
421
+ return r && (t.sunk.ship_id !== r.id || !Te(r.cells, t.sunk.cells.map(([e, t]) => ({
422
+ row: e,
423
+ col: t
424
+ })))) ? null : {
425
+ shots: ve(e.incomingShots, t.row, t.col, t.result),
426
+ ship: r
427
+ };
428
+ }
429
+ function Ge(e, t, n, r) {
430
+ let i = Ce(e, t);
431
+ if (e[i]) return e[i] === n ? e : null;
432
+ let a = {
433
+ ...e,
434
+ [i]: n
435
+ };
436
+ if (t === e.ownId) {
437
+ let t = r?.commitment === n ? V(r.fleet) : null;
438
+ t && pe.test(r.salt ?? "") ? a = {
439
+ ...a,
440
+ myFleet: t,
441
+ mySalt: r.salt,
442
+ myCommitment: n
443
+ } : e.myCommitment === n && e.mySalt || (a = {
444
+ ...a,
445
+ myFleet: [],
446
+ mySalt: null,
447
+ myCommitment: n,
448
+ error: _e
449
+ }), a.myReady = !0;
450
+ } else a.opponentReady = !0;
451
+ return a.hostCommitment && a.guestCommitment && (a = {
452
+ ...a,
453
+ status: "active",
454
+ turnId: e.hostId,
455
+ ply: 0,
456
+ pendingShot: null
457
+ }), a;
458
+ }
459
+ function Ke(e, t, { row: r, col: i, ply: a }, o) {
460
+ let s = t === e.ownId ? e.targetShots : e.incomingShots;
461
+ return !n({
462
+ row: r,
463
+ col: i
464
+ }) || s[r][i] !== null ? null : {
465
+ ...e,
466
+ pendingShot: {
467
+ row: r,
468
+ col: i,
469
+ ply: a,
470
+ by: t
471
+ },
472
+ lastEventId: o ?? e.lastEventId
473
+ };
474
+ }
475
+ function qe(e, t, n, r) {
476
+ let i = e.pendingShot, a = t === e.ownId, o = a ? We(e, n) : Ue(e, n);
477
+ if (!o) return null;
478
+ let s = !!n.defeated, c = {
479
+ ply: i.ply,
480
+ by: i.by,
481
+ row: i.row,
482
+ col: i.col,
483
+ result: n.result,
484
+ sunk: o.ship,
485
+ defeated: s
486
+ };
487
+ return {
488
+ ...e,
489
+ incomingShots: a ? o.shots : e.incomingShots,
490
+ targetShots: a ? e.targetShots : o.shots,
491
+ sunkEnemyShips: !a && o.ship ? [...e.sunkEnemyShips, o.ship] : e.sunkEnemyShips,
492
+ ply: i.ply,
493
+ shots: [...e.shots, c],
494
+ pendingShot: null,
495
+ lastShot: {
496
+ ...c,
497
+ eventId: r ?? null
498
+ },
499
+ lastEventId: r ?? e.lastEventId,
500
+ turnId: s ? null : t,
501
+ status: s ? "won" : "active",
502
+ winnerId: s ? i.by : null,
503
+ verification: s ? "pending" : e.verification
504
+ };
505
+ }
506
+ function Je(e, t, n) {
507
+ let { ply: r, row: i, col: a, prev_event_id: o } = t.data;
508
+ return n === xe(e, r) ? e.status === "active" ? r <= e.ply ? e : e.pendingShot ? r === e.pendingShot.ply ? e : F(e, N) : r > e.ply + 1 ? F(e, N) : n === e.turnId ? o === e.lastEventId ? Ke(e, n, {
509
+ row: i,
510
+ col: a,
511
+ ply: r
512
+ }, t.event_id) ?? e : F(e, N) : e : F(e, e.status === "invited" ? he : N) : e;
513
+ }
514
+ function Ye(e, t, n) {
515
+ let { ply: r, row: i, col: a } = t.data;
516
+ if (e.status !== "active") return e.status === "placement" ? F(e, N) : e;
517
+ let o = e.pendingShot;
518
+ return o ? r === o.ply ? n === o.by ? e : i !== o.row || a !== o.col ? n === e.ownId ? e : F(e, "El rival respondió a un disparo distinto.") : qe(e, n, t.data, t.event_id) || (n === e.ownId ? e : F(e, ge)) : r < o.ply ? e : F(e, N) : r <= e.ply ? e : F(e, N);
519
+ }
520
+ function Xe(e, t, n) {
521
+ return !e.winnerId || !["won", "closed"].includes(e.status) ? e : n === e.ownId ? e.myRevealSent ? e : {
522
+ ...e,
523
+ myRevealSent: !0
524
+ } : e.opponentReveal ? e : {
525
+ ...e,
526
+ opponentReveal: {
527
+ fleet: t.fleet.map((e) => ({ ...e })),
528
+ salt: t.salt
529
+ },
530
+ verification: "pending"
531
+ };
532
+ }
533
+ function Ze(e, t, n, r = {}) {
534
+ if (!e || e.game !== "battleship" || t?.game !== "battleship" || t.game_id !== e.gameId || n !== e.hostId && n !== e.guestId) return e;
535
+ let i = t.data;
536
+ if (t.type === "game_end") return i.reason !== "closed" || [
537
+ "closed",
538
+ "declined",
539
+ "won"
540
+ ].includes(e.status) ? e : {
541
+ ...e,
542
+ status: "closed",
543
+ closedBy: n,
544
+ error: ""
545
+ };
546
+ if (t.type === "bs_reveal") return Xe(e, i, n);
547
+ if (me.includes(e.status) || e.status === "conflict") return e;
548
+ switch (t.type) {
549
+ case "game_accept":
550
+ case "game_decline": return n !== e.guestId || e.status !== "invited" || i.invite_event_id !== e.inviteEventId ? e : t.type === "game_accept" ? {
551
+ ...e,
552
+ status: "placement",
553
+ acceptEventId: t.event_id,
554
+ lastEventId: t.event_id
555
+ } : {
556
+ ...e,
557
+ status: "declined",
558
+ lastEventId: t.event_id
559
+ };
560
+ case "bs_commit": return e.status === "invited" ? F(e, he) : e.status === "placement" ? Ge(e, n, i.commitment, r.stored) ?? e : e;
561
+ case "bs_fire": return Je(e, t, n);
562
+ case "bs_result": return Ye(e, t, n);
563
+ default: return e;
564
+ }
565
+ }
566
+ function Qe(e, t) {
567
+ let n = de({
568
+ gameId: String(e.gameId),
569
+ players: [e.hostId, e.guestId],
570
+ firstPlayerId: e.hostId
571
+ });
572
+ for (let e of n.players) {
573
+ for (let r of t[e]) n = fe(n, {
574
+ type: "place_ship",
575
+ playerId: e,
576
+ ...Oe(r)
577
+ });
578
+ n = fe(n, {
579
+ type: "ready",
580
+ playerId: e
581
+ });
582
+ }
583
+ if (n.phase !== "playing") return !1;
584
+ for (let t of e.shots) {
585
+ let e = fe(n, {
586
+ type: "fire",
587
+ playerId: t.by,
588
+ row: t.row,
589
+ col: t.col
590
+ });
591
+ if (e === n) return !1;
592
+ let r = e.lastShot;
593
+ if (r.result !== t.result || r.defeated !== t.defeated || r.sunk !== !!t.sunk) return !1;
594
+ if (t.sunk) {
595
+ let n = e.boards[e.players.indexOf(r.targetId)].ships.find((e) => e.id === r.shipId);
596
+ if (t.sunk.id !== r.shipId || !Te(n.cells, t.sunk.cells)) return !1;
597
+ }
598
+ n = e;
599
+ }
600
+ return !e.winnerId || n.winnerId === e.winnerId;
601
+ }
602
+ async function $e(e, t = e?.opponentReveal) {
603
+ if (!e || !t) return "pending";
604
+ let n = Se(e, e.ownId), r = e[Ce(e, n)], i = V(t.fleet);
605
+ if (!r || !i || typeof t.salt != "string" || !pe.test(t.salt)) return "mismatch";
606
+ let a;
607
+ try {
608
+ a = await Be(t.fleet, t.salt);
609
+ } catch {
610
+ return "mismatch";
611
+ }
612
+ if (a !== r) return "mismatch";
613
+ let o = V(e.myFleet);
614
+ return o ? Qe(e, {
615
+ [e.ownId]: o,
616
+ [n]: i
617
+ }) ? "ok" : "mismatch" : "pending";
618
+ }
619
+ var et = (e) => {
620
+ if (e.result === "miss") return [
621
+ e.row,
622
+ e.col,
623
+ 0
624
+ ];
625
+ if (!e.sunk) return [
626
+ e.row,
627
+ e.col,
628
+ 1
629
+ ];
630
+ let t = e.sunk.cells[0];
631
+ return [
632
+ e.row,
633
+ e.col,
634
+ 2,
635
+ o.findIndex((t) => t.id === e.sunk.id),
636
+ t.row,
637
+ t.col,
638
+ +(e.sunk.orientation === "vertical")
639
+ ];
640
+ };
641
+ function tt(e) {
642
+ if (!e.acceptEventId) return {
643
+ commits: [null, null],
644
+ log: [],
645
+ head: e.inviteEventId
646
+ };
647
+ let t = e.shots.map(et);
648
+ return e.pendingShot && t.push([e.pendingShot.row, e.pendingShot.col]), {
649
+ accept_event_id: e.acceptEventId,
650
+ commits: [e.hostCommitment ?? null, e.guestCommitment ?? null],
651
+ log: t,
652
+ head: e.lastEventId
653
+ };
654
+ }
655
+ function nt(e, t) {
656
+ let n = e.accept_event_id ?? null, r = t.accept_event_id ?? null;
657
+ if (n && r && n !== r) return "diverged";
658
+ let i = /* @__PURE__ */ new Set();
659
+ n && !r && i.add("ahead"), !n && r && i.add("behind");
660
+ for (let n of [0, 1]) {
661
+ let r = e.commits?.[n] ?? null, a = t.commits?.[n] ?? null;
662
+ if (r && a && r !== a) return "diverged";
663
+ r && !a && i.add("ahead"), !r && a && i.add("behind");
664
+ }
665
+ let a = e.log ?? [], o = t.log ?? [];
666
+ for (let e = 0; e < Math.min(a.length, o.length); e += 1) {
667
+ let t = a[e], n = o[e];
668
+ if (t.length === n.length) {
669
+ if (t.some((e, t) => e !== n[t])) return "diverged";
670
+ } else if (t[0] !== n[0] || t[1] !== n[1]) return "diverged";
671
+ else i.add(t.length === 2 ? "behind" : "ahead");
672
+ }
673
+ return a.length !== o.length && i.add(a.length < o.length ? "behind" : "ahead"), i.size === 2 ? "mixed" : i.size === 1 ? [...i][0] : a.length && e.head !== t.head ? "diverged" : "equal";
674
+ }
675
+ function rt(e, t) {
676
+ if ((e.log ?? []).length || (t.log ?? []).length) return null;
677
+ let n = e.accept_event_id ?? t.accept_event_id;
678
+ return n ? {
679
+ accept_event_id: n,
680
+ commits: [0, 1].map((n) => e.commits?.[n] ?? t.commits?.[n] ?? null),
681
+ log: [],
682
+ head: n
683
+ } : null;
684
+ }
685
+ function it(e, t, n = {}) {
686
+ let r = {
687
+ ...e,
688
+ status: "invited",
689
+ turnId: null,
690
+ myReady: !1,
691
+ opponentReady: !1,
692
+ incomingShots: P(),
693
+ targetShots: P(),
694
+ sunkEnemyShips: [],
695
+ pendingShot: null,
696
+ lastShot: null,
697
+ winnerId: null,
698
+ verification: null,
699
+ ply: 0,
700
+ shots: [],
701
+ acceptEventId: null,
702
+ hostCommitment: null,
703
+ guestCommitment: null,
704
+ error: "",
705
+ myRevealSent: !1,
706
+ opponentReveal: null,
707
+ closedBy: void 0
708
+ }, i = t.log ?? [], a = t.commits ?? [null, null];
709
+ if (!t.accept_event_id) return a.some(Boolean) || i.length ? null : {
710
+ ...r,
711
+ lastEventId: e.inviteEventId
712
+ };
713
+ if (t.accept_event_id === e.inviteEventId) return null;
714
+ let s = e.ownId === e.hostId ? 0 : 1;
715
+ if (e.myCommitment && a[s] && a[s] !== e.myCommitment && n.stored?.commitment !== a[s]) return null;
716
+ let c = {
717
+ ...r,
718
+ status: "placement",
719
+ acceptEventId: t.accept_event_id,
720
+ lastEventId: t.accept_event_id
721
+ };
722
+ for (let [t, r] of [e.hostId, e.guestId].entries()) if (a[t] && (c = Ge(c, r, a[t], n.stored), !c)) return null;
723
+ if (i.length && c.status !== "active") return null;
724
+ for (let e = 0; e < i.length; e += 1) {
725
+ let t = i[e], n = e + 1;
726
+ if (c = Ke(c, xe(c, n), {
727
+ row: t[0],
728
+ col: t[1],
729
+ ply: n
730
+ }, null), !c) return null;
731
+ if (t.length === 2) {
732
+ if (e !== i.length - 1) return null;
733
+ break;
734
+ }
735
+ let r = Se(c, c.pendingShot.by), a = null;
736
+ if (t[2] === 2) {
737
+ let e = o[t[3]];
738
+ if (!e) return null;
739
+ let n = t[6] === 1;
740
+ a = {
741
+ ship_id: e.id,
742
+ cells: Array.from({ length: e.size }, (e, r) => [t[4] + (n ? r : 0), t[5] + (n ? 0 : r)])
743
+ };
744
+ }
745
+ let s = ye(r === c.ownId ? c.incomingShots : c.targetShots) + (t[2] === 0 ? 0 : 1);
746
+ if (c = qe(c, r, {
747
+ ply: n,
748
+ row: t[0],
749
+ col: t[1],
750
+ result: t[2] === 0 ? "miss" : "hit",
751
+ sunk: a,
752
+ defeated: s === M
753
+ }, null), !c || c.status === "won" && e !== i.length - 1) return null;
754
+ }
755
+ return !i.length && t.head !== t.accept_event_id ? null : (c = {
756
+ ...c,
757
+ lastEventId: t.head
758
+ }, c.winnerId && e.winnerId === c.winnerId && (c = {
759
+ ...c,
760
+ myRevealSent: e.myRevealSent,
761
+ opponentReveal: e.opponentReveal,
762
+ verification: e.verification
763
+ }), c);
764
+ }
765
+ function at(e, t) {
766
+ if (!e || !t) return !1;
767
+ let n = e.log?.[(t.data?.ply ?? 0) - 1];
768
+ switch (t.type) {
769
+ case "game_accept": return e.accept_event_id === t.event_id;
770
+ case "bs_commit": return (e.commits ?? []).includes(t.data.commitment);
771
+ case "bs_fire": return !!(n && n[0] === t.data.row && n[1] === t.data.col);
772
+ case "bs_result": return !!(n && n.length > 2 && n[0] === t.data.row && n[1] === t.data.col);
773
+ default: return !1;
774
+ }
775
+ }
776
+ function ot(e, t) {
777
+ let n = { ...e };
778
+ return t.acceptEventId && (n[t.acceptEventId] = !0), t.lastEventId && (n[t.lastEventId] = !0), n;
779
+ }
780
+ // src/games/battleship/net/fleetStorage.js
781
+ var st = "lira:bs:", ct = 12096e5, lt = (e, t) => `${st}${e}:${t}`, ut = () => {
782
+ try {
783
+ return globalThis.localStorage ?? null;
784
+ } catch {
785
+ return null;
786
+ }
787
+ };
788
+ function dt(e) {
789
+ return typeof e == "object" && !!e && Array.isArray(e.fleet) && e.fleet.length === 5 && typeof e.salt == "string" && /^[0-9a-f]{32}$/.test(e.salt) && typeof e.commitment == "string" && /^[0-9a-f]{64}$/.test(e.commitment);
790
+ }
791
+ function ft(e) {
792
+ let t = Date.now();
793
+ for (let n = e.length - 1; n >= 0; --n) {
794
+ let r = e.key(n);
795
+ if (r?.startsWith(st)) try {
796
+ let n = JSON.parse(e.getItem(r));
797
+ dt(n) && t - n.savedAt < ct || e.removeItem(r);
798
+ } catch {
799
+ e.removeItem(r);
800
+ }
801
+ }
802
+ }
803
+ function pt(e, t, { fleet: n, salt: r, commitment: i }) {
804
+ try {
805
+ let a = ut();
806
+ return a ? (ft(a), a.setItem(lt(e, t), JSON.stringify({
807
+ fleet: n,
808
+ salt: r,
809
+ commitment: i,
810
+ savedAt: Date.now()
811
+ })), !0) : !1;
812
+ } catch {
813
+ return !1;
814
+ }
815
+ }
816
+ function mt(e, t) {
817
+ try {
818
+ let n = JSON.parse(ut()?.getItem(lt(e, t)) ?? "null");
819
+ return dt(n) ? {
820
+ fleet: n.fleet,
821
+ salt: n.salt,
822
+ commitment: n.commitment
823
+ } : null;
824
+ } catch {
825
+ return null;
826
+ }
827
+ }
828
+ // src/games/shared/useChatGames.js
829
+ var ht = ["connect4", "battleship"], H = (e) => e?.game ?? "connect4", U = (e) => H(e) === "battleship", gt = 250, W = (e) => [
830
+ "won",
831
+ "draw",
832
+ "closed",
833
+ "declined"
834
+ ].includes(e.status), _t = (e, t, n) => JSON.stringify([
835
+ e,
836
+ String(t),
837
+ n
838
+ ]), vt = (e) => {
839
+ let t = Object.keys(e).filter((t) => W(e[t]));
840
+ if (t.length <= 80) return e;
841
+ let n = { ...e };
842
+ return t.slice(0, t.length - 80).forEach((e) => {
843
+ delete n[e];
844
+ }), n;
845
+ };
846
+ function yt(e, t, n) {
847
+ if (![e.hostId, e.guestId].includes(n)) return e;
848
+ if (t.type === "game_end" && t.data.reason === "closed") return ["closed", "declined"].includes(e.status) ? e : {
849
+ ...e,
850
+ status: "closed",
851
+ closedBy: n,
852
+ error: ""
853
+ };
854
+ if (W(e) || e.status === "conflict") return e;
855
+ if (t.type === "game_accept" || t.type === "game_decline") return n !== e.guestId || e.status !== "invited" || t.data.invite_event_id !== e.inviteEventId ? e : {
856
+ ...e,
857
+ status: t.type === "game_accept" ? "active" : "declined",
858
+ lastEventId: t.event_id,
859
+ acceptEventId: t.type === "game_accept" ? t.event_id : e.acceptEventId
860
+ };
861
+ if (t.type !== "game_move") return e;
862
+ let { ply: r, prev_event_id: i, column: a } = t.data;
863
+ if (n !== (r % 2 == 1 ? e.hostId : e.guestId)) return e;
864
+ if (e.status !== "active") return {
865
+ ...e,
866
+ status: "conflict",
867
+ error: "Falta la aceptación de la partida. Ciérrala y vuelve a invitar."
868
+ };
869
+ if (r <= e.ply || r > e.ply + 1 || i !== e.lastEventId) return {
870
+ ...e,
871
+ status: "conflict",
872
+ error: "La partida perdió sincronización. Ciérrala y envía una nueva invitación."
873
+ };
874
+ if (n !== e.turnId) return e;
875
+ let o = le(e.board, a, n);
876
+ return o ? {
877
+ ...e,
878
+ board: o.board,
879
+ ply: r,
880
+ lastEventId: t.event_id,
881
+ moves: [...e.moves ?? [], [a, t.event_id]],
882
+ lastMove: {
883
+ row: o.row,
884
+ column: a,
885
+ eventId: t.event_id
886
+ },
887
+ winnerId: o.winner || null,
888
+ winningCells: o.winningCells,
889
+ status: o.winner ? "won" : o.draw ? "draw" : "active",
890
+ turnId: n === e.hostId ? e.guestId : e.hostId
891
+ } : e;
892
+ }
893
+ var bt = 8e3, G = {
894
+ status: "idle",
895
+ requestId: null,
896
+ requestedAt: 0,
897
+ auto: !1,
898
+ outgoing: [],
899
+ replies: [],
900
+ offer: null,
901
+ message: ""
902
+ }, xt = (e) => [
903
+ "game_resync_request",
904
+ "game_resync_state",
905
+ "bs_sync_request",
906
+ "bs_sync_state"
907
+ ].includes(e), St = (e) => e.acceptEventId ? {
908
+ accept_event_id: e.acceptEventId,
909
+ moves: e.moves ?? [],
910
+ rev: (e.moves ?? []).length
911
+ } : {
912
+ moves: [],
913
+ rev: 0
914
+ };
915
+ function Ct(e, t, n) {
916
+ let r = {
917
+ ...e,
918
+ board: ie(),
919
+ ply: 0,
920
+ turnId: e.hostId,
921
+ winnerId: null,
922
+ winningCells: [],
923
+ lastMove: null,
924
+ moves: [],
925
+ error: ""
926
+ };
927
+ if (!t) return n.length ? null : {
928
+ ...r,
929
+ status: "invited",
930
+ acceptEventId: null,
931
+ lastEventId: e.inviteEventId
932
+ };
933
+ if (t === e.inviteEventId) return null;
934
+ let i = {
935
+ ...r,
936
+ status: "active",
937
+ acceptEventId: t,
938
+ lastEventId: t
939
+ }, a = /* @__PURE__ */ new Set([e.inviteEventId, t]);
940
+ for (let t = 0; t < n.length; t += 1) {
941
+ let [r, o] = n[t];
942
+ if (a.has(o)) return null;
943
+ a.add(o);
944
+ let s = t % 2 == 0 ? e.hostId : e.guestId, c = yt(i, {
945
+ type: "game_move",
946
+ event_id: o,
947
+ data: {
948
+ column: r,
949
+ ply: t + 1,
950
+ prev_event_id: i.lastEventId
951
+ }
952
+ }, s);
953
+ if (c.status === "conflict" || c.ply !== t + 1 || c.lastEventId !== o) return null;
954
+ i = c;
955
+ }
956
+ return i;
957
+ }
958
+ function wt(e, t) {
959
+ if (e.acceptEventId && t.acceptEventId && e.acceptEventId !== t.acceptEventId) return "diverged";
960
+ let n = Math.min(e.moves.length, t.moves.length);
961
+ for (let r = 0; r < n; r += 1) if (e.moves[r][0] !== t.moves[r][0] || e.moves[r][1] !== t.moves[r][1]) return "diverged";
962
+ return e.moves.length === t.moves.length ? e.acceptEventId && !t.acceptEventId ? "ahead" : !e.acceptEventId && t.acceptEventId ? "behind" : "equal" : e.moves.length < t.moves.length ? "behind" : "ahead";
963
+ }
964
+ var Tt = (e) => e.pendingEvent?.type === "game_move" && !e.pending ? e.pendingEvent.event_id : null, Et = {
965
+ requestType: "game_resync_request",
966
+ stateType: "game_resync_state",
967
+ historyOf: St,
968
+ rebuild: (e, t) => Ct(e, t.accept_event_id ?? null, t.moves),
969
+ compare: (e, t) => wt({
970
+ acceptEventId: e.acceptEventId ?? null,
971
+ moves: e.moves ?? []
972
+ }, {
973
+ acceptEventId: t.accept_event_id ?? null,
974
+ moves: t.moves
975
+ }),
976
+ offerOf: (e) => ({
977
+ accept_event_id: e.accept_event_id ?? null,
978
+ moves: e.moves
979
+ }),
980
+ covers: (e, t) => {
981
+ let n = Tt(e);
982
+ return !!(n && t.moves?.some((e) => e[1] === n));
983
+ },
984
+ markSeen: (e, t) => {
985
+ let n = { ...e };
986
+ return t.acceptEventId && (n[t.acceptEventId] = !0), (t.moves ?? []).forEach((e) => {
987
+ n[e[1]] = !0;
988
+ }), n;
989
+ },
990
+ merge: () => null
991
+ }, Dt = (e) => ({
992
+ requestType: "bs_sync_request",
993
+ stateType: "bs_sync_state",
994
+ historyOf: tt,
995
+ rebuild: (t, n) => it(t, n, { stored: e(t.scope, t.gameId) }),
996
+ compare: (e, t) => nt(tt(e), t),
997
+ offerOf: (e) => ({
998
+ accept_event_id: e.accept_event_id,
999
+ commits: e.commits,
1000
+ log: e.log,
1001
+ head: e.head
1002
+ }),
1003
+ covers: (e, t) => !!(e.pendingEvent && !e.pending && at(t, e.pendingEvent)),
1004
+ markSeen: ot,
1005
+ merge: (e, t) => rt(tt(e), t)
1006
+ }), Ot = (e, t, n) => j(t, {
1007
+ game_id: e.gameId,
1008
+ data: n,
1009
+ game: H(e)
1010
+ });
1011
+ function kt() {
1012
+ let e = null, t = /* @__PURE__ */ new Map(), n = (e, n) => t.get(`${e}:${n}`) ?? mt(e, n), r = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Set(), a = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Set(), s = Dt(n), l = (e) => U(e) ? s : Et;
1013
+ return c((s, c) => ({
1014
+ games: {},
1015
+ configureTransport: (t) => {
1016
+ e = t;
1017
+ },
1018
+ clear: () => {
1019
+ r.forEach((e) => clearTimeout(e)), r.clear(), o.forEach((e) => clearTimeout(e)), o.clear(), t.clear(), i.clear(), a.clear(), s({ games: {} });
1020
+ },
1021
+ markDisconnected: (e) => s((t) => ({ games: Object.fromEntries(Object.entries(t.games).map(([t, n]) => [t, n.scope === e && !W(n) ? {
1022
+ ...n,
1023
+ status: "conflict",
1024
+ error: "Conexión interrumpida. Se intentará resincronizar al reconectar.",
1025
+ sync: {
1026
+ ...G,
1027
+ ...n.sync,
1028
+ status: "idle",
1029
+ auto: !1
1030
+ }
1031
+ } : n])) })),
1032
+ ingest: (t, r, i) => {
1033
+ let o = typeof r == "object" ? r : {
1034
+ scope: r,
1035
+ currentUserId: i
1036
+ }, l = o?.scope ?? e?.getScope?.(), u = String(o?.currentUserId ?? e?.getUserId?.() ?? ""), d = t.data ?? t.payload, f = d && typeof d == "object" ? {
1037
+ ...d,
1038
+ ...t
1039
+ } : t, p = f.message ?? f.text;
1040
+ if (typeof p != "string" || !p.startsWith("LIRA_GAME_V1:")) return !1;
1041
+ let m = re(p), h = String(f.room_id ?? ""), g = String(f.user_id ?? "");
1042
+ if (!m || !l || !u || !g || !h.startsWith("private_")) return !0;
1043
+ let _ = h.slice(8).split("_");
1044
+ if (_.length !== 2 || !_.includes(u) || !_.includes(g)) return !0;
1045
+ let v = _t(l, h, m.game_id), y = c().games[v];
1046
+ if (y && H(y) !== m.game) return !0;
1047
+ if (xt(m.type)) return y && !y.seen[m.event_id] && c().handleResync(v, m, g, u), !0;
1048
+ if (!y && m.type !== "game_invite") {
1049
+ let e = Date.now();
1050
+ for (let [t, n] of a) e - n.at > 3e4 && a.delete(t);
1051
+ !a.has(v) && a.size >= 32 && a.delete(a.keys().next().value);
1052
+ let t = a.get(v) ?? {
1053
+ at: e,
1054
+ messages: []
1055
+ };
1056
+ return t.messages.length < 8 && !t.messages.some((e) => e.eventId === m.event_id) && t.messages.push({
1057
+ eventId: m.event_id,
1058
+ message: f
1059
+ }), a.set(v, t), !0;
1060
+ }
1061
+ if (y?.seen[m.event_id]) return !0;
1062
+ let b = y;
1063
+ if (m.type === "game_invite") {
1064
+ let e = m.data.opponent_id;
1065
+ if (y || e === g || !_.includes(e)) return !0;
1066
+ b = m.game === "battleship" ? Ee({
1067
+ key: v,
1068
+ gameId: m.game_id,
1069
+ game_id: m.game_id,
1070
+ scope: l,
1071
+ roomId: h,
1072
+ ownId: u,
1073
+ hostId: g,
1074
+ guestId: e,
1075
+ createdAt: f.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
1076
+ inviteEventId: m.event_id,
1077
+ lastEventId: m.event_id,
1078
+ seen: {},
1079
+ sync: { ...G }
1080
+ }) : {
1081
+ key: v,
1082
+ gameId: m.game_id,
1083
+ game_id: m.game_id,
1084
+ game: "connect4",
1085
+ scope: l,
1086
+ roomId: h,
1087
+ ownId: u,
1088
+ hostId: g,
1089
+ guestId: e,
1090
+ turnId: g,
1091
+ status: "invited",
1092
+ board: ie(),
1093
+ ply: 0,
1094
+ winnerId: null,
1095
+ lastMove: null,
1096
+ createdAt: f.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
1097
+ inviteEventId: m.event_id,
1098
+ lastEventId: m.event_id,
1099
+ seen: {},
1100
+ pending: !1,
1101
+ error: "",
1102
+ pendingEvent: null,
1103
+ acceptEventId: null,
1104
+ moves: [],
1105
+ sync: { ...G }
1106
+ };
1107
+ } else U(y) ? b = Ze(y, m, g, { stored: m.type === "bs_commit" && g === u ? n(l, m.game_id) : null }) : y && (b = yt(y, m, g));
1108
+ if (!b || b === y) return !0;
1109
+ if (b = {
1110
+ ...b,
1111
+ seen: {
1112
+ ...b.seen,
1113
+ [m.event_id]: !0
1114
+ }
1115
+ }, s((e) => {
1116
+ let t = {
1117
+ ...e.games,
1118
+ [v]: b
1119
+ };
1120
+ if (m.type === "game_invite") {
1121
+ let e = Object.values(t).filter((e) => e.scope === l && e.roomId === h && !W(e)), n = e.sort((e, t) => e.gameId < t.gameId ? -1 : +(e.gameId > t.gameId))[0];
1122
+ e.forEach((e) => {
1123
+ e.key !== n?.key && (t[e.key] = {
1124
+ ...e,
1125
+ status: "closed",
1126
+ error: "Se conserva la otra invitación de esta conversación."
1127
+ });
1128
+ });
1129
+ }
1130
+ return { games: vt(t) };
1131
+ }), b.status === "conflict" && y?.status !== "conflict" && queueMicrotask(() => {
1132
+ c().requestResync(v, { auto: !0 });
1133
+ }), U(b) && c().bsScheduleEffects(v), m.type === "game_invite") {
1134
+ let e = a.get(v);
1135
+ a.delete(v), e && Date.now() - e.at <= 3e4 && e.messages.forEach((e) => c().ingest(e.message, l, u));
1136
+ }
1137
+ return !0;
1138
+ },
1139
+ invite: async ({ roomId: t, opponentId: n, gameType: r = "connect4" }) => {
1140
+ if (!e) throw Error("Chat no disponible");
1141
+ if (!ht.includes(r)) throw Error("Juego no disponible");
1142
+ let i = e.getScope();
1143
+ if (!String(e.getUserId() ?? "") || !String(t).startsWith("private_")) throw Error("Abre un chat privado para jugar.");
1144
+ if (Object.values(c().games).some((e) => e.scope === i && e.roomId === String(t) && (!W(e) || e.pendingEvent))) throw Error("Cierra la partida actual antes de invitar.");
1145
+ let a = j("game_invite", {
1146
+ game_id: crypto.randomUUID(),
1147
+ data: {
1148
+ opponent_id: String(n),
1149
+ rules_version: 1
1150
+ },
1151
+ game: r
1152
+ });
1153
+ return c().sendEvent(t, a);
1154
+ },
1155
+ act: async (t, n, r = {}) => {
1156
+ let i = c().games[t], a = String(e?.getUserId?.() ?? "");
1157
+ if (!i || i.scope !== e?.getScope?.()) throw Error("Partida no disponible");
1158
+ if (n !== "game_end" && (i.pending || i.pendingEvent)) throw Error("Reintenta el envío pendiente antes de continuar.");
1159
+ let o = r;
1160
+ if (n === "game_accept" || n === "game_decline") {
1161
+ if (i.status !== "invited" || a !== i.guestId) return;
1162
+ o = { invite_event_id: i.inviteEventId };
1163
+ } else if (n === "game_move") {
1164
+ if (U(i) || i.status !== "active" || a !== i.turnId || !le(i.board, r.column, a)) return;
1165
+ o = {
1166
+ column: r.column,
1167
+ ply: i.ply + 1,
1168
+ prev_event_id: i.lastEventId
1169
+ };
1170
+ } else if (n === "game_end") o = { reason: "closed" };
1171
+ else return;
1172
+ return c().sendEvent(i.roomId, j(n, {
1173
+ game_id: i.gameId,
1174
+ data: o,
1175
+ game: H(i)
1176
+ }));
1177
+ },
1178
+ bsUpdateLocal: (e, t) => {
1179
+ let n = c().games[e];
1180
+ if (!U(n)) return !1;
1181
+ let r = t(n);
1182
+ return r !== n && (s((t) => t.games[e] === n ? { games: {
1183
+ ...t.games,
1184
+ [e]: r
1185
+ } } : t), c().games[e] === r);
1186
+ },
1187
+ bsPlaceShip: (e, t) => c().bsUpdateLocal(e, (e) => Me(e, t)),
1188
+ bsRemoveShip: (e, t) => c().bsUpdateLocal(e, (e) => Ne(e, t)),
1189
+ bsRandomFleet: (e) => c().bsUpdateLocal(e, (e) => Ie(e)),
1190
+ bsReady: async (n) => {
1191
+ let r = c().games[n];
1192
+ if (!U(r) || r.status !== "placement" || r.myReady) return;
1193
+ if (r.scope !== e?.getScope?.()) throw Error("Partida no disponible");
1194
+ if (r.pending || r.pendingEvent) throw Error("Reintenta el envío pendiente antes de continuar.");
1195
+ let i = B(r.myFleet);
1196
+ if (!Ae(i)) throw Error("Coloca los cinco barcos antes de continuar.");
1197
+ let a = Re(), o = await Be(i, a), s = c().games[n];
1198
+ if (!(!s || s.myReady || s.status !== "placement" || s.pending || s.pendingEvent || JSON.stringify(B(s.myFleet)) !== JSON.stringify(i))) return t.set(`${r.scope}:${r.gameId}`, {
1199
+ fleet: i,
1200
+ salt: a,
1201
+ commitment: o
1202
+ }), pt(r.scope, r.gameId, {
1203
+ fleet: i,
1204
+ salt: a,
1205
+ commitment: o
1206
+ }), c().sendEvent(r.roomId, j("bs_commit", {
1207
+ game_id: r.gameId,
1208
+ data: { commitment: o },
1209
+ game: "battleship"
1210
+ }));
1211
+ },
1212
+ bsFire: async (t, { row: n, col: r } = {}) => {
1213
+ let i = c().games[t];
1214
+ if (!U(i) || i.scope !== e?.getScope?.()) throw Error("Partida no disponible");
1215
+ if (i.pending || i.pendingEvent) throw Error("Reintenta el envío pendiente antes de continuar.");
1216
+ if (De(i) && i.targetShots[n]?.[r] === null) return c().sendEvent(i.roomId, j("bs_fire", {
1217
+ game_id: i.gameId,
1218
+ data: {
1219
+ ply: i.ply + 1,
1220
+ row: n,
1221
+ col: r,
1222
+ prev_event_id: i.lastEventId
1223
+ },
1224
+ game: "battleship"
1225
+ }));
1226
+ },
1227
+ bsScheduleEffects: (e) => {
1228
+ r.has(e) || r.set(e, setTimeout(() => {
1229
+ r.delete(e), c().bsRunEffects(e);
1230
+ }, gt));
1231
+ },
1232
+ bsRunEffects: (t) => {
1233
+ let r = c().games[t];
1234
+ if (!U(r) || !e || r.scope !== e.getScope?.()) return;
1235
+ if (r.opponentReveal && r.verification === "pending" && !i.has(t)) {
1236
+ let e = r.opponentReveal;
1237
+ i.add(t), $e(r, e).then((n) => s((r) => {
1238
+ let i = r.games[t];
1239
+ return !i || i.opponentReveal !== e || i.verification === n ? r : { games: {
1240
+ ...r.games,
1241
+ [t]: {
1242
+ ...i,
1243
+ verification: n
1244
+ }
1245
+ } };
1246
+ })).catch(() => {}).finally(() => {
1247
+ i.delete(t);
1248
+ });
1249
+ }
1250
+ if (r.pending || r.pendingEvent) return;
1251
+ let a = (e, t) => {
1252
+ c().sendEvent(r.roomId, j(e, {
1253
+ game_id: r.gameId,
1254
+ data: t,
1255
+ game: "battleship"
1256
+ })).catch(() => {});
1257
+ };
1258
+ if (r.status === "active" && r.pendingShot && r.pendingShot.by !== r.ownId) {
1259
+ let e = Ve(je(r), r.pendingShot);
1260
+ e ? a("bs_result", e) : r.error || s((e) => ({ games: {
1261
+ ...e.games,
1262
+ [t]: {
1263
+ ...e.games[t],
1264
+ error: "Tu flota no está disponible en este dispositivo; no se pueden responder disparos."
1265
+ }
1266
+ } }));
1267
+ return;
1268
+ }
1269
+ let o = String(r.winnerId) !== String(r.ownId) || !!r.opponentReveal;
1270
+ if (r.winnerId && ["won", "closed"].includes(r.status) && !r.myRevealSent && o) {
1271
+ let e = B(r.myFleet), t = r.mySalt ?? n(r.scope, r.gameId)?.salt;
1272
+ Ae(e) && t && a("bs_reveal", {
1273
+ fleet: e,
1274
+ salt: t
1275
+ });
1276
+ }
1277
+ },
1278
+ sendEvent: async (t, n) => {
1279
+ if (!e) throw Error("Chat no disponible");
1280
+ let r = e, i = r.getScope(), a = String(r.getUserId() ?? ""), o = _t(i, t, n.game_id), l = A(n);
1281
+ if (c().ingest({
1282
+ room_id: t,
1283
+ user_id: a,
1284
+ message: l
1285
+ }, i, a), !c().games[o]?.seen[n.event_id]) throw Error("Evento de partida inválido");
1286
+ let u = (e, t = !0) => s((r) => {
1287
+ let i = r.games[o];
1288
+ return !i || t && i.pendingEvent?.event_id !== n.event_id ? r : { games: {
1289
+ ...r.games,
1290
+ [o]: {
1291
+ ...i,
1292
+ ...e
1293
+ }
1294
+ } };
1295
+ });
1296
+ u({
1297
+ pending: !0,
1298
+ pendingEvent: n,
1299
+ error: ""
1300
+ }, !1);
1301
+ try {
1302
+ await r.send(t, l), u({
1303
+ pending: !1,
1304
+ pendingEvent: null
1305
+ }), n.game === "battleship" && c().bsScheduleEffects(o);
1306
+ } catch (e) {
1307
+ throw u({
1308
+ pending: !1,
1309
+ error: e.message || "No se pudo enviar. Reintenta el mismo evento."
1310
+ }), e;
1311
+ }
1312
+ return o;
1313
+ },
1314
+ handleResync: (e, t, n, r) => {
1315
+ let i = c().games[e], a = l(i), o = {
1316
+ ...i.seen,
1317
+ [t.event_id]: !0
1318
+ }, u = (t) => {
1319
+ s((n) => ({ games: {
1320
+ ...n.games,
1321
+ [e]: t
1322
+ } })), U(t) && c().bsScheduleEffects(e);
1323
+ };
1324
+ if (n === r || ![i.hostId, i.guestId].includes(n) || ["closed", "declined"].includes(i.status)) {
1325
+ u({
1326
+ ...i,
1327
+ seen: o
1328
+ });
1329
+ return;
1330
+ }
1331
+ let d = {
1332
+ ...G,
1333
+ ...i.sync
1334
+ };
1335
+ if (![a.requestType, a.stateType].includes(t.type)) {
1336
+ u({
1337
+ ...i,
1338
+ seen: o
1339
+ });
1340
+ return;
1341
+ }
1342
+ let f = t.type === a.stateType;
1343
+ if (f && !d.outgoing.includes(t.data.request_event_id)) {
1344
+ u({
1345
+ ...i,
1346
+ seen: o
1347
+ });
1348
+ return;
1349
+ }
1350
+ let p = a.rebuild(i, t.data);
1351
+ if (!p) {
1352
+ u({
1353
+ ...i,
1354
+ seen: o,
1355
+ sync: f ? {
1356
+ ...d,
1357
+ status: "failed",
1358
+ message: "El rival envió un estado de partida inválido."
1359
+ } : d
1360
+ });
1361
+ return;
1362
+ }
1363
+ let m = a.compare(i, t.data), h = {
1364
+ ...d,
1365
+ status: "ok",
1366
+ offer: null,
1367
+ auto: !1,
1368
+ message: ""
1369
+ }, g, _ = !f, v = !1, y = m === "mixed" ? a.merge(i, t.data) : null;
1370
+ if (m === "equal" || m === "behind") g = {
1371
+ ...p,
1372
+ sync: h
1373
+ }, a.covers(i, t.data) && (g = {
1374
+ ...g,
1375
+ pendingEvent: null
1376
+ });
1377
+ else if (y) {
1378
+ let e = a.rebuild(i, y);
1379
+ g = e ? {
1380
+ ...e,
1381
+ sync: h
1382
+ } : {
1383
+ ...i,
1384
+ sync: {
1385
+ ...d,
1386
+ status: "failed",
1387
+ message: "No se pudo reconstruir la partida local."
1388
+ }
1389
+ }, _ = !!e, v = !!e;
1390
+ } else if (m === "ahead" || n === i.guestId) {
1391
+ let e = a.rebuild(i, a.historyOf(i));
1392
+ g = e ? {
1393
+ ...e,
1394
+ sync: h
1395
+ } : {
1396
+ ...i,
1397
+ sync: {
1398
+ ...d,
1399
+ status: "failed",
1400
+ message: "No se pudo reconstruir la partida local."
1401
+ }
1402
+ }, _ = !!e, v = !!e;
1403
+ } else g = {
1404
+ ...i,
1405
+ status: "conflict",
1406
+ error: "El anfitrión tiene otra versión de la partida. Revísala antes de aceptarla.",
1407
+ sync: {
1408
+ ...d,
1409
+ status: "incompatible",
1410
+ offer: a.offerOf(t.data),
1411
+ message: ""
1412
+ }
1413
+ };
1414
+ g = {
1415
+ ...g,
1416
+ seen: a.markSeen(o, g)
1417
+ };
1418
+ let b = Date.now(), x = g.sync.replies.filter((e) => b - e < 3e4), S = null;
1419
+ if (_ && x.length < 6) try {
1420
+ S = Ot(i, a.stateType, {
1421
+ ...a.historyOf(g),
1422
+ request_event_id: t.event_id
1423
+ });
1424
+ } catch {
1425
+ S = null;
1426
+ }
1427
+ S && (g = {
1428
+ ...g,
1429
+ seen: {
1430
+ ...g.seen,
1431
+ [S.event_id]: !0
1432
+ },
1433
+ sync: {
1434
+ ...g.sync,
1435
+ replies: [...x, b],
1436
+ outgoing: [...g.sync.outgoing, S.event_id].slice(-8)
1437
+ }
1438
+ }), u(g), S && c().sendResync(e, S).then(() => {
1439
+ v && (s((t) => {
1440
+ let n = t.games[e];
1441
+ return !n || !l(n).covers(n, l(n).historyOf(n)) ? t : { games: {
1442
+ ...t.games,
1443
+ [e]: {
1444
+ ...n,
1445
+ pendingEvent: null,
1446
+ error: ""
1447
+ }
1448
+ } };
1449
+ }), U(c().games[e]) && c().bsScheduleEffects(e));
1450
+ }).catch(() => {});
1451
+ },
1452
+ sendResync: async (t, n) => {
1453
+ let r = c().games[t];
1454
+ if (!e || !r || r.scope !== e.getScope?.()) throw Error("Chat no disponible");
1455
+ await e.send(r.roomId, A(n));
1456
+ },
1457
+ requestResync: async (t, { auto: n = !1 } = {}) => {
1458
+ let r = c().games[t];
1459
+ if (!r || !e || ["closed", "declined"].includes(r.status) || r.scope !== e.getScope?.()) return;
1460
+ let i = {
1461
+ ...G,
1462
+ ...r.sync
1463
+ };
1464
+ if (i.status === "requesting" && Date.now() - i.requestedAt < bt || n && i.auto) return;
1465
+ let a;
1466
+ try {
1467
+ a = Ot(r, l(r).requestType, l(r).historyOf(r));
1468
+ } catch {
1469
+ return;
1470
+ }
1471
+ let u = (e) => s((n) => {
1472
+ let r = n.games[t];
1473
+ return r?.sync?.requestId !== a.event_id || r.sync.status !== "requesting" ? n : { games: {
1474
+ ...n.games,
1475
+ [t]: {
1476
+ ...r,
1477
+ sync: {
1478
+ ...r.sync,
1479
+ status: "failed",
1480
+ message: e
1481
+ }
1482
+ }
1483
+ } };
1484
+ });
1485
+ s((e) => {
1486
+ let r = e.games[t];
1487
+ return r ? { games: {
1488
+ ...e.games,
1489
+ [t]: {
1490
+ ...r,
1491
+ seen: {
1492
+ ...r.seen,
1493
+ [a.event_id]: !0
1494
+ },
1495
+ sync: {
1496
+ ...i,
1497
+ status: "requesting",
1498
+ requestId: a.event_id,
1499
+ requestedAt: Date.now(),
1500
+ auto: i.auto || n,
1501
+ message: "",
1502
+ outgoing: [...i.outgoing, a.event_id].slice(-8)
1503
+ }
1504
+ }
1505
+ } } : e;
1506
+ });
1507
+ let d = setTimeout(() => {
1508
+ o.delete(d), u("El rival no respondió a la sincronización. Reintenta cuando esté conectado.");
1509
+ }, bt);
1510
+ o.add(d);
1511
+ try {
1512
+ await c().sendResync(t, a);
1513
+ } catch (e) {
1514
+ u(e.message || "No se pudo enviar la solicitud de sincronización.");
1515
+ }
1516
+ },
1517
+ adoptResyncOffer: (e) => {
1518
+ let t = c().games[e], n = t?.sync?.offer;
1519
+ if (!n || t.sync.status !== "incompatible") return !1;
1520
+ let r = l(t), i = r.rebuild(t, n);
1521
+ return s((n) => ({ games: {
1522
+ ...n.games,
1523
+ [e]: i ? {
1524
+ ...i,
1525
+ seen: r.markSeen(t.seen, i),
1526
+ pending: !1,
1527
+ pendingEvent: null,
1528
+ sync: {
1529
+ ...t.sync,
1530
+ status: "ok",
1531
+ offer: null,
1532
+ auto: !1,
1533
+ message: ""
1534
+ }
1535
+ } : {
1536
+ ...t,
1537
+ sync: {
1538
+ ...t.sync,
1539
+ status: "failed",
1540
+ offer: null,
1541
+ message: "El estado del anfitrión ya no es válido."
1542
+ }
1543
+ }
1544
+ } })), i && U(i) && c().bsScheduleEffects(e), !!i;
1545
+ },
1546
+ resyncConflicts: (e) => {
1547
+ Object.values(c().games).filter((t) => t.scope === e && t.status === "conflict").forEach((e) => {
1548
+ c().requestResync(e.key, { auto: !0 });
1549
+ });
1550
+ },
1551
+ retry: (t) => {
1552
+ let n = c().games[t];
1553
+ return !n?.pendingEvent || n.pending ? Promise.resolve() : n.scope === e?.getScope?.() ? c().sendEvent(n.roomId, n.pendingEvent) : Promise.reject(/* @__PURE__ */ Error("La sesión de esta partida ya no está activa."));
1554
+ }
1555
+ }));
1556
+ }
1557
+ var K = kt(), At = (e) => l(K, e);
1558
+ Object.assign(At, {
1559
+ getState: K.getState,
1560
+ setState: K.setState,
1561
+ subscribe: K.subscribe
1562
+ });
1563
+ // src/assets/chatAssets.js
1564
+ var jt = "/sounds", Mt = jt, Nt = (e) => String(e).replace(/\/+$/, "");
1565
+ function Pt(e) {
1566
+ Mt = e == null ? jt : Nt(e);
1567
+ }
1568
+ function Ft() {
1569
+ return Mt;
1570
+ }
1571
+ function It(e) {
1572
+ return `${Mt}/${String(e).replace(/^\/+/, "")}`;
1573
+ }
1574
+ // src/core/connection/connectionStore.js
1575
+ var Lt = c(() => ({ status: "idle" }));
1576
+ function Rt(e) {
1577
+ Lt.setState({ status: e });
1578
+ }
1579
+ function zt() {
1580
+ return l(Lt, (e) => e.status);
1581
+ }
1582
+ // src/games/shared/gameStatus.js
1583
+ var q = (e, t) => e != null && t != null && String(e) === String(t), Bt = (e) => [
1584
+ "won",
1585
+ "draw",
1586
+ "declined",
1587
+ "closed"
1588
+ ].includes(e?.status), Vt = (e) => !!e && ([
1589
+ "invited",
1590
+ "placement",
1591
+ "active",
1592
+ "conflict"
1593
+ ].includes(e.status) || !!e.pendingEvent), J = (e) => e?.game === "battleship", Ht = (e) => J(e) ? "Batalla Naval" : "Conecta 4", Ut = {
1594
+ ok: "Partida verificada",
1595
+ mismatch: "Resultados inconsistentes del rival",
1596
+ pending: "Verificando…"
1597
+ }, Wt = (e) => Ut[e?.verification] || "";
1598
+ function Gt(e, t) {
1599
+ let n = q(t, e.turnId);
1600
+ return e.status === "placement" ? e.myReady ? e.opponentReady ? "Iniciando batalla…" : "Esperando a que el rival coloque su flota" : "Coloca tu flota" : e.status === "active" ? e.pendingShot ? "Esperando resultado…" : n ? "Tu turno · elige una casilla" : "Turno del rival" : e.status === "won" ? q(t, e.winnerId) ? "¡Ganaste!" : "Tu rival ganó" : null;
1601
+ }
1602
+ function Kt(e, t) {
1603
+ if (J(e)) {
1604
+ let n = Gt(e, t);
1605
+ if (n) return n;
1606
+ }
1607
+ let n = e.status === "active" && q(t, e.turnId);
1608
+ return e.status === "invited" ? q(t, e.guestId) ? "Te han invitado a jugar" : "Esperando respuesta a la invitación" : e.status === "active" ? n ? "Tu turno · elige una columna" : "Turno de tu rival" : e.status === "won" ? q(t, e.winnerId) ? "¡Ganaste la partida!" : "Tu rival ganó la partida" : e.status === "draw" ? "Empate · tablero completo" : e.status === "declined" ? "Invitación rechazada" : e.status === "closed" ? "Partida finalizada" : e.status === "conflict" ? "Partida pausada por un conflicto de sincronización" : "Esperando respuesta a la invitación";
1609
+ }
1610
+ function qt(e, t) {
1611
+ if (J(e)) {
1612
+ if (e.status === "placement") return e.myReady ? "Esperando al rival" : "Coloca tu flota";
1613
+ if (e.status === "active" && e.pendingShot) return "Esperando resultado…";
1614
+ }
1615
+ return e.status === "active" ? q(t, e.turnId) ? "Tu turno" : "Turno del rival" : e.status === "invited" ? q(t, e.guestId) ? "Invitación recibida" : "Invitación enviada" : e.status === "conflict" ? e.sync?.status === "requesting" ? "Sincronizando…" : "Sin sincronizar" : Kt(e, t);
1616
+ }
1617
+ // src/audio/useSoundSettings.js
1618
+ function Jt(e) {
1619
+ return s(e.subscribe, e.getSettings, e.getSettings);
1620
+ }
1621
+ // src/games/shared/GameSoundControls.jsx
1622
+ function Yt({ manager: e }) {
1623
+ let { volume: t, muted: n } = Jt(e), r = n || t === 0;
1624
+ return /* @__PURE__ */ d("div", {
1625
+ className: "chat-game-sound",
1626
+ children: [/* @__PURE__ */ u("button", {
1627
+ type: "button",
1628
+ className: "chat-game-sound-toggle",
1629
+ onClick: e.toggleMuted,
1630
+ "aria-pressed": r,
1631
+ "aria-label": r ? "Activar sonido del juego" : "Silenciar sonido del juego",
1632
+ title: r ? "Activar sonido" : "Silenciar",
1633
+ children: u(r ? p : f, { size: 15 })
1634
+ }), /* @__PURE__ */ u("input", {
1635
+ type: "range",
1636
+ min: "0",
1637
+ max: "100",
1638
+ step: "5",
1639
+ value: Math.round((n ? 0 : t) * 100),
1640
+ onChange: (t) => e.setVolume(Number(t.target.value) / 100),
1641
+ "aria-label": "Volumen del juego"
1642
+ })]
1643
+ });
1644
+ }
1645
+ // src/audio/createSoundManager.js
1646
+ var Xt = [
1647
+ "pointerdown",
1648
+ "keydown",
1649
+ "touchend"
1650
+ ], Zt = 300, Qt = 800, Y = (e) => Math.min(1, Math.max(0, Number(e) || 0));
1651
+ function $t(e, t) {
1652
+ try {
1653
+ let n = JSON.parse(localStorage.getItem(e) ?? "null");
1654
+ if (n && typeof n == "object") return {
1655
+ volume: Y(n.volume ?? t.volume),
1656
+ muted: !!n.muted
1657
+ };
1658
+ } catch {}
1659
+ return {
1660
+ volume: Y(t.volume),
1661
+ muted: !1
1662
+ };
1663
+ }
1664
+ var en = 1.5, tn = .6;
1665
+ function nn({ id: e, baseUrl: t, sounds: n, levels: r = {}, defaultVolume: i = .6, settingsFrom: a = null }) {
1666
+ let o = `lira.sound.${e}`, s = typeof window < "u" ? window.AudioContext || window.webkitAudioContext : null, c = a ? a.getSettings() : $t(o, { volume: i }), l = null, u = null, d = !1, f = /* @__PURE__ */ new Map(), p = /* @__PURE__ */ new Map(), m = /* @__PURE__ */ new Set(), h = /* @__PURE__ */ new Set(), g = /* @__PURE__ */ new Set(), _ = /* @__PURE__ */ new Set(), v = /* @__PURE__ */ new Map(), y = !1, b = !1, x = null, S = (e) => `${String(typeof t == "function" ? t() : t).replace(/\/$/, "")}/${n[e]}`, C = (e) => (f.has(e) || f.set(e, fetch(S(e)).then((e) => e.ok ? e.arrayBuffer() : null).catch(() => null)), f.get(e)), w = () => {
1667
+ if (!s) return null;
1668
+ if (!l) try {
1669
+ l = new s(), u = l.createGain(), u.gain.value = c.muted ? 0 : c.volume, u.connect(l.destination);
1670
+ } catch {
1671
+ return l = null, null;
1672
+ }
1673
+ return l.state === "suspended" && l.resume().catch(() => {}), l;
1674
+ }, T = (e) => {
1675
+ if (m.has(e) || !n[e]) return Promise.resolve(null);
1676
+ if (!p.has(e)) {
1677
+ let t = w();
1678
+ if (!t) return Promise.resolve(null);
1679
+ p.set(e, C(e).then((e) => e ? new Promise((n) => {
1680
+ t.decodeAudioData(e.slice(0), n, () => n(null));
1681
+ }) : null).then((t) => (t || m.add(e), t)).catch(() => (m.add(e), null)));
1682
+ }
1683
+ return p.get(e);
1684
+ }, ee = (e) => Y(r[e] ?? 1), E = (e) => {
1685
+ if (!_.has(e) || v.has(e) || !d) return;
1686
+ let t = w();
1687
+ if (!t) return;
1688
+ let n = {};
1689
+ v.set(e, n), T(e).then((r) => {
1690
+ if (v.get(e) === n) {
1691
+ if (!r || t.state === "closed") v.delete(e);
1692
+ else try {
1693
+ let n = t.createGain();
1694
+ n.gain.setValueAtTime(0, t.currentTime), n.gain.linearRampToValueAtTime(ee(e), t.currentTime + en), n.connect(u);
1695
+ let i = t.createBufferSource();
1696
+ i.buffer = r, i.loop = !0, i.connect(n), i.start(), v.set(e, {
1697
+ source: i,
1698
+ level: n
1699
+ });
1700
+ } catch {
1701
+ v.delete(e);
1702
+ }
1703
+ }
1704
+ });
1705
+ }, te = (e) => {
1706
+ let t = v.get(e);
1707
+ if (v.delete(e), t?.source && l) try {
1708
+ let e = l.currentTime;
1709
+ t.level.gain.cancelScheduledValues(e), t.level.gain.setValueAtTime(t.level.gain.value, e), t.level.gain.linearRampToValueAtTime(0, e + tn), t.source.stop(e + tn + .05);
1710
+ } catch {}
1711
+ }, D = () => {
1712
+ d || (d = !0, ne(), w() && Object.keys(n).forEach((e) => {
1713
+ f.has(e) && T(e);
1714
+ }), _.forEach(E));
1715
+ };
1716
+ function ne() {
1717
+ b && (b = !1, Xt.forEach((e) => window.removeEventListener(e, D, !0)));
1718
+ }
1719
+ let O = (e) => !h.has(e) && (h.add(e), h.size > Zt && h.delete(h.values().next().value), !0), k = () => g.forEach((e) => e()), re = (e) => {
1720
+ c = e, u && (u.gain.value = c.muted ? 0 : c.volume), k();
1721
+ }, A = (e) => {
1722
+ let t = {
1723
+ volume: Y(e.volume ?? c.volume),
1724
+ muted: e.muted ?? c.muted
1725
+ };
1726
+ try {
1727
+ localStorage.setItem(o, JSON.stringify(t));
1728
+ } catch {}
1729
+ re(t);
1730
+ }, j = () => {
1731
+ y || (y = !0, a && (c = a.getSettings(), x = a.subscribe(() => re(a.getSettings()))), !(typeof window > "u" || d) && (typeof navigator < "u" && navigator.userActivation?.hasBeenActive ? d = !0 : (b = !0, Xt.forEach((e) => window.addEventListener(e, D, {
1732
+ capture: !0,
1733
+ passive: !0
1734
+ })))));
1735
+ };
1736
+ return {
1737
+ start: j,
1738
+ dispose: () => {
1739
+ ne(), x && (x(), x = null), y = !1, _.clear(), v.forEach((e) => {
1740
+ try {
1741
+ e?.source?.stop();
1742
+ } catch {}
1743
+ }), v.clear(), p.clear();
1744
+ let e = l;
1745
+ l = null, u = null, e && e.state !== "closed" && e.close().catch(() => {});
1746
+ },
1747
+ preload(e = Object.keys(n)) {
1748
+ j(), e.forEach((e) => {
1749
+ n[e] && !m.has(e) && (C(e), l && T(e));
1750
+ });
1751
+ },
1752
+ play(e, { key: t } = {}) {
1753
+ if (j(), t != null && !O(`${e}:${t}`) || !n[e] || m.has(e) || !d || c.muted || c.volume === 0) return !1;
1754
+ let r = w();
1755
+ if (!r) return !1;
1756
+ let i = Date.now();
1757
+ return T(e).then((t) => {
1758
+ if (!(!t || r.state === "closed" || Date.now() - i > Qt)) try {
1759
+ let n = r.createBufferSource();
1760
+ n.buffer = t;
1761
+ let i = ee(e);
1762
+ if (i === 1) n.connect(u);
1763
+ else {
1764
+ let e = r.createGain();
1765
+ e.gain.value = i, n.connect(e), e.connect(u);
1766
+ }
1767
+ n.start();
1768
+ } catch {}
1769
+ }), !0;
1770
+ },
1771
+ markPlayed(e, t) {
1772
+ O(`${e}:${t}`);
1773
+ },
1774
+ startLoop(e) {
1775
+ j(), n[e] && !m.has(e) && (_.add(e), E(e));
1776
+ },
1777
+ stopLoop(e) {
1778
+ _.delete(e), te(e);
1779
+ },
1780
+ getSettings: () => a && !y ? a.getSettings() : c,
1781
+ setVolume: a ? a.setVolume : (e) => A({
1782
+ volume: e,
1783
+ muted: Y(e) === 0 && c.muted
1784
+ }),
1785
+ setMuted: a ? a.setMuted : (e) => A({ muted: !!e }),
1786
+ toggleMuted: a ? a.toggleMuted : () => A({ muted: !c.muted }),
1787
+ subscribe(e) {
1788
+ return j(), g.add(e), () => g.delete(e);
1789
+ }
1790
+ };
1791
+ }
1792
+ // src/games/connect4/connect4Sounds.js
1793
+ var X = nn({
1794
+ id: "connect4",
1795
+ baseUrl: () => It("connect4"),
1796
+ sounds: {
1797
+ invite: "invite.ogg",
1798
+ start: "start.ogg",
1799
+ drop: "drop.ogg",
1800
+ turn: "turn.ogg",
1801
+ win: "win.ogg",
1802
+ lose: "lose.ogg",
1803
+ draw: "draw.ogg",
1804
+ close: "close.ogg"
1805
+ }
1806
+ }), rn = 140, Z = /* @__PURE__ */ new Map(), Q = /* @__PURE__ */ new Set(), $ = null, an = (e, t) => e != null && t != null && String(e) === String(t), on = () => typeof window < "u" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
1807
+ function sn(e, t) {
1808
+ e.status === "won" ? X.play(an(e.winnerId, e.ownId) ? "win" : "lose", { key: t }) : e.status === "draw" ? X.play("draw", { key: t }) : e.status === "active" && an(e.turnId, e.ownId) && X.play("turn", { key: t });
1809
+ }
1810
+ function cn(e) {
1811
+ let t = Z.get(e);
1812
+ if (!t) return;
1813
+ clearTimeout(t.timer), Z.delete(e), X.play("drop", { key: e });
1814
+ let n = setTimeout(() => {
1815
+ Q.delete(n), sn(t.game, e);
1816
+ }, rn);
1817
+ Q.add(n);
1818
+ }
1819
+ function ln(e) {
1820
+ let t = e.lastMove?.eventId;
1821
+ if (!t || Z.has(t)) return;
1822
+ let n = on() ? 0 : 440;
1823
+ Z.set(t, {
1824
+ game: e,
1825
+ timer: setTimeout(() => cn(t), n)
1826
+ });
1827
+ }
1828
+ function un(e, t) {
1829
+ t ? t.status === "invited" && e.status === "active" ? X.play("start", { key: e.lastEventId }) : e.ply > t.ply ? ln(e) : (e.status === "closed" && e.closedBy != null || e.status === "declined") && t.status !== e.status && X.play("close", { key: e.gameId }) : e.status === "invited" && an(e.guestId, e.ownId) && X.play("invite", { key: e.inviteEventId });
1830
+ }
1831
+ var dn = () => $ != null;
1832
+ function fn() {
1833
+ if ($) return $;
1834
+ X.start();
1835
+ let e = At.subscribe((e, t) => {
1836
+ e.games !== t.games && Object.entries(e.games).forEach(([e, n]) => {
1837
+ let r = t.games[e];
1838
+ n.game && n.game !== "connect4" || n !== r && n.ownId != null && un(n, r);
1839
+ });
1840
+ }), t = () => {
1841
+ $ === t && ($ = null, e(), Z.forEach(({ timer: e }) => clearTimeout(e)), Z.clear(), Q.forEach(clearTimeout), Q.clear());
1842
+ };
1843
+ return $ = t, t;
1844
+ }
1845
+ export { m as C, At as S, zt as _, nn as a, Pt as b, Ht as c, J as d, Vt as f, Rt as g, Lt as h, fn as i, qt as l, q as m, dn as n, Yt as o, Bt as p, cn as r, Kt as s, X as t, Wt as u, It as v, O as w, K as x, Ft as y };
1846
+
1847
+ //# sourceMappingURL=connect4Sounds-Do3nvVFx.js.map