@minicode-dev/chat 0.1.5 → 0.1.7

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 (53) hide show
  1. package/README.md +6 -2
  2. package/assets/sounds/tanks/big_explosion.mp3 +0 -0
  3. package/assets/sounds/tanks/big_explosion.ogg +0 -0
  4. package/assets/sounds/tanks/cannon_fire.mp3 +0 -0
  5. package/assets/sounds/tanks/cannon_fire.ogg +0 -0
  6. package/assets/sounds/tanks/defeat.mp3 +0 -0
  7. package/assets/sounds/tanks/defeat.ogg +0 -0
  8. package/assets/sounds/tanks/engine_loop.mp3 +0 -0
  9. package/assets/sounds/tanks/engine_loop.ogg +0 -0
  10. package/assets/sounds/tanks/engine_start.mp3 +0 -0
  11. package/assets/sounds/tanks/engine_start.ogg +0 -0
  12. package/assets/sounds/tanks/projectile_whistle.mp3 +0 -0
  13. package/assets/sounds/tanks/projectile_whistle.ogg +0 -0
  14. package/assets/sounds/tanks/tank_destroyed.mp3 +0 -0
  15. package/assets/sounds/tanks/tank_destroyed.ogg +0 -0
  16. package/assets/sounds/tanks/tank_hit.mp3 +0 -0
  17. package/assets/sounds/tanks/tank_hit.ogg +0 -0
  18. package/assets/sounds/tanks/terrain_impact.mp3 +0 -0
  19. package/assets/sounds/tanks/terrain_impact.ogg +0 -0
  20. package/assets/sounds/tanks/tracks_loop.mp3 +0 -0
  21. package/assets/sounds/tanks/tracks_loop.ogg +0 -0
  22. package/assets/sounds/tanks/turret_loop.mp3 +0 -0
  23. package/assets/sounds/tanks/turret_loop.ogg +0 -0
  24. package/assets/sounds/tanks/victory.mp3 +0 -0
  25. package/assets/sounds/tanks/victory.ogg +0 -0
  26. package/dist/chunks/{BattleshipGameCard-CW_A8Nim.js → BattleshipGameCard-CAWHxqJE.js} +307 -306
  27. package/dist/chunks/{BattleshipGameCard-CW_A8Nim.js.map → BattleshipGameCard-CAWHxqJE.js.map} +1 -1
  28. package/dist/chunks/{BattleshipPrototype-Duz-S1JE.js → BattleshipPrototype-CmQd5AUO.js} +55 -54
  29. package/dist/chunks/{BattleshipPrototype-Duz-S1JE.js.map → BattleshipPrototype-CmQd5AUO.js.map} +1 -1
  30. package/dist/chunks/ChatContext-CUiEAMKK.js +90 -0
  31. package/dist/chunks/ChatContext-CUiEAMKK.js.map +1 -0
  32. package/dist/chunks/TanksGameCard-BEnXTz_J.js +1705 -0
  33. package/dist/chunks/TanksGameCard-BEnXTz_J.js.map +1 -0
  34. package/dist/chunks/{battleship-DXKuIZ1I.js → board-DXKuIZ1I.js} +1 -1
  35. package/dist/chunks/board-DXKuIZ1I.js.map +1 -0
  36. package/dist/chunks/connect4Sounds-BDXQAvU1.js +3199 -0
  37. package/dist/chunks/connect4Sounds-BDXQAvU1.js.map +1 -0
  38. package/dist/chunks/core-geo-UJY-tH9L.js +361 -0
  39. package/dist/chunks/core-geo-UJY-tH9L.js.map +1 -0
  40. package/dist/chunks/createBattleScene-L4ZRWDED.js +1265 -0
  41. package/dist/chunks/createBattleScene-L4ZRWDED.js.map +1 -0
  42. package/dist/chunks/createTankScene-BuliAxwR.js +2150 -0
  43. package/dist/chunks/createTankScene-BuliAxwR.js.map +1 -0
  44. package/dist/index.js +3677 -3644
  45. package/dist/index.js.map +1 -1
  46. package/dist/styles.css +1 -1
  47. package/index.d.ts +4 -0
  48. package/package.json +1 -1
  49. package/dist/chunks/battleship-DXKuIZ1I.js.map +0 -1
  50. package/dist/chunks/connect4Sounds-Do3nvVFx.js +0 -1847
  51. package/dist/chunks/connect4Sounds-Do3nvVFx.js.map +0 -1
  52. package/dist/chunks/createBattleScene-HIAvjixn.js +0 -1621
  53. package/dist/chunks/createBattleScene-HIAvjixn.js.map +0 -1
@@ -0,0 +1,3199 @@
1
+ import { a as e, c as t, i as n, n as r, r as i, s as a, t as o } from "./board-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 { Volume2 as u, VolumeX as d } from "lucide-react";
6
+ import { jsx as f, jsxs as p } from "react/jsx-runtime";
7
+ // src/games/tanks/net/protocol.js
8
+ var m = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, h = /^[0-9a-f]{16}$/, g = /^[0-9a-f]{32}$/, _ = /^[0-9a-f]{64}$/, v = (e) => typeof e == "object" && !!e && !Array.isArray(e), y = (e) => typeof e == "string" && e.length > 0 && e.length <= 256 && e.trim() === e, b = (e) => typeof e == "string" && m.test(e), x = (e, t, n) => Number.isInteger(e) && e >= t && e <= n, S = Object.freeze([
9
+ "standard",
10
+ "heavy",
11
+ "cluster"
12
+ ]), ee = (e) => x(e, 1, 120), te = (e) => x(e.move, -16, 16) && x(e.yaw, 0, 359) && x(e.pitch, 5, 80) && x(e.power, 0, 100) && x(e.ammo, 0, S.length - 1);
13
+ function C(e) {
14
+ return Array.isArray(e) ? e[0] === 1 ? e.length === 6 && te({
15
+ move: e[1],
16
+ yaw: e[2],
17
+ pitch: e[3],
18
+ power: e[4],
19
+ ammo: e[5]
20
+ }) : e[0] === 2 ? e.length === 1 : e[0] === 3 && e.length === 2 && (e[1] === 0 || e[1] === 1) : !1;
21
+ }
22
+ var w = (e) => Array.isArray(e.log) && e.log.length <= 120 && e.log.every(C) && b(e.head) && (e.accept_event_id === void 0 ? e.log.length === 0 && e.seed_b === void 0 && e.seed_a === void 0 : b(e.accept_event_id) && typeof e.seed_b == "string" && g.test(e.seed_b)) && (e.seed_a === void 0 ? e.log.length === 0 : g.test(e.seed_a) && b(e.seed_event_id));
23
+ function ne(e) {
24
+ let t = e.data;
25
+ switch (e.type) {
26
+ case "game_invite": return y(t.opponent_id) && t.rules_version === 1 && typeof t.seed_commit == "string" && _.test(t.seed_commit) && (t.first_player_id === void 0 || y(t.first_player_id)) && (t.rematch_of === void 0 || b(t.rematch_of));
27
+ case "game_accept": return b(t.invite_event_id) && typeof t.seed_b == "string" && g.test(t.seed_b);
28
+ case "game_decline": return b(t.invite_event_id);
29
+ case "game_end": return t.reason === "closed";
30
+ case "tk_seed": return typeof t.seed_a == "string" && g.test(t.seed_a);
31
+ case "tk_turn": return ee(t.ply) && b(t.prev_event_id) && te(t) && typeof t.hash == "string" && h.test(t.hash);
32
+ case "tk_skip":
33
+ case "tk_resign": return ee(t.ply) && b(t.prev_event_id);
34
+ case "tk_sync_request": return v(t) && w(t);
35
+ case "tk_sync_state": return v(t) && w(t) && b(t.request_event_id);
36
+ default: return !1;
37
+ }
38
+ }
39
+ // src/games/shared/protocol.js
40
+ var re = "LIRA_GAME_V1:", ie = 4096, ae = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i, T = (e) => typeof e == "object" && !!e && !Array.isArray(e), E = (e) => typeof e == "string" && e.length > 0 && e.length <= 256 && e.trim() === e, D = (e) => typeof e == "string" && ae.test(e), oe = (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 && D(e[1])) && new Set(e.map((e) => e[1])).size === e.length, O = (e) => oe(e.moves) && e.rev === e.moves.length && (e.accept_event_id === void 0 ? e.moves.length === 0 : D(e.accept_event_id)), k = [
41
+ "carrier",
42
+ "battleship",
43
+ "cruiser",
44
+ "submarine",
45
+ "destroyer"
46
+ ], A = (e) => Number.isInteger(e) && e >= 0 && e < 10, se = (e) => typeof e == "string" && /^[0-9a-f]{64}$/.test(e), ce = (e) => Number.isInteger(e) && e >= 1 && e <= 200, le = (e) => e === null || T(e) && k.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 && A(e[0]) && A(e[1])), ue = (e) => Array.isArray(e) && e.length === k.length && e.every((e) => T(e) && k.includes(e.ship_id) && A(e.row) && A(e.col) && (e.orientation === "horizontal" || e.orientation === "vertical")) && new Set(e.map((e) => e.ship_id)).size === e.length, de = (e, t) => Array.isArray(e) && A(e[0]) && A(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] < k.length && A(e[4]) && A(e[5]) && (e[6] === 0 || e[6] === 1)), fe = (e) => Array.isArray(e.commits) && e.commits.length === 2 && e.commits.every((e) => e === null || se(e)) && Array.isArray(e.log) && e.log.length <= 200 && e.log.every((t, n) => de(t, n === e.log.length - 1)) && D(e.head) && (e.accept_event_id === void 0 ? e.commits.every((e) => e === null) && e.log.length === 0 : D(e.accept_event_id)) && (e.log.length === 0 || e.commits.every(Boolean));
47
+ function pe(e) {
48
+ let t = e.data;
49
+ switch (e.type) {
50
+ case "game_invite": return E(t.opponent_id) && t.rules_version === 1;
51
+ case "game_accept":
52
+ case "game_decline": return D(t.invite_event_id);
53
+ case "game_end": return ["closed", "win"].includes(t.reason) && (t.winner_id === void 0 || E(t.winner_id));
54
+ case "bs_commit": return se(t.commitment);
55
+ case "bs_fire": return ce(t.ply) && A(t.row) && A(t.col) && D(t.prev_event_id);
56
+ case "bs_result": return ce(t.ply) && A(t.row) && A(t.col) && ["hit", "miss"].includes(t.result) && le(t.sunk) && typeof t.defeated == "boolean" && (t.result === "hit" || t.sunk === null && !t.defeated);
57
+ case "bs_reveal": return ue(t.fleet) && typeof t.salt == "string" && /^[0-9a-f]{32}$/.test(t.salt);
58
+ case "bs_sync_request": return fe(t);
59
+ case "bs_sync_state": return fe(t) && D(t.request_event_id);
60
+ default: return !1;
61
+ }
62
+ }
63
+ function me(e) {
64
+ return typeof e == "string" && e.startsWith("LIRA_GAME_V1:");
65
+ }
66
+ function he(e) {
67
+ let t = e.data;
68
+ switch (e.type) {
69
+ case "game_invite": return E(t.opponent_id) && t.rules_version === 1;
70
+ case "game_accept":
71
+ case "game_decline": return D(t.invite_event_id);
72
+ case "game_move": return Number.isInteger(t.column) && t.column >= 0 && t.column < 7 && Number.isInteger(t.ply) && t.ply >= 1 && t.ply <= 42 && D(t.prev_event_id);
73
+ case "game_end": return [
74
+ "closed",
75
+ "win",
76
+ "draw"
77
+ ].includes(t.reason) && (t.winner_id === void 0 || E(t.winner_id)) && (t.final_move_event_id === void 0 || D(t.final_move_event_id)) && (t.reason !== "win" || E(t.winner_id) && D(t.final_move_event_id)) && (t.reason !== "draw" || D(t.final_move_event_id));
78
+ case "game_resync_request": return O(t);
79
+ case "game_resync_state": return O(t) && D(t.request_event_id);
80
+ default: return !1;
81
+ }
82
+ }
83
+ var ge = {
84
+ connect4: he,
85
+ battleship: pe,
86
+ tanks: ne
87
+ }, _e = Object.freeze(Object.keys(ge));
88
+ function ve(e) {
89
+ return !T(e) || e.version !== 1 || !Object.hasOwn(ge, e.game) || !D(e.game_id) || !D(e.event_id) || !T(e.data) ? !1 : ge[e.game](e);
90
+ }
91
+ function ye(e) {
92
+ if (!me(e) || e.length > ie) return null;
93
+ try {
94
+ let t = JSON.parse(e.slice(13));
95
+ return ve(t) ? t : null;
96
+ } catch {
97
+ return null;
98
+ }
99
+ }
100
+ function be(e) {
101
+ if (!ve(e)) throw Error("Evento de juego inválido");
102
+ let t = re + JSON.stringify(e);
103
+ if (t.length > ie) throw Error("Evento de juego demasiado grande");
104
+ return t;
105
+ }
106
+ function j(e, { game_id: t, data: n, event_id: r = crypto.randomUUID(), game: i = "connect4" }) {
107
+ let a = {
108
+ version: 1,
109
+ game: i,
110
+ game_id: t,
111
+ event_id: r,
112
+ type: e,
113
+ data: n
114
+ };
115
+ if (!ve(a)) throw Error("Evento de juego inválido");
116
+ return a;
117
+ }
118
+ function xe() {
119
+ return Array.from({ length: 6 }, () => Array(7).fill(null));
120
+ }
121
+ var Se = [
122
+ [0, 1],
123
+ [1, 0],
124
+ [1, 1],
125
+ [1, -1]
126
+ ];
127
+ function Ce(e) {
128
+ for (let t = 0; t < 6; t += 1) for (let n = 0; n < 7; n += 1) {
129
+ let r = e[t][n];
130
+ if (r != null) for (let [i, a] of Se) {
131
+ let o = [];
132
+ for (let s = 0; s < 4; s += 1) {
133
+ let c = t + i * s, l = n + a * s;
134
+ if (c < 0 || c >= 6 || l < 0 || l >= 7 || e[c][l] !== r) break;
135
+ o.push([c, l]);
136
+ }
137
+ if (o.length === 4) return o;
138
+ }
139
+ }
140
+ return [];
141
+ }
142
+ function we(e) {
143
+ let t = Ce(e);
144
+ return t.length ? e[t[0][0]][t[0][1]] : null;
145
+ }
146
+ function Te(e) {
147
+ return e[0].every((e) => e !== null);
148
+ }
149
+ function Ee(e, t, n) {
150
+ if (!Number.isInteger(t) || t < 0 || t >= 7 || n == null || we(e) !== null) return null;
151
+ let r = 5;
152
+ for (; r >= 0 && e[r][t] !== null;) --r;
153
+ if (r < 0) return null;
154
+ let i = e.map((e) => e.slice());
155
+ i[r][t] = n;
156
+ let a = Ce(i), o = a.length ? i[a[0][0]][a[0][1]] : null;
157
+ return {
158
+ board: i,
159
+ row: r,
160
+ column: t,
161
+ winner: o,
162
+ draw: o === null && Te(i),
163
+ winningCells: a
164
+ };
165
+ }
166
+ // src/games/battleship/logic/game.js
167
+ var De = (e) => typeof e == "string" && e.length > 0 && e.length <= 256 && e.trim() === e;
168
+ function Oe({ gameId: e, players: t, firstPlayerId: n = t?.[0] } = {}) {
169
+ if (!De(e) || !Array.isArray(t) || t.length !== 2 || !t.every(De) || t[0] === t[1] || !t.includes(n)) throw TypeError("Supply a gameId, two distinct player IDs and a valid firstPlayerId.");
170
+ return {
171
+ game: "battleship",
172
+ rulesVersion: 1,
173
+ gameId: e,
174
+ players: t.slice(),
175
+ boards: [r(), r()],
176
+ ready: [!1, !1],
177
+ phase: "placement",
178
+ turnId: null,
179
+ firstPlayerId: n,
180
+ winnerId: null,
181
+ shotCount: 0,
182
+ lastShot: null,
183
+ revision: 0
184
+ };
185
+ }
186
+ function ke(n, r) {
187
+ 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;
188
+ let o = n.players.indexOf(r.playerId);
189
+ if (o < 0) return n;
190
+ let s = n.boards[o];
191
+ if (n.phase === "placement") {
192
+ if (n.ready[o]) return n;
193
+ if (r.type === "place_ship" || r.type === "remove_ship") {
194
+ let e = r.type === "place_ship" ? a(s, r) : t(s, r.shipId);
195
+ if (!e.ok) return n;
196
+ let i = n.boards.slice();
197
+ return i[o] = e.board, {
198
+ ...n,
199
+ boards: i,
200
+ revision: n.revision + 1
201
+ };
202
+ }
203
+ if (r.type === "ready" && e(s)) {
204
+ let e = n.ready.slice();
205
+ e[o] = !0;
206
+ let t = e.every(Boolean);
207
+ return {
208
+ ...n,
209
+ ready: e,
210
+ phase: t ? "playing" : "placement",
211
+ turnId: t ? n.firstPlayerId : null,
212
+ revision: n.revision + 1
213
+ };
214
+ }
215
+ return n;
216
+ }
217
+ if (n.phase !== "playing" || r.type !== "fire" || r.playerId !== n.turnId) return n;
218
+ let c = 1 - o, l = i(n.boards[c], r);
219
+ if (!l.ok) return n;
220
+ let u = n.boards.slice();
221
+ return u[c] = l.board, {
222
+ ...n,
223
+ boards: u,
224
+ revision: n.revision + 1,
225
+ shotCount: n.shotCount + 1,
226
+ phase: l.defeated ? "finished" : "playing",
227
+ turnId: l.defeated ? null : n.players[c],
228
+ winnerId: l.defeated ? r.playerId : null,
229
+ lastShot: {
230
+ playerId: r.playerId,
231
+ targetId: n.players[c],
232
+ row: r.row,
233
+ col: r.col,
234
+ result: l.result,
235
+ shipId: l.shipId,
236
+ sunk: l.sunk,
237
+ defeated: l.defeated
238
+ }
239
+ };
240
+ }
241
+ // src/games/battleship/net/session.js
242
+ var Ae = o.reduce((e, t) => e + t.size, 0), je = /^[0-9a-f]{32}$/, Me = [
243
+ "won",
244
+ "closed",
245
+ "declined"
246
+ ], M = "La partida perdió sincronización. Se intentará resincronizar.", Ne = "Falta la aceptación de la partida. Ciérrala y vuelve a invitar.", Pe = "El rival envió un resultado imposible para ese disparo.", Fe = "Tu flota no está disponible en este dispositivo; no se pueden responder disparos.", Ie = () => Array.from({ length: 10 }, () => Array(10).fill(null)), Le = (e, t, n, r) => e.map((e, i) => i === t ? e.map((e, t) => t === n ? r : e) : e), Re = (e) => e.reduce((e, t) => e + t.filter((e) => e === "hit").length, 0), ze = (e) => e.reduce((e, t) => e + t.filter((e) => e !== null).length, 0), Be = (e, t) => t % 2 == 1 ? e.hostId : e.guestId, Ve = (e, t) => t === e.hostId ? e.guestId : e.hostId, He = (e, t) => t === e.hostId ? "hostCommitment" : "guestCommitment", N = (e, t) => ({
247
+ ...e,
248
+ status: "conflict",
249
+ error: t
250
+ }), Ue = (e) => `${e.row},${e.col}`, We = (e, t) => e.row - t.row || e.col - t.col, Ge = (e, t) => e.length === t.length && e.map(Ue).sort().join("|") === t.map(Ue).sort().join("|");
251
+ function Ke(e) {
252
+ return {
253
+ ...e,
254
+ game: "battleship",
255
+ status: "invited",
256
+ turnId: null,
257
+ myFleet: [],
258
+ myReady: !1,
259
+ opponentReady: !1,
260
+ incomingShots: Ie(),
261
+ targetShots: Ie(),
262
+ sunkEnemyShips: [],
263
+ pendingShot: null,
264
+ lastShot: null,
265
+ winnerId: null,
266
+ verification: null,
267
+ ply: 0,
268
+ shots: [],
269
+ acceptEventId: null,
270
+ hostCommitment: null,
271
+ guestCommitment: null,
272
+ myCommitment: null,
273
+ mySalt: null,
274
+ myRevealSent: !1,
275
+ opponentReveal: null,
276
+ seen: e.seen ?? {},
277
+ pending: !1,
278
+ pendingEvent: null,
279
+ error: "",
280
+ sync: e.sync ?? null
281
+ };
282
+ }
283
+ var qe = (e) => e?.game === "battleship" && ["invited", "placement"].includes(e.status) && !e.myReady, Je = (e) => e?.status === "active" && e.turnId === e.ownId && !e.pendingShot, Ye = (e) => ({
284
+ id: e.id,
285
+ size: e.size,
286
+ orientation: e.orientation,
287
+ cells: e.cells.map((e) => ({
288
+ row: e.row,
289
+ col: e.col
290
+ }))
291
+ }), Xe = (e) => ({
292
+ shipId: e.id,
293
+ row: e.cells[0].row,
294
+ col: e.cells[0].col,
295
+ orientation: e.orientation
296
+ });
297
+ function Ze(e) {
298
+ return !e || typeof e != "object" ? null : typeof e.ship_id == "string" ? {
299
+ shipId: e.ship_id,
300
+ row: e.row,
301
+ col: e.col,
302
+ orientation: e.orientation
303
+ } : typeof e.id == "string" && Array.isArray(e.cells) && e.cells.length ? Xe(e) : null;
304
+ }
305
+ function Qe(e) {
306
+ if (!Array.isArray(e)) return null;
307
+ let t = r();
308
+ for (let n of e) {
309
+ let e = Ze(n), r = e && a(t, e);
310
+ if (!r?.ok) return null;
311
+ t = r.board;
312
+ }
313
+ return t;
314
+ }
315
+ function $e(e) {
316
+ if (!Array.isArray(e)) return null;
317
+ let t = e.map(Ze);
318
+ return t.some((e) => !e) ? null : t.map(({ shipId: e, row: t, col: n, orientation: r }) => ({
319
+ ship_id: e,
320
+ row: t,
321
+ col: n,
322
+ orientation: r
323
+ })).sort((e, t) => e.ship_id < t.ship_id ? -1 : +(e.ship_id > t.ship_id));
324
+ }
325
+ function et(t) {
326
+ let n = Qe(t);
327
+ return n && e(n) ? n.ships.map(Ye) : null;
328
+ }
329
+ var tt = (e) => !!et(e);
330
+ function nt(t) {
331
+ let n = Qe(t?.myFleet);
332
+ return n && e(n) ? {
333
+ ...n,
334
+ shots: t.incomingShots.map((e) => e.slice())
335
+ } : null;
336
+ }
337
+ function rt(e, { shipId: t, row: n, col: r, orientation: i } = {}) {
338
+ if (!qe(e)) return e;
339
+ let o = Qe(e.myFleet.filter((e) => e.id !== t)), s = o && a(o, {
340
+ shipId: t,
341
+ row: n,
342
+ col: r,
343
+ orientation: i
344
+ });
345
+ return s?.ok ? {
346
+ ...e,
347
+ myFleet: s.board.ships.map(Ye)
348
+ } : e;
349
+ }
350
+ function it(e, t) {
351
+ return !qe(e) || !e.myFleet.some((e) => e.id === t) ? e : {
352
+ ...e,
353
+ myFleet: e.myFleet.filter((e) => e.id !== t)
354
+ };
355
+ }
356
+ function at(e) {
357
+ let t = Math.floor(4294967296 / e) * e, n = /* @__PURE__ */ new Uint32Array(1);
358
+ do
359
+ globalThis.crypto.getRandomValues(n);
360
+ while (n[0] >= t);
361
+ return n[0] % e;
362
+ }
363
+ function ot(t = at) {
364
+ for (let n = 0; n < 50; n += 1) {
365
+ let n = r();
366
+ for (let e of o) for (let r = 0; r < 300; r += 1) {
367
+ let r = a(n, {
368
+ shipId: e.id,
369
+ row: t(10),
370
+ col: t(10),
371
+ orientation: t(2) === 0 ? "horizontal" : "vertical"
372
+ });
373
+ if (r.ok) {
374
+ n = r.board;
375
+ break;
376
+ }
377
+ }
378
+ if (e(n)) return n.ships.map(Ye);
379
+ }
380
+ throw Error("No se pudo generar una flota aleatoria.");
381
+ }
382
+ var st = (e, t) => qe(e) ? {
383
+ ...e,
384
+ myFleet: ot(t)
385
+ } : e, ct = (e) => Array.from(e, (e) => e.toString(16).padStart(2, "0")).join("");
386
+ function lt() {
387
+ let e = /* @__PURE__ */ new Uint8Array(16);
388
+ return globalThis.crypto.getRandomValues(e), ct(e);
389
+ }
390
+ function ut(e, t) {
391
+ let n = $e(e);
392
+ if (!n || typeof t != "string") throw TypeError("Flota inválida");
393
+ return JSON.stringify({
394
+ fleet: n,
395
+ salt: t
396
+ });
397
+ }
398
+ async function dt(e, t) {
399
+ let n = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(ut(e, t)));
400
+ return ct(new Uint8Array(n));
401
+ }
402
+ function ft(e, t) {
403
+ if (!e || !t) return null;
404
+ let n = i(e, {
405
+ row: t.row,
406
+ col: t.col
407
+ });
408
+ if (!n.ok) return null;
409
+ let r = n.sunk ? e.ships.find((e) => e.id === n.shipId) : null;
410
+ return {
411
+ ply: t.ply,
412
+ row: t.row,
413
+ col: t.col,
414
+ result: n.result,
415
+ sunk: r ? {
416
+ ship_id: r.id,
417
+ cells: r.cells.map((e) => [e.row, e.col])
418
+ } : null,
419
+ defeated: n.defeated
420
+ };
421
+ }
422
+ function pt(e) {
423
+ let t = o.find((t) => t.id === e?.ship_id);
424
+ if (!t || !Array.isArray(e.cells) || e.cells.length !== t.size) return null;
425
+ let r = e.cells.map((e) => Array.isArray(e) ? {
426
+ row: e[0],
427
+ col: e[1]
428
+ } : null);
429
+ if (r.some((e) => !n(e))) return null;
430
+ r.sort(We);
431
+ 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);
432
+ return !i && !a ? null : {
433
+ id: t.id,
434
+ size: t.size,
435
+ orientation: i ? "horizontal" : "vertical",
436
+ cells: r,
437
+ sunk: !0
438
+ };
439
+ }
440
+ function mt(e, t) {
441
+ let { row: n, col: r, result: i, sunk: a } = t, s = !!t.defeated;
442
+ if (i !== "hit" && i !== "miss" || e.targetShots[n][r] !== null) return null;
443
+ let c = Le(e.targetShots, n, r, i), l = Re(c), u = null;
444
+ if (a) {
445
+ if (u = i === "hit" ? pt(a) : null, !u || e.sunkEnemyShips.some((e) => e.id === u.id)) return null;
446
+ let t = new Set(e.sunkEnemyShips.flatMap((e) => e.cells.map(Ue)));
447
+ if (!u.cells.some((e) => e.row === n && e.col === r) || u.cells.some((e) => c[e.row][e.col] !== "hit" || t.has(Ue(e)))) return null;
448
+ }
449
+ let d = e.sunkEnemyShips.length + +!!u;
450
+ return l > Ae || s !== (l === Ae) || s !== (d === o.length) || !s && Ae - l > 100 - ze(c) ? null : {
451
+ shots: c,
452
+ ship: u
453
+ };
454
+ }
455
+ function ht(e, t) {
456
+ let n = ft(nt(e), t);
457
+ if (!n || n.result !== t.result || n.defeated !== !!t.defeated || !!n.sunk != !!t.sunk) return null;
458
+ let r = n.sunk ? pt(n.sunk) : null;
459
+ return r && (t.sunk.ship_id !== r.id || !Ge(r.cells, t.sunk.cells.map(([e, t]) => ({
460
+ row: e,
461
+ col: t
462
+ })))) ? null : {
463
+ shots: Le(e.incomingShots, t.row, t.col, t.result),
464
+ ship: r
465
+ };
466
+ }
467
+ function gt(e, t, n, r) {
468
+ let i = He(e, t);
469
+ if (e[i]) return e[i] === n ? e : null;
470
+ let a = {
471
+ ...e,
472
+ [i]: n
473
+ };
474
+ if (t === e.ownId) {
475
+ let t = r?.commitment === n ? et(r.fleet) : null;
476
+ t && je.test(r.salt ?? "") ? a = {
477
+ ...a,
478
+ myFleet: t,
479
+ mySalt: r.salt,
480
+ myCommitment: n
481
+ } : e.myCommitment === n && e.mySalt || (a = {
482
+ ...a,
483
+ myFleet: [],
484
+ mySalt: null,
485
+ myCommitment: n,
486
+ error: Fe
487
+ }), a.myReady = !0;
488
+ } else a.opponentReady = !0;
489
+ return a.hostCommitment && a.guestCommitment && (a = {
490
+ ...a,
491
+ status: "active",
492
+ turnId: e.hostId,
493
+ ply: 0,
494
+ pendingShot: null
495
+ }), a;
496
+ }
497
+ function _t(e, t, { row: r, col: i, ply: a }, o) {
498
+ let s = t === e.ownId ? e.targetShots : e.incomingShots;
499
+ return !n({
500
+ row: r,
501
+ col: i
502
+ }) || s[r][i] !== null ? null : {
503
+ ...e,
504
+ pendingShot: {
505
+ row: r,
506
+ col: i,
507
+ ply: a,
508
+ by: t
509
+ },
510
+ lastEventId: o ?? e.lastEventId
511
+ };
512
+ }
513
+ function vt(e, t, n, r) {
514
+ let i = e.pendingShot, a = t === e.ownId, o = a ? ht(e, n) : mt(e, n);
515
+ if (!o) return null;
516
+ let s = !!n.defeated, c = {
517
+ ply: i.ply,
518
+ by: i.by,
519
+ row: i.row,
520
+ col: i.col,
521
+ result: n.result,
522
+ sunk: o.ship,
523
+ defeated: s
524
+ };
525
+ return {
526
+ ...e,
527
+ incomingShots: a ? o.shots : e.incomingShots,
528
+ targetShots: a ? e.targetShots : o.shots,
529
+ sunkEnemyShips: !a && o.ship ? [...e.sunkEnemyShips, o.ship] : e.sunkEnemyShips,
530
+ ply: i.ply,
531
+ shots: [...e.shots, c],
532
+ pendingShot: null,
533
+ lastShot: {
534
+ ...c,
535
+ eventId: r ?? null
536
+ },
537
+ lastEventId: r ?? e.lastEventId,
538
+ turnId: s ? null : t,
539
+ status: s ? "won" : "active",
540
+ winnerId: s ? i.by : null,
541
+ verification: s ? "pending" : e.verification
542
+ };
543
+ }
544
+ function yt(e, t, n) {
545
+ let { ply: r, row: i, col: a, prev_event_id: o } = t.data;
546
+ return n === Be(e, r) ? e.status === "active" ? r <= e.ply ? e : e.pendingShot ? r === e.pendingShot.ply ? e : N(e, M) : r > e.ply + 1 ? N(e, M) : n === e.turnId ? o === e.lastEventId ? _t(e, n, {
547
+ row: i,
548
+ col: a,
549
+ ply: r
550
+ }, t.event_id) ?? e : N(e, M) : e : N(e, e.status === "invited" ? Ne : M) : e;
551
+ }
552
+ function bt(e, t, n) {
553
+ let { ply: r, row: i, col: a } = t.data;
554
+ if (e.status !== "active") return e.status === "placement" ? N(e, M) : e;
555
+ let o = e.pendingShot;
556
+ return o ? r === o.ply ? n === o.by ? e : i !== o.row || a !== o.col ? n === e.ownId ? e : N(e, "El rival respondió a un disparo distinto.") : vt(e, n, t.data, t.event_id) || (n === e.ownId ? e : N(e, Pe)) : r < o.ply ? e : N(e, M) : r <= e.ply ? e : N(e, M);
557
+ }
558
+ function xt(e, t, n) {
559
+ return !e.winnerId || !["won", "closed"].includes(e.status) ? e : n === e.ownId ? e.myRevealSent ? e : {
560
+ ...e,
561
+ myRevealSent: !0
562
+ } : e.opponentReveal ? e : {
563
+ ...e,
564
+ opponentReveal: {
565
+ fleet: t.fleet.map((e) => ({ ...e })),
566
+ salt: t.salt
567
+ },
568
+ verification: "pending"
569
+ };
570
+ }
571
+ function St(e, t, n, r = {}) {
572
+ if (!e || e.game !== "battleship" || t?.game !== "battleship" || t.game_id !== e.gameId || n !== e.hostId && n !== e.guestId) return e;
573
+ let i = t.data;
574
+ if (t.type === "game_end") return i.reason !== "closed" || [
575
+ "closed",
576
+ "declined",
577
+ "won"
578
+ ].includes(e.status) ? e : {
579
+ ...e,
580
+ status: "closed",
581
+ closedBy: n,
582
+ error: ""
583
+ };
584
+ if (t.type === "bs_reveal") return xt(e, i, n);
585
+ if (Me.includes(e.status) || e.status === "conflict") return e;
586
+ switch (t.type) {
587
+ case "game_accept":
588
+ case "game_decline": return n !== e.guestId || e.status !== "invited" || i.invite_event_id !== e.inviteEventId ? e : t.type === "game_accept" ? {
589
+ ...e,
590
+ status: "placement",
591
+ acceptEventId: t.event_id,
592
+ lastEventId: t.event_id
593
+ } : {
594
+ ...e,
595
+ status: "declined",
596
+ lastEventId: t.event_id
597
+ };
598
+ case "bs_commit": return e.status === "invited" ? N(e, Ne) : e.status === "placement" ? gt(e, n, i.commitment, r.stored) ?? e : e;
599
+ case "bs_fire": return yt(e, t, n);
600
+ case "bs_result": return bt(e, t, n);
601
+ default: return e;
602
+ }
603
+ }
604
+ function Ct(e, t) {
605
+ let n = Oe({
606
+ gameId: String(e.gameId),
607
+ players: [e.hostId, e.guestId],
608
+ firstPlayerId: e.hostId
609
+ });
610
+ for (let e of n.players) {
611
+ for (let r of t[e]) n = ke(n, {
612
+ type: "place_ship",
613
+ playerId: e,
614
+ ...Xe(r)
615
+ });
616
+ n = ke(n, {
617
+ type: "ready",
618
+ playerId: e
619
+ });
620
+ }
621
+ if (n.phase !== "playing") return !1;
622
+ for (let t of e.shots) {
623
+ let e = ke(n, {
624
+ type: "fire",
625
+ playerId: t.by,
626
+ row: t.row,
627
+ col: t.col
628
+ });
629
+ if (e === n) return !1;
630
+ let r = e.lastShot;
631
+ if (r.result !== t.result || r.defeated !== t.defeated || r.sunk !== !!t.sunk) return !1;
632
+ if (t.sunk) {
633
+ let n = e.boards[e.players.indexOf(r.targetId)].ships.find((e) => e.id === r.shipId);
634
+ if (t.sunk.id !== r.shipId || !Ge(n.cells, t.sunk.cells)) return !1;
635
+ }
636
+ n = e;
637
+ }
638
+ return !e.winnerId || n.winnerId === e.winnerId;
639
+ }
640
+ async function wt(e, t = e?.opponentReveal) {
641
+ if (!e || !t) return "pending";
642
+ let n = Ve(e, e.ownId), r = e[He(e, n)], i = et(t.fleet);
643
+ if (!r || !i || typeof t.salt != "string" || !je.test(t.salt)) return "mismatch";
644
+ let a;
645
+ try {
646
+ a = await dt(t.fleet, t.salt);
647
+ } catch {
648
+ return "mismatch";
649
+ }
650
+ if (a !== r) return "mismatch";
651
+ let o = et(e.myFleet);
652
+ return o ? Ct(e, {
653
+ [e.ownId]: o,
654
+ [n]: i
655
+ }) ? "ok" : "mismatch" : "pending";
656
+ }
657
+ var Tt = (e) => {
658
+ if (e.result === "miss") return [
659
+ e.row,
660
+ e.col,
661
+ 0
662
+ ];
663
+ if (!e.sunk) return [
664
+ e.row,
665
+ e.col,
666
+ 1
667
+ ];
668
+ let t = e.sunk.cells[0];
669
+ return [
670
+ e.row,
671
+ e.col,
672
+ 2,
673
+ o.findIndex((t) => t.id === e.sunk.id),
674
+ t.row,
675
+ t.col,
676
+ +(e.sunk.orientation === "vertical")
677
+ ];
678
+ };
679
+ function Et(e) {
680
+ if (!e.acceptEventId) return {
681
+ commits: [null, null],
682
+ log: [],
683
+ head: e.inviteEventId
684
+ };
685
+ let t = e.shots.map(Tt);
686
+ return e.pendingShot && t.push([e.pendingShot.row, e.pendingShot.col]), {
687
+ accept_event_id: e.acceptEventId,
688
+ commits: [e.hostCommitment ?? null, e.guestCommitment ?? null],
689
+ log: t,
690
+ head: e.lastEventId
691
+ };
692
+ }
693
+ function Dt(e, t) {
694
+ let n = e.accept_event_id ?? null, r = t.accept_event_id ?? null;
695
+ if (n && r && n !== r) return "diverged";
696
+ let i = /* @__PURE__ */ new Set();
697
+ n && !r && i.add("ahead"), !n && r && i.add("behind");
698
+ for (let n of [0, 1]) {
699
+ let r = e.commits?.[n] ?? null, a = t.commits?.[n] ?? null;
700
+ if (r && a && r !== a) return "diverged";
701
+ r && !a && i.add("ahead"), !r && a && i.add("behind");
702
+ }
703
+ let a = e.log ?? [], o = t.log ?? [];
704
+ for (let e = 0; e < Math.min(a.length, o.length); e += 1) {
705
+ let t = a[e], n = o[e];
706
+ if (t.length === n.length) {
707
+ if (t.some((e, t) => e !== n[t])) return "diverged";
708
+ } else if (t[0] !== n[0] || t[1] !== n[1]) return "diverged";
709
+ else i.add(t.length === 2 ? "behind" : "ahead");
710
+ }
711
+ 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";
712
+ }
713
+ function Ot(e, t) {
714
+ if ((e.log ?? []).length || (t.log ?? []).length) return null;
715
+ let n = e.accept_event_id ?? t.accept_event_id;
716
+ return n ? {
717
+ accept_event_id: n,
718
+ commits: [0, 1].map((n) => e.commits?.[n] ?? t.commits?.[n] ?? null),
719
+ log: [],
720
+ head: n
721
+ } : null;
722
+ }
723
+ function kt(e, t, n = {}) {
724
+ let r = {
725
+ ...e,
726
+ status: "invited",
727
+ turnId: null,
728
+ myReady: !1,
729
+ opponentReady: !1,
730
+ incomingShots: Ie(),
731
+ targetShots: Ie(),
732
+ sunkEnemyShips: [],
733
+ pendingShot: null,
734
+ lastShot: null,
735
+ winnerId: null,
736
+ verification: null,
737
+ ply: 0,
738
+ shots: [],
739
+ acceptEventId: null,
740
+ hostCommitment: null,
741
+ guestCommitment: null,
742
+ error: "",
743
+ myRevealSent: !1,
744
+ opponentReveal: null,
745
+ closedBy: void 0
746
+ }, i = t.log ?? [], a = t.commits ?? [null, null];
747
+ if (!t.accept_event_id) return a.some(Boolean) || i.length ? null : {
748
+ ...r,
749
+ lastEventId: e.inviteEventId
750
+ };
751
+ if (t.accept_event_id === e.inviteEventId) return null;
752
+ let s = e.ownId === e.hostId ? 0 : 1;
753
+ if (e.myCommitment && a[s] && a[s] !== e.myCommitment && n.stored?.commitment !== a[s]) return null;
754
+ let c = {
755
+ ...r,
756
+ status: "placement",
757
+ acceptEventId: t.accept_event_id,
758
+ lastEventId: t.accept_event_id
759
+ };
760
+ for (let [t, r] of [e.hostId, e.guestId].entries()) if (a[t] && (c = gt(c, r, a[t], n.stored), !c)) return null;
761
+ if (i.length && c.status !== "active") return null;
762
+ for (let e = 0; e < i.length; e += 1) {
763
+ let t = i[e], n = e + 1;
764
+ if (c = _t(c, Be(c, n), {
765
+ row: t[0],
766
+ col: t[1],
767
+ ply: n
768
+ }, null), !c) return null;
769
+ if (t.length === 2) {
770
+ if (e !== i.length - 1) return null;
771
+ break;
772
+ }
773
+ let r = Ve(c, c.pendingShot.by), a = null;
774
+ if (t[2] === 2) {
775
+ let e = o[t[3]];
776
+ if (!e) return null;
777
+ let n = t[6] === 1;
778
+ a = {
779
+ ship_id: e.id,
780
+ cells: Array.from({ length: e.size }, (e, r) => [t[4] + (n ? r : 0), t[5] + (n ? 0 : r)])
781
+ };
782
+ }
783
+ let s = Re(r === c.ownId ? c.incomingShots : c.targetShots) + (t[2] === 0 ? 0 : 1);
784
+ if (c = vt(c, r, {
785
+ ply: n,
786
+ row: t[0],
787
+ col: t[1],
788
+ result: t[2] === 0 ? "miss" : "hit",
789
+ sunk: a,
790
+ defeated: s === Ae
791
+ }, null), !c || c.status === "won" && e !== i.length - 1) return null;
792
+ }
793
+ return !i.length && t.head !== t.accept_event_id ? null : (c = {
794
+ ...c,
795
+ lastEventId: t.head
796
+ }, c.winnerId && e.winnerId === c.winnerId && (c = {
797
+ ...c,
798
+ myRevealSent: e.myRevealSent,
799
+ opponentReveal: e.opponentReveal,
800
+ verification: e.verification
801
+ }), c);
802
+ }
803
+ function At(e, t) {
804
+ if (!e || !t) return !1;
805
+ let n = e.log?.[(t.data?.ply ?? 0) - 1];
806
+ switch (t.type) {
807
+ case "game_accept": return e.accept_event_id === t.event_id;
808
+ case "bs_commit": return (e.commits ?? []).includes(t.data.commitment);
809
+ case "bs_fire": return !!(n && n[0] === t.data.row && n[1] === t.data.col);
810
+ case "bs_result": return !!(n && n.length > 2 && n[0] === t.data.row && n[1] === t.data.col);
811
+ default: return !1;
812
+ }
813
+ }
814
+ function jt(e, t) {
815
+ let n = { ...e };
816
+ return t.acceptEventId && (n[t.acceptEventId] = !0), t.lastEventId && (n[t.lastEventId] = !0), n;
817
+ }
818
+ // src/games/battleship/net/fleetStorage.js
819
+ var Mt = "lira:bs:", Nt = 12096e5, Pt = (e, t) => `${Mt}${e}:${t}`, Ft = () => {
820
+ try {
821
+ return globalThis.localStorage ?? null;
822
+ } catch {
823
+ return null;
824
+ }
825
+ };
826
+ function It(e) {
827
+ 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);
828
+ }
829
+ function Lt(e) {
830
+ let t = Date.now();
831
+ for (let n = e.length - 1; n >= 0; --n) {
832
+ let r = e.key(n);
833
+ if (r?.startsWith(Mt)) try {
834
+ let n = JSON.parse(e.getItem(r));
835
+ It(n) && t - n.savedAt < Nt || e.removeItem(r);
836
+ } catch {
837
+ e.removeItem(r);
838
+ }
839
+ }
840
+ }
841
+ function Rt(e, t, { fleet: n, salt: r, commitment: i }) {
842
+ try {
843
+ let a = Ft();
844
+ return a ? (Lt(a), a.setItem(Pt(e, t), JSON.stringify({
845
+ fleet: n,
846
+ salt: r,
847
+ commitment: i,
848
+ savedAt: Date.now()
849
+ })), !0) : !1;
850
+ } catch {
851
+ return !1;
852
+ }
853
+ }
854
+ function zt(e, t) {
855
+ try {
856
+ let n = JSON.parse(Ft()?.getItem(Pt(e, t)) ?? "null");
857
+ return It(n) ? {
858
+ fleet: n.fleet,
859
+ salt: n.salt,
860
+ commitment: n.commitment
861
+ } : null;
862
+ } catch {
863
+ return null;
864
+ }
865
+ }
866
+ // src/games/tanks/logic/constants.js
867
+ var P = 1e5, Bt = 160 * P, F = 2 * P, Vt = 20 * P;
868
+ 2 * P;
869
+ var Ht = 1 * P;
870
+ 4 * P, 4 * P;
871
+ var Ut = 18e4, Wt = 25e4, Gt = 5e4, I = 25e3, Kt = 60 * P, qt = 4 * P, Jt = Object.freeze({
872
+ move: Object.freeze([-16, 16]),
873
+ yaw: Object.freeze([0, 359]),
874
+ pitch: Object.freeze([5, 80]),
875
+ power: Object.freeze([0, 100])
876
+ }), L = Object.freeze({
877
+ standard: Object.freeze({
878
+ id: "standard",
879
+ cost: 0,
880
+ radius: 6 * P,
881
+ maxDmg: 40,
882
+ depth: 15e4,
883
+ speedPct: 100
884
+ }),
885
+ heavy: Object.freeze({
886
+ id: "heavy",
887
+ cost: 1,
888
+ radius: 8 * P,
889
+ maxDmg: 55,
890
+ depth: 25e4,
891
+ speedPct: 85
892
+ }),
893
+ cluster: Object.freeze({
894
+ id: "cluster",
895
+ cost: 1,
896
+ radius: 4 * P,
897
+ maxDmg: 15,
898
+ depth: 8e4,
899
+ speedPct: 100
900
+ })
901
+ }), Yt = Object.freeze({
902
+ radius: 4 * P,
903
+ maxDmg: 15,
904
+ depth: 8e4
905
+ }), Xt = Object.freeze([
906
+ Object.freeze([
907
+ 0,
908
+ 0,
909
+ 0
910
+ ]),
911
+ Object.freeze([
912
+ 6e3,
913
+ 0,
914
+ 0
915
+ ]),
916
+ Object.freeze([
917
+ -6e3,
918
+ 0,
919
+ 0
920
+ ]),
921
+ Object.freeze([
922
+ 0,
923
+ 0,
924
+ 6e3
925
+ ]),
926
+ Object.freeze([
927
+ 0,
928
+ 0,
929
+ -6e3
930
+ ])
931
+ ]), Zt = Object.freeze({
932
+ heavy: 2,
933
+ cluster: 2
934
+ }), Qt = Object.freeze([
935
+ 0,
936
+ 17452,
937
+ 34899,
938
+ 52336,
939
+ 69756,
940
+ 87156,
941
+ 104528,
942
+ 121869,
943
+ 139173,
944
+ 156434,
945
+ 173648,
946
+ 190809,
947
+ 207912,
948
+ 224951,
949
+ 241922,
950
+ 258819,
951
+ 275637,
952
+ 292372,
953
+ 309017,
954
+ 325568,
955
+ 342020,
956
+ 358368,
957
+ 374607,
958
+ 390731,
959
+ 406737,
960
+ 422618,
961
+ 438371,
962
+ 453990,
963
+ 469472,
964
+ 484810,
965
+ 5e5,
966
+ 515038,
967
+ 529919,
968
+ 544639,
969
+ 559193,
970
+ 573576,
971
+ 587785,
972
+ 601815,
973
+ 615661,
974
+ 629320,
975
+ 642788,
976
+ 656059,
977
+ 669131,
978
+ 681998,
979
+ 694658,
980
+ 707107,
981
+ 719340,
982
+ 731354,
983
+ 743145,
984
+ 754710,
985
+ 766044,
986
+ 777146,
987
+ 788011,
988
+ 798636,
989
+ 809017,
990
+ 819152,
991
+ 829038,
992
+ 838671,
993
+ 848048,
994
+ 857167,
995
+ 866025,
996
+ 874620,
997
+ 882948,
998
+ 891007,
999
+ 898794,
1000
+ 906308,
1001
+ 913545,
1002
+ 920505,
1003
+ 927184,
1004
+ 933580,
1005
+ 939693,
1006
+ 945519,
1007
+ 951057,
1008
+ 956305,
1009
+ 961262,
1010
+ 965926,
1011
+ 970296,
1012
+ 974370,
1013
+ 978148,
1014
+ 981627,
1015
+ 984808,
1016
+ 987688,
1017
+ 990268,
1018
+ 992546,
1019
+ 994522,
1020
+ 996195,
1021
+ 997564,
1022
+ 998630,
1023
+ 999391,
1024
+ 999848,
1025
+ 1e6
1026
+ ]), $t = 1e6;
1027
+ function en(e) {
1028
+ let t = (e % 360 + 360) % 360;
1029
+ return t <= 90 ? Qt[t] : t <= 180 ? Qt[180 - t] : t <= 270 ? -Qt[t - 180] : -Qt[360 - t];
1030
+ }
1031
+ function tn(e) {
1032
+ return en(e + 90);
1033
+ }
1034
+ function R(e, t) {
1035
+ return Math.trunc(e * t / $t);
1036
+ }
1037
+ // src/games/tanks/logic/rng.js
1038
+ var nn = (e) => Number.isInteger(e) && e >= 0 && e <= 4294967295;
1039
+ function rn(e) {
1040
+ let t = e >>> 0;
1041
+ return function() {
1042
+ t = t + 1831565813 >>> 0;
1043
+ let e = t;
1044
+ return e = Math.imul(e ^ e >>> 15, e | 1), e ^= e + Math.imul(e ^ e >>> 7, e | 61), (e ^ e >>> 14) >>> 0;
1045
+ };
1046
+ }
1047
+ function z(e, t, n) {
1048
+ return t + e() % (n - t + 1);
1049
+ }
1050
+ function an(e, t) {
1051
+ let n = rn((e ^ Math.imul(t, 2654435761)) >>> 0);
1052
+ return {
1053
+ x: z(n, -40, 40),
1054
+ z: z(n, -40, 40)
1055
+ };
1056
+ }
1057
+ // src/games/tanks/logic/terrain.js
1058
+ var B = (e, t, n) => e < t ? t : e > n ? n : e, V = (e, t, n, r) => e + Math.trunc((t - e) * n / r);
1059
+ function H(e, t, n) {
1060
+ let r = B(t, 0, Bt), i = B(n, 0, Bt), a = Math.min(Math.trunc(r / F), 79), o = Math.min(Math.trunc(i / F), 79), s = r - a * F, c = i - o * F, l = o * 81;
1061
+ return V(V(e[l + a], e[l + a + 1], s, F), V(e[l + 81 + a], e[l + 81 + a + 1], s, F), c, F);
1062
+ }
1063
+ function on(e, t, n, r) {
1064
+ let i = Math.trunc(80 / t) + 1, a = [];
1065
+ for (let t = 0; t < i * i; t += 1) a.push(z(e, n, r) * 1e3);
1066
+ return {
1067
+ n: i,
1068
+ step: t,
1069
+ values: a
1070
+ };
1071
+ }
1072
+ function sn({ n: e, step: t, values: n }, r, i) {
1073
+ let a = Math.min(Math.trunc(r / t), e - 2), o = Math.min(Math.trunc(i / t), e - 2), s = r - a * t, c = i - o * t, l = (t, r) => n[r * e + t];
1074
+ return V(V(l(a, o), l(a + 1, o), s, t), V(l(a, o + 1), l(a + 1, o + 1), s, t), c, t);
1075
+ }
1076
+ function cn(e) {
1077
+ let t = new Int32Array(e.length);
1078
+ for (let n = 0; n < 81; n += 1) for (let r = 0; r < 81; r += 1) {
1079
+ let i = 0;
1080
+ for (let t = -1; t <= 1; t += 1) for (let a = -1; a <= 1; a += 1) i += e[B(n + t, 0, 80) * 81 + B(r + a, 0, 80)];
1081
+ t[n * 81 + r] = Math.trunc(i / 9);
1082
+ }
1083
+ return t;
1084
+ }
1085
+ function ln(e, t, n, r, i) {
1086
+ let a = H(e, t, n), o = r * r, s = i * i;
1087
+ for (let r = 0; r < 81; r += 1) for (let c = 0; c < 81; c += 1) {
1088
+ let l = c * F - t, u = r * F - n;
1089
+ if (l > i || l < -i || u > i || u < -i) continue;
1090
+ let d = l * l + u * u;
1091
+ if (d >= s) continue;
1092
+ let f = r * 81 + c;
1093
+ if (d <= o) e[f] = a;
1094
+ else {
1095
+ let t = Math.trunc((d - o) * 1e3 / (s - o));
1096
+ e[f] = a + Math.trunc((e[f] - a) * t / 1e3);
1097
+ }
1098
+ }
1099
+ }
1100
+ var U = (e, t, n) => z(e, t, n) * (P / 2), un = (e, t, n, r, i) => {
1101
+ let a = e - n, o = t - r;
1102
+ return a > i || a < -i || o > i || o < -i ? !1 : a * a + o * o < i * i;
1103
+ }, dn = (e, t, n, r) => t >= e.x - e.w / 2 - r && t <= e.x + e.w / 2 + r && n >= e.z - e.d / 2 - r && n <= e.z + e.d / 2 + r;
1104
+ function fn(e) {
1105
+ let t = rn(e), n = on(t, 20, 0, 1200), r = on(t, 10, -250, 250), i = on(t, 4, -60, 60), a = /* @__PURE__ */ new Int32Array(6561);
1106
+ for (let e = 0; e < 81; e += 1) for (let t = 0; t < 81; t += 1) {
1107
+ let o = 3 * P + sn(n, t, e) + sn(r, t, e) + sn(i, t, e);
1108
+ a[e * 81 + t] = B(o, 0, Vt);
1109
+ }
1110
+ a = cn(cn(a));
1111
+ let o = [{
1112
+ x: 20 * P + U(t, -4, 4),
1113
+ z: 80 * P + U(t, -40, 40)
1114
+ }, {
1115
+ x: 140 * P + U(t, -4, 4),
1116
+ z: 80 * P + U(t, -40, 40)
1117
+ }];
1118
+ for (let e of o) ln(a, e.x, e.z, qt, qt + 3 * P);
1119
+ let s = [], c = z(t, 4, 6);
1120
+ for (let e = 0; e < 200 && s.length < c; e += 1) {
1121
+ let e = t() % 2 == 0 ? "rock" : "wall", n = U(t, 4, 12), r = U(t, 4, 12);
1122
+ e === "wall" && (n >= r ? r = 2 * P : n = 2 * P);
1123
+ let i = U(t, 4, 10), c = U(t, 100, 220), l = U(t, 40, 280), u = 12 * P + (n > r ? n : r);
1124
+ if (o.some((e) => un(e.x, e.z, c, l, u))) continue;
1125
+ let d = {
1126
+ x: c,
1127
+ z: l,
1128
+ w: n,
1129
+ d: r
1130
+ };
1131
+ if (s.some((e) => dn(e, c, l, (n > r ? n : r) + 4e5))) continue;
1132
+ let f = [
1133
+ [-1, -1],
1134
+ [1, -1],
1135
+ [-1, 1],
1136
+ [1, 1]
1137
+ ].map(([e, t]) => H(a, c + e * n / 2, l + t * r / 2)), p = Math.min(H(a, c, l), ...f);
1138
+ s.push({
1139
+ id: s.length,
1140
+ kind: e,
1141
+ ...d,
1142
+ h: i,
1143
+ y: p
1144
+ });
1145
+ }
1146
+ let l = [], u = z(t, 30, 60);
1147
+ for (let e = 0; e < u * 10 && l.length < u; e += 1) {
1148
+ let e = U(t, 4, 316), n = U(t, 4, 316), r = t() % 3 == 0 ? "rock" : "tree", i = z(t, 80, 140);
1149
+ o.some((t) => un(t.x, t.z, e, n, 1e6)) || s.some((t) => dn(t, e, n, 2e5)) || l.push({
1150
+ id: l.length,
1151
+ kind: r,
1152
+ x: e,
1153
+ z: n,
1154
+ scale: i
1155
+ });
1156
+ }
1157
+ return {
1158
+ heights: a,
1159
+ spawns: o,
1160
+ obstacles: s,
1161
+ decor: l
1162
+ };
1163
+ }
1164
+ function pn(e, { x: t, z: n, radius: r, depth: i }) {
1165
+ let a = r * r, o = (e) => B(Math.trunc(e / F) - 1, 0, 80);
1166
+ for (let s = o(n - r); s <= o(n + r) + 2 && s < 81; s += 1) for (let c = o(t - r); c <= o(t + r) + 2 && c < 81; c += 1) {
1167
+ let o = c * F - t, l = s * F - n;
1168
+ if (o > r || o < -r || l > r || l < -r) continue;
1169
+ let u = o * o + l * l;
1170
+ if (u >= a) continue;
1171
+ let d = Math.trunc((a - u) * 4096 / a), f = s * 81 + c, p = e[f] - Math.trunc(i * d / 4096);
1172
+ e[f] = p < 0 ? 0 : p;
1173
+ }
1174
+ return e;
1175
+ }
1176
+ function mn(e, t) {
1177
+ return e.filter((e) => !t.some((t) => un(t.x, t.z, e.x, e.z, t.radius)));
1178
+ }
1179
+ // src/games/tanks/logic/ballistics.js
1180
+ function hn(e, t) {
1181
+ return Math.trunc((2e4 + 600 * e) * L[t].speedPct / 100);
1182
+ }
1183
+ function gn(e, { yaw: t, pitch: n, power: r, ammo: i }) {
1184
+ let a = tn(n), o = en(n), s = tn(t), c = en(t), l = R(Wt, a), u = hn(r, i), d = R(u, a);
1185
+ return {
1186
+ x: e.x + R(l, s),
1187
+ y: e.y + Ut + R(Wt, o),
1188
+ z: e.z + R(l, c),
1189
+ vx: R(d, s),
1190
+ vy: R(u, o),
1191
+ vz: R(d, c)
1192
+ };
1193
+ }
1194
+ function _n(e, t, n, r, i, a, o) {
1195
+ let s = e - r, c = t - i, l = n - a;
1196
+ return s > o || s < -o || c > o || c < -o || l > o || l < -o ? !1 : s * s + c * c + l * l < o * o;
1197
+ }
1198
+ function vn(e, { wind: t, heights: n, tanks: r, obstacles: i, maxTicks: a = 600, split: o = !1 }) {
1199
+ let { x: s, y: c, z: l, vx: u, vy: d, vz: f } = e, p = [
1200
+ s,
1201
+ c,
1202
+ l
1203
+ ];
1204
+ for (let e = 1; e <= a; e += 1) {
1205
+ let a = d;
1206
+ u += t.x, d -= 392, f += t.z, s += u, c += d, l += f;
1207
+ let m = null;
1208
+ for (let e of r) if (_n(s, c, l, e.x, e.y + 1e5, e.z, 2e5)) {
1209
+ m = {
1210
+ x: s,
1211
+ y: c,
1212
+ z: l,
1213
+ kind: "tank",
1214
+ tankId: e.id
1215
+ };
1216
+ break;
1217
+ }
1218
+ if (!m) {
1219
+ let e = i.find((e) => c <= e.y + e.h && dn(e, s, l, 0));
1220
+ e && (m = {
1221
+ x: s,
1222
+ y: c,
1223
+ z: l,
1224
+ kind: "obstacle",
1225
+ obstacleId: e.id
1226
+ });
1227
+ }
1228
+ if (!m && (s < 0 || s > 16e6 || l < 0 || l > 16e6) && (m = {
1229
+ x: s,
1230
+ y: c,
1231
+ z: l,
1232
+ kind: "out"
1233
+ }), !m) {
1234
+ let e = H(n, s, l);
1235
+ c <= e && (m = {
1236
+ x: s,
1237
+ y: e,
1238
+ z: l,
1239
+ kind: "terrain"
1240
+ });
1241
+ }
1242
+ if (!m && o && a > 0 && d <= 0 && (m = {
1243
+ x: s,
1244
+ y: c,
1245
+ z: l,
1246
+ kind: "split"
1247
+ }), m) return p.push(m.x, m.y, m.z), {
1248
+ samples: p,
1249
+ ticks: e,
1250
+ impact: m,
1251
+ velocity: {
1252
+ vx: u,
1253
+ vy: d,
1254
+ vz: f
1255
+ }
1256
+ };
1257
+ e % 2 == 0 && p.push(s, c, l);
1258
+ }
1259
+ return {
1260
+ samples: p,
1261
+ ticks: a,
1262
+ impact: {
1263
+ x: s,
1264
+ y: c,
1265
+ z: l,
1266
+ kind: "out"
1267
+ },
1268
+ velocity: {
1269
+ vx: u,
1270
+ vy: d,
1271
+ vz: f
1272
+ }
1273
+ };
1274
+ }
1275
+ var yn = (e, t, n, r) => ({
1276
+ role: e,
1277
+ startTick: t,
1278
+ samples: n.samples,
1279
+ ticks: n.ticks,
1280
+ impact: n.impact,
1281
+ radius: n.impact.kind === "split" ? 0 : r.radius,
1282
+ maxDmg: n.impact.kind === "split" ? 0 : r.maxDmg,
1283
+ depth: n.impact.kind === "split" ? 0 : r.depth
1284
+ });
1285
+ function bn(e, t, n) {
1286
+ let r = gn(e, t);
1287
+ if (t.ammo !== "cluster") return [yn("main", 0, vn(r, n), L[t.ammo])];
1288
+ let i = vn(r, {
1289
+ ...n,
1290
+ split: !0
1291
+ }), a = [yn("carrier", 0, i, Yt)];
1292
+ if (i.impact.kind !== "split") return a;
1293
+ let o = (n.maxTicks ?? 600) - i.ticks;
1294
+ for (let [e, t, r] of Xt) {
1295
+ let { x: s, y: c, z: l } = i.impact, { vx: u, vy: d, vz: f } = i.velocity, p = vn({
1296
+ x: s,
1297
+ y: c,
1298
+ z: l,
1299
+ vx: u + e,
1300
+ vy: d + t,
1301
+ vz: f + r
1302
+ }, {
1303
+ ...n,
1304
+ maxTicks: o,
1305
+ split: !1
1306
+ });
1307
+ a.push(yn("bomblet", i.ticks, p, Yt));
1308
+ }
1309
+ return a;
1310
+ }
1311
+ function xn(e, t) {
1312
+ let n = t.map(() => 0);
1313
+ for (let r of e) {
1314
+ let { impact: e, radius: i, maxDmg: a } = r;
1315
+ if (e.kind === "out" || e.kind === "split") continue;
1316
+ let o = i * i;
1317
+ t.forEach((t, r) => {
1318
+ let s = t.y + Ht;
1319
+ e.kind === "tank" && e.tankId === t.id && (n[r] += 25);
1320
+ let c = e.x - t.x, l = e.y - s, u = e.z - t.z;
1321
+ if (c >= i || c <= -i || l >= i || l <= -i || u >= i || u <= -i) return;
1322
+ let d = c * c + l * l + u * u;
1323
+ d < o && (n[r] += Math.trunc(a * (o - d) / o));
1324
+ });
1325
+ }
1326
+ return n;
1327
+ }
1328
+ function Sn(e) {
1329
+ return e.filter((e) => e.impact.kind !== "out" && e.impact.kind !== "split").map((e) => ({
1330
+ x: e.impact.x,
1331
+ z: e.impact.z,
1332
+ radius: e.radius,
1333
+ depth: e.depth
1334
+ }));
1335
+ }
1336
+ // src/games/tanks/logic/movement.js
1337
+ function Cn(e, t, { heights: n, obstacles: r, others: i }) {
1338
+ let a = t < 0 ? -1 : 1, o = (t < 0 ? -t : t) * (Gt / I), s = Math.min(o, Math.trunc(e.fuel / I)), c = a * R(I, tn(e.hullYaw)), l = a * R(I, en(e.hullYaw)), { x: u, z: d } = e, f = H(n, u, d), p = [{
1339
+ x: u,
1340
+ y: f,
1341
+ z: d
1342
+ }], m = 0, h = s < o ? "fuel" : null;
1343
+ for (let e = 0; e < s; e += 1) {
1344
+ let e = u + c, t = d + l;
1345
+ if (e < 4e5 || e > 156e5 || t < 4e5 || t > 156e5) {
1346
+ h = "border";
1347
+ break;
1348
+ }
1349
+ if (r.some((n) => dn(n, e, t, 2e5))) {
1350
+ h = "obstacle";
1351
+ break;
1352
+ }
1353
+ if (i.some((n) => {
1354
+ let r = n.x - e, i = n.z - t;
1355
+ return r * r + i * i < 16e10;
1356
+ })) {
1357
+ h = "tank";
1358
+ break;
1359
+ }
1360
+ let a = H(n, e, t);
1361
+ if ((a > f ? a - f : f - a) * 1e3 > 175e5) {
1362
+ h = "slope";
1363
+ break;
1364
+ }
1365
+ u = e, d = t, f = a, m += 1, m % 2 == 0 && p.push({
1366
+ x: u,
1367
+ y: f,
1368
+ z: d
1369
+ });
1370
+ }
1371
+ return m % 2 == 1 && p.push({
1372
+ x: u,
1373
+ y: f,
1374
+ z: d
1375
+ }), {
1376
+ path: p,
1377
+ x: u,
1378
+ y: f,
1379
+ z: d,
1380
+ used: m * I,
1381
+ stop: h
1382
+ };
1383
+ }
1384
+ // src/games/tanks/logic/game.js
1385
+ var wn = (e) => typeof e == "string" && e.length > 0 && e.length <= 256 && e.trim() === e, W = (e) => ({
1386
+ ok: !1,
1387
+ reason: e
1388
+ }), Tn = (e, [t, n]) => Number.isInteger(e) && e >= t && e <= n;
1389
+ function En({ gameId: e, players: t, firstPlayerId: n = t?.[0], seed: r } = {}) {
1390
+ if (!wn(e) || !Array.isArray(t) || t.length !== 2 || !t.every(wn) || t[0] === t[1] || !t.includes(n)) throw TypeError("Supply a gameId, two distinct player IDs and a valid firstPlayerId.");
1391
+ if (!nn(r)) throw TypeError("Supply an integer seed in 0..0xffffffff.");
1392
+ let { heights: i, spawns: a, obstacles: o, decor: s } = fn(r), c = t.map((e, t) => ({
1393
+ id: e,
1394
+ x: a[t].x,
1395
+ y: H(i, a[t].x, a[t].z),
1396
+ z: a[t].z,
1397
+ hullYaw: t === 0 ? 0 : 180,
1398
+ yaw: t === 0 ? 0 : 180,
1399
+ pitch: 30,
1400
+ hp: 100,
1401
+ fuel: Kt,
1402
+ ammo: { ...Zt },
1403
+ skips: 0
1404
+ }));
1405
+ return {
1406
+ game: "tanks",
1407
+ rulesVersion: 1,
1408
+ gameId: e,
1409
+ seed: r,
1410
+ players: t.slice(),
1411
+ firstPlayerId: n,
1412
+ phase: "playing",
1413
+ turnIndex: t.indexOf(n),
1414
+ ply: 0,
1415
+ maxShots: 30,
1416
+ shots: 0,
1417
+ tanks: c,
1418
+ heights: i,
1419
+ obstacles: o,
1420
+ decor: s,
1421
+ winnerId: null,
1422
+ result: null,
1423
+ reason: null,
1424
+ lastTurn: null,
1425
+ revision: 0
1426
+ };
1427
+ }
1428
+ function Dn(e, t) {
1429
+ return !e || !t || typeof t != "object" ? W("invalid_action") : e.phase === "finished" ? W("game_finished") : t.gameId !== void 0 && t.gameId !== e.gameId ? W("wrong_game") : t.expectedRevision !== void 0 && t.expectedRevision !== e.revision ? W("stale_revision") : e.players.includes(t.playerId) ? { ok: !0 } : W("unknown_player");
1430
+ }
1431
+ function On(e, t) {
1432
+ let n = Dn(e, t);
1433
+ if (!n.ok) return n;
1434
+ let r = e.players.indexOf(t.playerId);
1435
+ if (r !== e.turnIndex) return W("not_your_turn");
1436
+ if (!Tn(t.move, Jt.move)) return W("invalid_move");
1437
+ if (!Tn(t.yaw, Jt.yaw)) return W("invalid_yaw");
1438
+ if (!Tn(t.pitch, Jt.pitch)) return W("invalid_pitch");
1439
+ if (!Tn(t.power, Jt.power)) return W("invalid_power");
1440
+ if (typeof t.ammo != "string" || !Object.hasOwn(L, t.ammo)) return W("unknown_ammo");
1441
+ let i = L[t.ammo].cost;
1442
+ return i > 0 && e.tanks[r].ammo[t.ammo] < i ? W("out_of_ammo") : { ok: !0 };
1443
+ }
1444
+ function kn(e, t, { maxTicks: n = 600 } = {}) {
1445
+ let r = e.players.indexOf(t.playerId), i = e.tanks[r], a = e.tanks[1 - r], o = an(e.seed, e.ply), s = Cn(i, t.move ?? 0, {
1446
+ heights: e.heights,
1447
+ obstacles: e.obstacles,
1448
+ others: [a]
1449
+ }), c = {
1450
+ x: s.x,
1451
+ y: s.y,
1452
+ z: s.z
1453
+ }, l = e.tanks.map((e, t) => t === r ? {
1454
+ id: e.id,
1455
+ ...c
1456
+ } : {
1457
+ id: e.id,
1458
+ x: e.x,
1459
+ y: e.y,
1460
+ z: e.z
1461
+ }), u = bn(c, t, {
1462
+ wind: o,
1463
+ heights: e.heights,
1464
+ tanks: l,
1465
+ obstacles: e.obstacles,
1466
+ maxTicks: n
1467
+ }), d = xn(u, l), f = {};
1468
+ return e.players.forEach((e, t) => {
1469
+ f[e] = d[t];
1470
+ }), {
1471
+ playerId: t.playerId,
1472
+ movePath: s.path,
1473
+ moveStop: s.stop,
1474
+ fuelUsed: s.used,
1475
+ tankAfter: c,
1476
+ shots: u,
1477
+ damage: f,
1478
+ craters: Sn(u),
1479
+ wind: o
1480
+ };
1481
+ }
1482
+ function G(e, t, n, r) {
1483
+ return {
1484
+ ...e,
1485
+ ...r,
1486
+ phase: "finished",
1487
+ winnerId: t < 0 ? null : e.players[t],
1488
+ result: t < 0 ? "draw" : "win",
1489
+ reason: n,
1490
+ revision: e.revision + 1
1491
+ };
1492
+ }
1493
+ function An(e, t) {
1494
+ let n = e.turnIndex, r = {
1495
+ playerId: t.playerId,
1496
+ move: t.move,
1497
+ yaw: t.yaw,
1498
+ pitch: t.pitch,
1499
+ power: t.power,
1500
+ ammo: t.ammo
1501
+ }, i = kn(e, r), a = e.heights;
1502
+ if (i.craters.length) {
1503
+ a = Int32Array.from(e.heights);
1504
+ for (let e of i.craters) pn(a, e);
1505
+ }
1506
+ let o = i.craters.length ? mn(e.decor, i.craters) : e.decor, s = e.tanks.map((e, t) => {
1507
+ let o = t === n ? i.tankAfter : e, s = {
1508
+ ...e,
1509
+ ammo: { ...e.ammo },
1510
+ x: o.x,
1511
+ z: o.z,
1512
+ y: H(a, o.x, o.z),
1513
+ hp: Math.max(0, e.hp - i.damage[e.id])
1514
+ };
1515
+ if (t === n) {
1516
+ s.fuel = e.fuel - i.fuelUsed, s.yaw = r.yaw, s.pitch = r.pitch, s.skips = 0;
1517
+ let t = L[r.ammo].cost;
1518
+ t > 0 && (s.ammo[r.ammo] -= t);
1519
+ }
1520
+ return s;
1521
+ }), c = {
1522
+ ...e,
1523
+ tanks: s,
1524
+ heights: a,
1525
+ decor: o,
1526
+ shots: e.shots + 1,
1527
+ ply: e.ply + 1,
1528
+ turnIndex: 1 - n,
1529
+ lastTurn: {
1530
+ type: "turn",
1531
+ ply: e.ply,
1532
+ input: r,
1533
+ ...i
1534
+ }
1535
+ }, l = s.map((e) => e.hp === 0);
1536
+ if (l[0] && l[1]) return G(c, -1, "destroyed");
1537
+ if (l[0] || l[1]) return G(c, +!!l[0], "destroyed");
1538
+ if (c.shots >= c.maxShots) {
1539
+ let [e, t] = s.map((e) => e.hp);
1540
+ return G(c, e === t ? -1 : e > t ? 0 : 1, "max_shots");
1541
+ }
1542
+ return {
1543
+ ...c,
1544
+ revision: e.revision + 1
1545
+ };
1546
+ }
1547
+ function jn(e, t) {
1548
+ if (!t || typeof t != "object") return e;
1549
+ if (t.type === "turn") return On(e, t).ok ? An(e, t) : e;
1550
+ if (!Dn(e, t).ok) return e;
1551
+ let n = e.players.indexOf(t.playerId);
1552
+ if (t.type === "resign") return G(e, 1 - n, "resign");
1553
+ if (t.type === "skip") {
1554
+ if (n !== e.turnIndex || t.reason !== void 0 && t.reason !== "timeout") return e;
1555
+ let r = e.tanks[n].skips + 1, i = e.tanks.map((e, t) => t === n ? {
1556
+ ...e,
1557
+ skips: r
1558
+ } : e), a = {
1559
+ ...e,
1560
+ tanks: i,
1561
+ ply: e.ply + 1,
1562
+ turnIndex: 1 - n,
1563
+ lastTurn: {
1564
+ type: "skip",
1565
+ ply: e.ply,
1566
+ playerId: t.playerId
1567
+ }
1568
+ };
1569
+ return r >= 3 ? G(a, 1 - n, "timeout") : {
1570
+ ...a,
1571
+ revision: e.revision + 1
1572
+ };
1573
+ }
1574
+ return e;
1575
+ }
1576
+ function Mn(e, t) {
1577
+ let n = (e.lo ^ t) >>> 0, r = n * 435, i = r >>> 0, a = (r - i) / 4294967296;
1578
+ e.hi = Math.imul(e.hi, 435) + a + (n << 8) >>> 0, e.lo = i;
1579
+ }
1580
+ function Nn(e, t) {
1581
+ let n = t | 0;
1582
+ Mn(e, n & 255), Mn(e, n >>> 8 & 255), Mn(e, n >>> 16 & 255), Mn(e, n >>> 24 & 255);
1583
+ }
1584
+ function Pn(e) {
1585
+ let t = {
1586
+ hi: 3421674724,
1587
+ lo: 2216829733
1588
+ }, n = 0;
1589
+ for (let t = 0; t < e.heights.length; t += 1) n = Math.imul(n, 31) + e.heights[t] | 0;
1590
+ let r = e.winnerId === null ? -1 : e.players.indexOf(e.winnerId), i = [
1591
+ e.rulesVersion,
1592
+ e.ply,
1593
+ e.turnIndex,
1594
+ e.shots,
1595
+ +(e.phase === "finished"),
1596
+ e.result === "win" ? 1 : e.result === "draw" ? 2 : 0,
1597
+ r
1598
+ ];
1599
+ for (let t of e.tanks) i.push(t.x, t.y, t.z, t.hp, t.fuel, t.ammo.heavy, t.ammo.cluster, t.skips, t.yaw, t.pitch);
1600
+ i.push(n, e.decor.length);
1601
+ for (let e of i) Nn(t, e);
1602
+ return t.hi.toString(16).padStart(8, "0") + t.lo.toString(16).padStart(8, "0");
1603
+ }
1604
+ // src/games/tanks/net/sha256.js
1605
+ var Fn = new Uint32Array([
1606
+ 1116352408,
1607
+ 1899447441,
1608
+ 3049323471,
1609
+ 3921009573,
1610
+ 961987163,
1611
+ 1508970993,
1612
+ 2453635748,
1613
+ 2870763221,
1614
+ 3624381080,
1615
+ 310598401,
1616
+ 607225278,
1617
+ 1426881987,
1618
+ 1925078388,
1619
+ 2162078206,
1620
+ 2614888103,
1621
+ 3248222580,
1622
+ 3835390401,
1623
+ 4022224774,
1624
+ 264347078,
1625
+ 604807628,
1626
+ 770255983,
1627
+ 1249150122,
1628
+ 1555081692,
1629
+ 1996064986,
1630
+ 2554220882,
1631
+ 2821834349,
1632
+ 2952996808,
1633
+ 3210313671,
1634
+ 3336571891,
1635
+ 3584528711,
1636
+ 113926993,
1637
+ 338241895,
1638
+ 666307205,
1639
+ 773529912,
1640
+ 1294757372,
1641
+ 1396182291,
1642
+ 1695183700,
1643
+ 1986661051,
1644
+ 2177026350,
1645
+ 2456956037,
1646
+ 2730485921,
1647
+ 2820302411,
1648
+ 3259730800,
1649
+ 3345764771,
1650
+ 3516065817,
1651
+ 3600352804,
1652
+ 4094571909,
1653
+ 275423344,
1654
+ 430227734,
1655
+ 506948616,
1656
+ 659060556,
1657
+ 883997877,
1658
+ 958139571,
1659
+ 1322822218,
1660
+ 1537002063,
1661
+ 1747873779,
1662
+ 1955562222,
1663
+ 2024104815,
1664
+ 2227730452,
1665
+ 2361852424,
1666
+ 2428436474,
1667
+ 2756734187,
1668
+ 3204031479,
1669
+ 3329325298
1670
+ ]), K = (e, t) => e >>> t | e << 32 - t;
1671
+ function In(e) {
1672
+ let t = new TextEncoder().encode(String(e)), n = t.length, r = new Uint8Array((n + 9 >> 6) + 1 << 6);
1673
+ r.set(t), r[n] = 128;
1674
+ let i = new DataView(r.buffer);
1675
+ i.setUint32(r.length - 8, Math.floor(n / 536870912)), i.setUint32(r.length - 4, n << 3 >>> 0);
1676
+ let a = new Uint32Array([
1677
+ 1779033703,
1678
+ 3144134277,
1679
+ 1013904242,
1680
+ 2773480762,
1681
+ 1359893119,
1682
+ 2600822924,
1683
+ 528734635,
1684
+ 1541459225
1685
+ ]), o = /* @__PURE__ */ new Uint32Array(64);
1686
+ for (let e = 0; e < r.length; e += 64) {
1687
+ for (let t = 0; t < 16; t += 1) o[t] = i.getUint32(e + t * 4);
1688
+ for (let e = 16; e < 64; e += 1) {
1689
+ let t = K(o[e - 15], 7) ^ K(o[e - 15], 18) ^ o[e - 15] >>> 3, n = K(o[e - 2], 17) ^ K(o[e - 2], 19) ^ o[e - 2] >>> 10;
1690
+ o[e] = o[e - 16] + t + o[e - 7] + n >>> 0;
1691
+ }
1692
+ let [t, n, r, s, c, l, u, d] = a;
1693
+ for (let e = 0; e < 64; e += 1) {
1694
+ let i = d + (K(c, 6) ^ K(c, 11) ^ K(c, 25)) + (c & l ^ ~c & u) + Fn[e] + o[e] >>> 0, a = (K(t, 2) ^ K(t, 13) ^ K(t, 22)) + (t & n ^ t & r ^ n & r) >>> 0;
1695
+ d = u, u = l, l = c, c = s + i >>> 0, s = r, r = n, n = t, t = i + a >>> 0;
1696
+ }
1697
+ a[0] += t, a[1] += n, a[2] += r, a[3] += s, a[4] += c, a[5] += l, a[6] += u, a[7] += d;
1698
+ }
1699
+ return Array.from(a, (e) => e.toString(16).padStart(8, "0")).join("");
1700
+ }
1701
+ // src/games/tanks/net/session.js
1702
+ var Ln = "La partida perdió sincronización. Se intentará resincronizar.", Rn = "Falta la aceptación de la partida. Ciérrala y vuelve a invitar.", zn = "El rival reveló una semilla que no coincide con su invitación.", Bn = "Los resultados del disparo no coinciden entre dispositivos.", Vn = [
1703
+ "won",
1704
+ "draw",
1705
+ "closed",
1706
+ "declined"
1707
+ ], q = (e, t) => ({
1708
+ ...e,
1709
+ status: "conflict",
1710
+ error: t
1711
+ }), Hn = (e) => Array.from(e, (e) => e.toString(16).padStart(2, "0")).join("");
1712
+ function Un() {
1713
+ let e = /* @__PURE__ */ new Uint8Array(16);
1714
+ return globalThis.crypto.getRandomValues(e), Hn(e);
1715
+ }
1716
+ var Wn = (e) => In(`lira-tanks-seed:${e}`), Gn = (e, t) => parseInt(In(`lira-tanks-map:${e}:${t}`).slice(0, 8), 16) >>> 0;
1717
+ function Kn(e, t) {
1718
+ let n = t.first_player_id === e.guestId ? e.guestId : e.hostId;
1719
+ return {
1720
+ ...e,
1721
+ game: "tanks",
1722
+ status: "invited",
1723
+ turnId: null,
1724
+ firstPlayerId: n,
1725
+ seedCommit: t.seed_commit,
1726
+ rematchOf: t.rematch_of ?? null,
1727
+ seedA: null,
1728
+ seedB: null,
1729
+ seedEventId: null,
1730
+ acceptEventId: null,
1731
+ logic: null,
1732
+ log: [],
1733
+ ply: 0,
1734
+ lastAction: null,
1735
+ winnerId: null,
1736
+ result: null,
1737
+ seen: e.seen ?? {},
1738
+ pending: !1,
1739
+ pendingEvent: null,
1740
+ error: "",
1741
+ sync: e.sync ?? null
1742
+ };
1743
+ }
1744
+ var J = (e) => [e.hostId, e.guestId], qn = (e) => e.logic && e.logic.phase === "playing" ? J(e)[e.logic.turnIndex] : null, Jn = (e) => e?.status === "active" && !e.pendingEvent && qn(e) === e.ownId, Yn = (e, t, n) => e === "tk_turn" ? [
1745
+ 1,
1746
+ t.move,
1747
+ t.yaw,
1748
+ t.pitch,
1749
+ t.power,
1750
+ t.ammo
1751
+ ] : e === "tk_skip" ? [2] : [3, n], Xn = (e, t) => e.length === t.length && e.every((e, n) => e === t[n]);
1752
+ function Zn(e, t) {
1753
+ let n = J(e);
1754
+ if (t[0] === 3) return {
1755
+ type: "resign",
1756
+ playerId: n[t[1]]
1757
+ };
1758
+ let r = qn(e);
1759
+ return t[0] === 2 ? {
1760
+ type: "skip",
1761
+ playerId: r,
1762
+ reason: "timeout"
1763
+ } : {
1764
+ type: "turn",
1765
+ playerId: r,
1766
+ move: t[1],
1767
+ yaw: t[2],
1768
+ pitch: t[3],
1769
+ power: t[4],
1770
+ ammo: S[t[5]]
1771
+ };
1772
+ }
1773
+ function Qn(e, t, n, r) {
1774
+ let i = jn(e.logic, Zn(e, t));
1775
+ if (i === e.logic) return null;
1776
+ let a = i.phase === "finished";
1777
+ return {
1778
+ ...e,
1779
+ logic: i,
1780
+ log: [...e.log, t],
1781
+ ply: e.ply + 1,
1782
+ lastEventId: n,
1783
+ lastAction: {
1784
+ eventId: n,
1785
+ entry: t,
1786
+ author: r,
1787
+ turn: i.lastTurn ?? null
1788
+ },
1789
+ turnId: a ? null : J(e)[i.turnIndex],
1790
+ status: a ? i.result === "draw" ? "draw" : "won" : "active",
1791
+ winnerId: i.winnerId ?? null,
1792
+ result: i.result ?? null
1793
+ };
1794
+ }
1795
+ function $n(e, t, n) {
1796
+ if (Wn(t) !== e.seedCommit) return null;
1797
+ let r = En({
1798
+ gameId: e.gameId,
1799
+ players: J(e),
1800
+ firstPlayerId: e.firstPlayerId,
1801
+ seed: Gn(t, e.seedB)
1802
+ });
1803
+ return {
1804
+ ...e,
1805
+ seedA: t,
1806
+ seedEventId: n,
1807
+ logic: r,
1808
+ log: [],
1809
+ ply: 0,
1810
+ lastEventId: n,
1811
+ lastAction: null,
1812
+ status: "active",
1813
+ turnId: J(e)[r.turnIndex],
1814
+ error: ""
1815
+ };
1816
+ }
1817
+ function er(e, t, n) {
1818
+ if (![e.hostId, e.guestId].includes(n)) return e;
1819
+ let r = t.data;
1820
+ if (t.type === "game_end") return ["closed", "declined"].includes(e.status) ? e : {
1821
+ ...e,
1822
+ status: "closed",
1823
+ closedBy: n,
1824
+ error: ""
1825
+ };
1826
+ if (Vn.includes(e.status) || e.status === "conflict") return e;
1827
+ if (t.type === "game_accept" || t.type === "game_decline") return n !== e.guestId || e.status !== "invited" || r.invite_event_id !== e.inviteEventId ? e : t.type === "game_decline" ? {
1828
+ ...e,
1829
+ status: "declined",
1830
+ lastEventId: t.event_id
1831
+ } : {
1832
+ ...e,
1833
+ status: "seeding",
1834
+ seedB: r.seed_b,
1835
+ acceptEventId: t.event_id,
1836
+ lastEventId: t.event_id
1837
+ };
1838
+ if (t.type === "tk_seed") return n !== e.hostId || e.status !== "seeding" ? e : $n(e, r.seed_a, t.event_id) ?? q(e, zn);
1839
+ if (![
1840
+ "tk_turn",
1841
+ "tk_skip",
1842
+ "tk_resign"
1843
+ ].includes(t.type)) return e;
1844
+ if (e.status !== "active") return q(e, Rn);
1845
+ let i = J(e).indexOf(n), a = Yn(t.type, r, i);
1846
+ if (r.ply <= e.ply) return Xn(e.log[r.ply - 1] ?? [], a) ? e : q(e, Ln);
1847
+ if (r.ply > e.ply + 1 || r.prev_event_id !== e.lastEventId) return q(e, Ln);
1848
+ if (t.type !== "tk_resign" && n !== qn(e)) return e;
1849
+ let o = Qn(e, a, t.event_id, n);
1850
+ return o ? t.type === "tk_turn" && Pn(o.logic) !== r.hash ? q(e, Bn) : o : e;
1851
+ }
1852
+ function tr(e, t) {
1853
+ if (!Jn(e)) return null;
1854
+ let n = {
1855
+ ply: e.ply + 1,
1856
+ prev_event_id: e.lastEventId,
1857
+ move: t.move,
1858
+ yaw: t.yaw,
1859
+ pitch: t.pitch,
1860
+ power: t.power,
1861
+ ammo: S.indexOf(t.ammo)
1862
+ };
1863
+ if (n.ammo < 0) return null;
1864
+ let r = Qn(e, Yn("tk_turn", n), "local", e.ownId);
1865
+ return r ? {
1866
+ ...n,
1867
+ hash: Pn(r.logic)
1868
+ } : null;
1869
+ }
1870
+ function nr(e) {
1871
+ let t = {
1872
+ log: e.log ?? [],
1873
+ head: e.lastEventId
1874
+ };
1875
+ return e.acceptEventId && Object.assign(t, {
1876
+ accept_event_id: e.acceptEventId,
1877
+ seed_b: e.seedB
1878
+ }), e.seedA && Object.assign(t, {
1879
+ seed_a: e.seedA,
1880
+ seed_event_id: e.seedEventId
1881
+ }), t;
1882
+ }
1883
+ function rr(e, t) {
1884
+ if (e.accept_event_id && t.accept_event_id && e.accept_event_id !== t.accept_event_id || e.seed_a && t.seed_a && e.seed_a !== t.seed_a) return "diverged";
1885
+ let n = Math.min(e.log.length, t.log.length);
1886
+ for (let r = 0; r < n; r += 1) if (!Xn(e.log[r], t.log[r])) return "diverged";
1887
+ let r = (e) => (e.seed_a ? 2 : +!!e.accept_event_id) * 1e3 + e.log.length;
1888
+ return r(e) === r(t) ? e.log.length === t.log.length && e.head !== t.head && e.log.length > 0 ? "diverged" : "equal" : r(e) < r(t) ? "behind" : "ahead";
1889
+ }
1890
+ function ir(e, t) {
1891
+ let n = {
1892
+ ...e,
1893
+ status: "invited",
1894
+ acceptEventId: null,
1895
+ seedB: null,
1896
+ seedA: null,
1897
+ seedEventId: null,
1898
+ logic: null,
1899
+ log: [],
1900
+ ply: 0,
1901
+ lastAction: null,
1902
+ winnerId: null,
1903
+ result: null,
1904
+ turnId: null,
1905
+ error: "",
1906
+ lastEventId: e.inviteEventId
1907
+ };
1908
+ if (!t.accept_event_id) return t.log.length ? null : {
1909
+ ...n,
1910
+ lastEventId: t.head === e.inviteEventId ? t.head : e.inviteEventId
1911
+ };
1912
+ if (t.accept_event_id === e.inviteEventId) return null;
1913
+ if (n = {
1914
+ ...n,
1915
+ status: "seeding",
1916
+ acceptEventId: t.accept_event_id,
1917
+ seedB: t.seed_b,
1918
+ lastEventId: t.accept_event_id
1919
+ }, !t.seed_a) return n;
1920
+ if (n = $n(n, t.seed_a, t.seed_event_id), !n) return null;
1921
+ for (let e = 0; e < t.log.length; e += 1) {
1922
+ let r = t.log[e];
1923
+ if (!C(r)) return null;
1924
+ let i = e === t.log.length - 1, a = r[0] === 3 ? J(n)[r[1]] : qn(n);
1925
+ if (n = Qn(n, r, i ? t.head : `${t.seed_event_id}:${e + 1}`, a), !n) return null;
1926
+ }
1927
+ return n;
1928
+ }
1929
+ function ar(e, t) {
1930
+ if (!t) return !1;
1931
+ if (t.type === "tk_seed") return e.seed_a === t.data.seed_a;
1932
+ if (t.type === "game_accept") return e.accept_event_id === t.event_id;
1933
+ if (![
1934
+ "tk_turn",
1935
+ "tk_skip",
1936
+ "tk_resign"
1937
+ ].includes(t.type)) return !1;
1938
+ let n = e.log[t.data.ply - 1];
1939
+ return !!n && n[0] === Yn(t.type, t.data, 0)[0];
1940
+ }
1941
+ function or(e, t) {
1942
+ let n = { ...e };
1943
+ return [
1944
+ t.acceptEventId,
1945
+ t.seedEventId,
1946
+ t.lastEventId
1947
+ ].forEach((e) => {
1948
+ e && (n[e] = !0);
1949
+ }), n;
1950
+ }
1951
+ function sr(e) {
1952
+ return {
1953
+ gameId: e.gameId,
1954
+ roomId: e.roomId,
1955
+ hostId: e.hostId,
1956
+ guestId: e.guestId,
1957
+ ownId: e.ownId,
1958
+ firstPlayerId: e.firstPlayerId,
1959
+ seedCommit: e.seedCommit,
1960
+ rematchOf: e.rematchOf,
1961
+ inviteEventId: e.inviteEventId,
1962
+ createdAt: e.createdAt,
1963
+ status: e.status,
1964
+ ...nr(e)
1965
+ };
1966
+ }
1967
+ // src/games/tanks/net/tankStorage.js
1968
+ var cr = "lira:tk:", lr = 6048e5, ur = 20, dr = (e, t) => `${cr}${e}:${t}`, fr = () => {
1969
+ try {
1970
+ return globalThis.localStorage ?? null;
1971
+ } catch {
1972
+ return null;
1973
+ }
1974
+ };
1975
+ function pr(e) {
1976
+ let t = [];
1977
+ for (let n = 0; n < e.length; n += 1) {
1978
+ let r = e.key(n);
1979
+ if (r?.startsWith(cr)) try {
1980
+ let n = JSON.parse(e.getItem(r));
1981
+ t.push({
1982
+ key: r,
1983
+ value: n
1984
+ });
1985
+ } catch {
1986
+ t.push({
1987
+ key: r,
1988
+ value: null
1989
+ });
1990
+ }
1991
+ }
1992
+ return t;
1993
+ }
1994
+ function mr(e) {
1995
+ let t = Date.now(), n = pr(e);
1996
+ n.filter(({ value: e }) => !e || !(t - e.savedAt < lr)).forEach(({ key: t }) => e.removeItem(t));
1997
+ let r = n.filter(({ value: e }) => e && t - e.savedAt < lr).sort((e, t) => e.value.savedAt - t.value.savedAt);
1998
+ r.slice(0, Math.max(0, r.length - ur)).forEach(({ key: t }) => e.removeItem(t));
1999
+ }
2000
+ function hr(e, t, n) {
2001
+ try {
2002
+ let r = fr();
2003
+ if (!r) return !1;
2004
+ let i = gr(e, t) ?? {};
2005
+ return r.setItem(dr(e, t), JSON.stringify({
2006
+ ...i,
2007
+ ...n,
2008
+ savedAt: Date.now()
2009
+ })), mr(r), !0;
2010
+ } catch {
2011
+ return !1;
2012
+ }
2013
+ }
2014
+ function gr(e, t) {
2015
+ try {
2016
+ let n = JSON.parse(fr()?.getItem(dr(e, t)) ?? "null");
2017
+ return !n || typeof n != "object" || !(Date.now() - n.savedAt < lr) || n.seedA !== void 0 && !/^[0-9a-f]{32}$/.test(n.seedA) ? null : n;
2018
+ } catch {
2019
+ return null;
2020
+ }
2021
+ }
2022
+ function _r(e) {
2023
+ try {
2024
+ let t = fr();
2025
+ return t ? pr(t).filter(({ key: t, value: n }) => t.startsWith(`${cr}${e}:`) && n?.snapshot && Date.now() - n.savedAt < lr).map(({ value: e }) => e).sort((e, t) => t.savedAt - e.savedAt) : [];
2026
+ } catch {
2027
+ return [];
2028
+ }
2029
+ }
2030
+ // src/games/shared/useChatGames.js
2031
+ var vr = _e, Y = (e) => e?.game ?? "connect4", yr = (e) => Y(e) === "battleship", br = (e) => Y(e) === "tanks", xr = 250, Sr = (e) => [
2032
+ "won",
2033
+ "draw",
2034
+ "closed",
2035
+ "declined"
2036
+ ].includes(e.status), Cr = (e, t, n) => JSON.stringify([
2037
+ e,
2038
+ String(t),
2039
+ n
2040
+ ]), wr = (e) => {
2041
+ let t = Object.keys(e).filter((t) => Sr(e[t]));
2042
+ if (t.length <= 80) return e;
2043
+ let n = { ...e };
2044
+ return t.slice(0, t.length - 80).forEach((e) => {
2045
+ delete n[e];
2046
+ }), n;
2047
+ };
2048
+ function Tr(e, t, n) {
2049
+ if (![e.hostId, e.guestId].includes(n)) return e;
2050
+ if (t.type === "game_end" && t.data.reason === "closed") return ["closed", "declined"].includes(e.status) ? e : {
2051
+ ...e,
2052
+ status: "closed",
2053
+ closedBy: n,
2054
+ error: ""
2055
+ };
2056
+ if (Sr(e) || e.status === "conflict") return e;
2057
+ if (t.type === "game_accept" || t.type === "game_decline") return n !== e.guestId || e.status !== "invited" || t.data.invite_event_id !== e.inviteEventId ? e : {
2058
+ ...e,
2059
+ status: t.type === "game_accept" ? "active" : "declined",
2060
+ lastEventId: t.event_id,
2061
+ acceptEventId: t.type === "game_accept" ? t.event_id : e.acceptEventId
2062
+ };
2063
+ if (t.type !== "game_move") return e;
2064
+ let { ply: r, prev_event_id: i, column: a } = t.data;
2065
+ if (n !== (r % 2 == 1 ? e.hostId : e.guestId)) return e;
2066
+ if (e.status !== "active") return {
2067
+ ...e,
2068
+ status: "conflict",
2069
+ error: "Falta la aceptación de la partida. Ciérrala y vuelve a invitar."
2070
+ };
2071
+ if (r <= e.ply || r > e.ply + 1 || i !== e.lastEventId) return {
2072
+ ...e,
2073
+ status: "conflict",
2074
+ error: "La partida perdió sincronización. Ciérrala y envía una nueva invitación."
2075
+ };
2076
+ if (n !== e.turnId) return e;
2077
+ let o = Ee(e.board, a, n);
2078
+ return o ? {
2079
+ ...e,
2080
+ board: o.board,
2081
+ ply: r,
2082
+ lastEventId: t.event_id,
2083
+ moves: [...e.moves ?? [], [a, t.event_id]],
2084
+ lastMove: {
2085
+ row: o.row,
2086
+ column: a,
2087
+ eventId: t.event_id
2088
+ },
2089
+ winnerId: o.winner || null,
2090
+ winningCells: o.winningCells,
2091
+ status: o.winner ? "won" : o.draw ? "draw" : "active",
2092
+ turnId: n === e.hostId ? e.guestId : e.hostId
2093
+ } : e;
2094
+ }
2095
+ var Er = 8e3, Dr = {
2096
+ status: "idle",
2097
+ requestId: null,
2098
+ requestedAt: 0,
2099
+ auto: !1,
2100
+ outgoing: [],
2101
+ replies: [],
2102
+ offer: null,
2103
+ message: ""
2104
+ }, Or = (e) => [
2105
+ "game_resync_request",
2106
+ "game_resync_state",
2107
+ "bs_sync_request",
2108
+ "bs_sync_state",
2109
+ "tk_sync_request",
2110
+ "tk_sync_state"
2111
+ ].includes(e), kr = (e) => e.acceptEventId ? {
2112
+ accept_event_id: e.acceptEventId,
2113
+ moves: e.moves ?? [],
2114
+ rev: (e.moves ?? []).length
2115
+ } : {
2116
+ moves: [],
2117
+ rev: 0
2118
+ };
2119
+ function Ar(e, t, n) {
2120
+ let r = {
2121
+ ...e,
2122
+ board: xe(),
2123
+ ply: 0,
2124
+ turnId: e.hostId,
2125
+ winnerId: null,
2126
+ winningCells: [],
2127
+ lastMove: null,
2128
+ moves: [],
2129
+ error: ""
2130
+ };
2131
+ if (!t) return n.length ? null : {
2132
+ ...r,
2133
+ status: "invited",
2134
+ acceptEventId: null,
2135
+ lastEventId: e.inviteEventId
2136
+ };
2137
+ if (t === e.inviteEventId) return null;
2138
+ let i = {
2139
+ ...r,
2140
+ status: "active",
2141
+ acceptEventId: t,
2142
+ lastEventId: t
2143
+ }, a = /* @__PURE__ */ new Set([e.inviteEventId, t]);
2144
+ for (let t = 0; t < n.length; t += 1) {
2145
+ let [r, o] = n[t];
2146
+ if (a.has(o)) return null;
2147
+ a.add(o);
2148
+ let s = t % 2 == 0 ? e.hostId : e.guestId, c = Tr(i, {
2149
+ type: "game_move",
2150
+ event_id: o,
2151
+ data: {
2152
+ column: r,
2153
+ ply: t + 1,
2154
+ prev_event_id: i.lastEventId
2155
+ }
2156
+ }, s);
2157
+ if (c.status === "conflict" || c.ply !== t + 1 || c.lastEventId !== o) return null;
2158
+ i = c;
2159
+ }
2160
+ return i;
2161
+ }
2162
+ function jr(e, t) {
2163
+ if (e.acceptEventId && t.acceptEventId && e.acceptEventId !== t.acceptEventId) return "diverged";
2164
+ let n = Math.min(e.moves.length, t.moves.length);
2165
+ 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";
2166
+ 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";
2167
+ }
2168
+ var Mr = (e) => e.pendingEvent?.type === "game_move" && !e.pending ? e.pendingEvent.event_id : null, Nr = {
2169
+ requestType: "game_resync_request",
2170
+ stateType: "game_resync_state",
2171
+ historyOf: kr,
2172
+ rebuild: (e, t) => Ar(e, t.accept_event_id ?? null, t.moves),
2173
+ compare: (e, t) => jr({
2174
+ acceptEventId: e.acceptEventId ?? null,
2175
+ moves: e.moves ?? []
2176
+ }, {
2177
+ acceptEventId: t.accept_event_id ?? null,
2178
+ moves: t.moves
2179
+ }),
2180
+ offerOf: (e) => ({
2181
+ accept_event_id: e.accept_event_id ?? null,
2182
+ moves: e.moves
2183
+ }),
2184
+ covers: (e, t) => {
2185
+ let n = Mr(e);
2186
+ return !!(n && t.moves?.some((e) => e[1] === n));
2187
+ },
2188
+ markSeen: (e, t) => {
2189
+ let n = { ...e };
2190
+ return t.acceptEventId && (n[t.acceptEventId] = !0), (t.moves ?? []).forEach((e) => {
2191
+ n[e[1]] = !0;
2192
+ }), n;
2193
+ },
2194
+ merge: () => null
2195
+ }, Pr = (e) => ({
2196
+ requestType: "bs_sync_request",
2197
+ stateType: "bs_sync_state",
2198
+ historyOf: Et,
2199
+ rebuild: (t, n) => kt(t, n, { stored: e(t.scope, t.gameId) }),
2200
+ compare: (e, t) => Dt(Et(e), t),
2201
+ offerOf: (e) => ({
2202
+ accept_event_id: e.accept_event_id,
2203
+ commits: e.commits,
2204
+ log: e.log,
2205
+ head: e.head
2206
+ }),
2207
+ covers: (e, t) => !!(e.pendingEvent && !e.pending && At(t, e.pendingEvent)),
2208
+ markSeen: jt,
2209
+ merge: (e, t) => Ot(Et(e), t)
2210
+ }), Fr = {
2211
+ requestType: "tk_sync_request",
2212
+ stateType: "tk_sync_state",
2213
+ historyOf: nr,
2214
+ rebuild: ir,
2215
+ compare: (e, t) => rr(nr(e), t),
2216
+ offerOf: (e) => ({
2217
+ ...e,
2218
+ request_event_id: void 0
2219
+ }),
2220
+ covers: (e, t) => !!(e.pendingEvent && !e.pending && ar(t, e.pendingEvent)),
2221
+ markSeen: or,
2222
+ merge: () => null
2223
+ }, Ir = (e) => ({
2224
+ ...e,
2225
+ game: "connect4",
2226
+ turnId: e.hostId,
2227
+ status: "invited",
2228
+ board: xe(),
2229
+ ply: 0,
2230
+ winnerId: null,
2231
+ lastMove: null,
2232
+ pending: !1,
2233
+ error: "",
2234
+ pendingEvent: null,
2235
+ acceptEventId: null,
2236
+ moves: []
2237
+ }), Lr = (e, t, n) => j(t, {
2238
+ game_id: e.gameId,
2239
+ data: n,
2240
+ game: Y(e)
2241
+ });
2242
+ function Rr() {
2243
+ let e = null, t = /* @__PURE__ */ new Map(), n = (e, n) => t.get(`${e}:${n}`) ?? zt(e, n), r = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Set(), a = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Set(), s = Pr(n), l = /* @__PURE__ */ new Map(), u = (e, t) => l.get(`${e}:${t}`) ?? gr(e, t)?.seedA ?? null, d = {
2244
+ connect4: {
2245
+ create: (e) => Ir(e),
2246
+ apply: (e, t, n) => Tr(e, t, n),
2247
+ sync: Nr
2248
+ },
2249
+ battleship: {
2250
+ create: (e) => Ke(e),
2251
+ apply: (e, t, r, i) => St(e, t, r, { stored: t.type === "bs_commit" && r === i ? n(e.scope, e.gameId) : null }),
2252
+ sync: s,
2253
+ after: (e, t) => t().bsScheduleEffects(e)
2254
+ },
2255
+ tanks: {
2256
+ create: (e, t) => Kn(e, t.data),
2257
+ apply: (e, t, n) => er(e, t, n),
2258
+ sync: Fr,
2259
+ after: (e, t) => t().tkScheduleEffects(e)
2260
+ }
2261
+ }, f = (e) => d[Y(e)] ?? null, p = (e) => f(e)?.sync ?? Nr;
2262
+ return c((s, c) => ({
2263
+ games: {},
2264
+ configureTransport: (t) => {
2265
+ e = t;
2266
+ },
2267
+ clear: () => {
2268
+ r.forEach((e) => clearTimeout(e)), r.clear(), o.forEach((e) => clearTimeout(e)), o.clear(), t.clear(), l.clear(), i.clear(), a.clear(), s({ games: {} });
2269
+ },
2270
+ markDisconnected: (e) => s((t) => ({ games: Object.fromEntries(Object.entries(t.games).map(([t, n]) => [t, n.scope === e && !Sr(n) ? {
2271
+ ...n,
2272
+ status: "conflict",
2273
+ error: "Conexión interrumpida. Se intentará resincronizar al reconectar.",
2274
+ sync: {
2275
+ ...Dr,
2276
+ ...n.sync,
2277
+ status: "idle",
2278
+ auto: !1
2279
+ }
2280
+ } : n])) })),
2281
+ ingest: (t, n, r) => {
2282
+ let i = typeof n == "object" ? n : {
2283
+ scope: n,
2284
+ currentUserId: r
2285
+ }, o = i?.scope ?? e?.getScope?.(), l = String(i?.currentUserId ?? e?.getUserId?.() ?? ""), u = t.data ?? t.payload, f = u && typeof u == "object" ? {
2286
+ ...u,
2287
+ ...t
2288
+ } : t, p = f.message ?? f.text;
2289
+ if (typeof p != "string" || !p.startsWith("LIRA_GAME_V1:")) return !1;
2290
+ let m = ye(p), h = String(f.room_id ?? ""), g = String(f.user_id ?? "");
2291
+ if (!m || !o || !l || !g || !h.startsWith("private_")) return !0;
2292
+ let _ = h.slice(8).split("_");
2293
+ if (_.length !== 2 || !_.includes(l) || !_.includes(g)) return !0;
2294
+ let v = Cr(o, h, m.game_id), y = c().games[v];
2295
+ if (y && Y(y) !== m.game) return !0;
2296
+ if (Or(m.type)) return y && !y.seen[m.event_id] && c().handleResync(v, m, g, l), !0;
2297
+ if (!y && m.type !== "game_invite" && m.game === "tanks" && c().restoreTanks(o, m.game_id)) return c().ingest(t, n, r);
2298
+ if (!y && m.type !== "game_invite") {
2299
+ let e = Date.now();
2300
+ for (let [t, n] of a) e - n.at > 3e4 && a.delete(t);
2301
+ !a.has(v) && a.size >= 32 && a.delete(a.keys().next().value);
2302
+ let t = a.get(v) ?? {
2303
+ at: e,
2304
+ messages: []
2305
+ };
2306
+ return t.messages.length < 8 && !t.messages.some((e) => e.eventId === m.event_id) && t.messages.push({
2307
+ eventId: m.event_id,
2308
+ message: f
2309
+ }), a.set(v, t), !0;
2310
+ }
2311
+ if (y?.seen[m.event_id]) return !0;
2312
+ let b = y, x = d[m.game];
2313
+ if (!x) return !0;
2314
+ if (m.type === "game_invite") {
2315
+ let e = m.data.opponent_id;
2316
+ if (y || e === g || !_.includes(e)) return !0;
2317
+ b = x.create({
2318
+ key: v,
2319
+ gameId: m.game_id,
2320
+ game_id: m.game_id,
2321
+ scope: o,
2322
+ roomId: h,
2323
+ ownId: l,
2324
+ hostId: g,
2325
+ guestId: e,
2326
+ createdAt: f.timestamp ?? (/* @__PURE__ */ new Date()).toISOString(),
2327
+ inviteEventId: m.event_id,
2328
+ lastEventId: m.event_id,
2329
+ seen: {},
2330
+ sync: { ...Dr }
2331
+ }, m);
2332
+ } else y && (b = x.apply(y, m, g, l));
2333
+ if (!b || b === y) return !0;
2334
+ if (b = {
2335
+ ...b,
2336
+ seen: {
2337
+ ...b.seen,
2338
+ [m.event_id]: !0
2339
+ }
2340
+ }, s((e) => {
2341
+ let t = {
2342
+ ...e.games,
2343
+ [v]: b
2344
+ };
2345
+ if (m.type === "game_invite") {
2346
+ let e = Object.values(t).filter((e) => e.scope === o && e.roomId === h && !Sr(e)), n = e.sort((e, t) => e.gameId < t.gameId ? -1 : +(e.gameId > t.gameId))[0];
2347
+ e.forEach((e) => {
2348
+ e.key !== n?.key && (t[e.key] = {
2349
+ ...e,
2350
+ status: "closed",
2351
+ error: "Se conserva la otra invitación de esta conversación."
2352
+ });
2353
+ });
2354
+ }
2355
+ return { games: wr(t) };
2356
+ }), b.status === "conflict" && y?.status !== "conflict" && queueMicrotask(() => {
2357
+ c().requestResync(v, { auto: !0 });
2358
+ }), c().afterGameChange(v), m.type === "game_invite") {
2359
+ let e = a.get(v);
2360
+ a.delete(v), e && Date.now() - e.at <= 3e4 && e.messages.forEach((e) => c().ingest(e.message, o, l));
2361
+ }
2362
+ return !0;
2363
+ },
2364
+ invite: async ({ roomId: t, opponentId: n, gameType: r = "connect4", firstPlayerId: i, rematchOf: a }) => {
2365
+ if (!e) throw Error("Chat no disponible");
2366
+ if (!vr.includes(r)) throw Error("Juego no disponible");
2367
+ let o = e.getScope();
2368
+ if (!String(e.getUserId() ?? "") || !String(t).startsWith("private_")) throw Error("Abre un chat privado para jugar.");
2369
+ if (Object.values(c().games).some((e) => e.scope === o && e.roomId === String(t) && (!Sr(e) || e.pendingEvent))) throw Error("Cierra la partida actual antes de invitar.");
2370
+ let s = crypto.randomUUID(), u = {
2371
+ opponent_id: String(n),
2372
+ rules_version: 1
2373
+ };
2374
+ if (r === "tanks") {
2375
+ let e = Un();
2376
+ l.set(`${o}:${s}`, e), hr(o, s, { seedA: e }), u.seed_commit = Wn(e), i != null && (u.first_player_id = String(i)), a && (u.rematch_of = a);
2377
+ }
2378
+ let d = j("game_invite", {
2379
+ game_id: s,
2380
+ data: u,
2381
+ game: r
2382
+ });
2383
+ return c().sendEvent(t, d);
2384
+ },
2385
+ act: async (t, n, r = {}) => {
2386
+ let i = c().games[t], a = String(e?.getUserId?.() ?? "");
2387
+ if (!i || i.scope !== e?.getScope?.()) throw Error("Partida no disponible");
2388
+ if (n !== "game_end" && (i.pending || i.pendingEvent)) throw Error("Reintenta el envío pendiente antes de continuar.");
2389
+ let o = r;
2390
+ if (n === "game_accept" || n === "game_decline") {
2391
+ if (i.status !== "invited" || a !== i.guestId) return;
2392
+ o = { invite_event_id: i.inviteEventId }, n === "game_accept" && br(i) && (o.seed_b = Un());
2393
+ } else if (n === "game_move") {
2394
+ if (Y(i) !== "connect4" || i.status !== "active" || a !== i.turnId || !Ee(i.board, r.column, a)) return;
2395
+ o = {
2396
+ column: r.column,
2397
+ ply: i.ply + 1,
2398
+ prev_event_id: i.lastEventId
2399
+ };
2400
+ } else if (n === "game_end") o = { reason: "closed" };
2401
+ else return;
2402
+ return c().sendEvent(i.roomId, j(n, {
2403
+ game_id: i.gameId,
2404
+ data: o,
2405
+ game: Y(i)
2406
+ }));
2407
+ },
2408
+ bsUpdateLocal: (e, t) => {
2409
+ let n = c().games[e];
2410
+ if (!yr(n)) return !1;
2411
+ let r = t(n);
2412
+ return r !== n && (s((t) => t.games[e] === n ? { games: {
2413
+ ...t.games,
2414
+ [e]: r
2415
+ } } : t), c().games[e] === r);
2416
+ },
2417
+ bsPlaceShip: (e, t) => c().bsUpdateLocal(e, (e) => rt(e, t)),
2418
+ bsRemoveShip: (e, t) => c().bsUpdateLocal(e, (e) => it(e, t)),
2419
+ bsRandomFleet: (e) => c().bsUpdateLocal(e, (e) => st(e)),
2420
+ bsReady: async (n) => {
2421
+ let r = c().games[n];
2422
+ if (!yr(r) || r.status !== "placement" || r.myReady) return;
2423
+ if (r.scope !== e?.getScope?.()) throw Error("Partida no disponible");
2424
+ if (r.pending || r.pendingEvent) throw Error("Reintenta el envío pendiente antes de continuar.");
2425
+ let i = $e(r.myFleet);
2426
+ if (!tt(i)) throw Error("Coloca los cinco barcos antes de continuar.");
2427
+ let a = lt(), o = await dt(i, a), s = c().games[n];
2428
+ if (!(!s || s.myReady || s.status !== "placement" || s.pending || s.pendingEvent || JSON.stringify($e(s.myFleet)) !== JSON.stringify(i))) return t.set(`${r.scope}:${r.gameId}`, {
2429
+ fleet: i,
2430
+ salt: a,
2431
+ commitment: o
2432
+ }), Rt(r.scope, r.gameId, {
2433
+ fleet: i,
2434
+ salt: a,
2435
+ commitment: o
2436
+ }), c().sendEvent(r.roomId, j("bs_commit", {
2437
+ game_id: r.gameId,
2438
+ data: { commitment: o },
2439
+ game: "battleship"
2440
+ }));
2441
+ },
2442
+ bsFire: async (t, { row: n, col: r } = {}) => {
2443
+ let i = c().games[t];
2444
+ if (!yr(i) || i.scope !== e?.getScope?.()) throw Error("Partida no disponible");
2445
+ if (i.pending || i.pendingEvent) throw Error("Reintenta el envío pendiente antes de continuar.");
2446
+ if (Je(i) && i.targetShots[n]?.[r] === null) return c().sendEvent(i.roomId, j("bs_fire", {
2447
+ game_id: i.gameId,
2448
+ data: {
2449
+ ply: i.ply + 1,
2450
+ row: n,
2451
+ col: r,
2452
+ prev_event_id: i.lastEventId
2453
+ },
2454
+ game: "battleship"
2455
+ }));
2456
+ },
2457
+ bsScheduleEffects: (e) => {
2458
+ r.has(e) || r.set(e, setTimeout(() => {
2459
+ r.delete(e), c().bsRunEffects(e);
2460
+ }, xr));
2461
+ },
2462
+ bsRunEffects: (t) => {
2463
+ let r = c().games[t];
2464
+ if (!yr(r) || !e || r.scope !== e.getScope?.()) return;
2465
+ if (r.opponentReveal && r.verification === "pending" && !i.has(t)) {
2466
+ let e = r.opponentReveal;
2467
+ i.add(t), wt(r, e).then((n) => s((r) => {
2468
+ let i = r.games[t];
2469
+ return !i || i.opponentReveal !== e || i.verification === n ? r : { games: {
2470
+ ...r.games,
2471
+ [t]: {
2472
+ ...i,
2473
+ verification: n
2474
+ }
2475
+ } };
2476
+ })).catch(() => {}).finally(() => {
2477
+ i.delete(t);
2478
+ });
2479
+ }
2480
+ if (r.pending || r.pendingEvent) return;
2481
+ let a = (e, t) => {
2482
+ c().sendEvent(r.roomId, j(e, {
2483
+ game_id: r.gameId,
2484
+ data: t,
2485
+ game: "battleship"
2486
+ })).catch(() => {});
2487
+ };
2488
+ if (r.status === "active" && r.pendingShot && r.pendingShot.by !== r.ownId) {
2489
+ let e = ft(nt(r), r.pendingShot);
2490
+ e ? a("bs_result", e) : r.error || s((e) => ({ games: {
2491
+ ...e.games,
2492
+ [t]: {
2493
+ ...e.games[t],
2494
+ error: "Tu flota no está disponible en este dispositivo; no se pueden responder disparos."
2495
+ }
2496
+ } }));
2497
+ return;
2498
+ }
2499
+ let o = String(r.winnerId) !== String(r.ownId) || !!r.opponentReveal;
2500
+ if (r.winnerId && ["won", "closed"].includes(r.status) && !r.myRevealSent && o) {
2501
+ let e = $e(r.myFleet), t = r.mySalt ?? n(r.scope, r.gameId)?.salt;
2502
+ tt(e) && t && a("bs_reveal", {
2503
+ fleet: e,
2504
+ salt: t
2505
+ });
2506
+ }
2507
+ },
2508
+ afterGameChange: (e) => {
2509
+ let t = c().games[e];
2510
+ f(t)?.after?.(e, c);
2511
+ },
2512
+ tkTurn: async (t, n) => {
2513
+ let r = c().games[t];
2514
+ if (!br(r) || r.scope !== e?.getScope?.()) throw Error("Partida no disponible");
2515
+ if (r.pending || r.pendingEvent) throw Error("Reintenta el envío pendiente antes de continuar.");
2516
+ let i = tr(r, n);
2517
+ if (i) return c().sendEvent(r.roomId, j("tk_turn", {
2518
+ game_id: r.gameId,
2519
+ data: i,
2520
+ game: "tanks"
2521
+ }));
2522
+ },
2523
+ tkSkip: async (t) => {
2524
+ let n = c().games[t];
2525
+ if (br(n) && Jn(n) && n.scope === e?.getScope?.()) return c().sendEvent(n.roomId, j("tk_skip", {
2526
+ game_id: n.gameId,
2527
+ data: {
2528
+ ply: n.ply + 1,
2529
+ prev_event_id: n.lastEventId
2530
+ },
2531
+ game: "tanks"
2532
+ }));
2533
+ },
2534
+ tkResign: async (t) => {
2535
+ let n = c().games[t];
2536
+ if (!(!br(n) || n.status !== "active" || n.pending || n.pendingEvent || n.scope !== e?.getScope?.())) return c().sendEvent(n.roomId, j("tk_resign", {
2537
+ game_id: n.gameId,
2538
+ data: {
2539
+ ply: n.ply + 1,
2540
+ prev_event_id: n.lastEventId
2541
+ },
2542
+ game: "tanks"
2543
+ }));
2544
+ },
2545
+ tkScheduleEffects: (e) => {
2546
+ r.has(e) || r.set(e, setTimeout(() => {
2547
+ r.delete(e), c().tkRunEffects(e);
2548
+ }, xr));
2549
+ },
2550
+ tkRunEffects: (t) => {
2551
+ let n = c().games[t];
2552
+ if (!br(n) || (hr(n.scope, n.gameId, { snapshot: sr(n) }), !e || n.scope !== e.getScope?.() || n.pending || n.pendingEvent) || n.status !== "seeding" || n.ownId !== n.hostId) return;
2553
+ let r = u(n.scope, n.gameId);
2554
+ r ? c().sendEvent(n.roomId, j("tk_seed", {
2555
+ game_id: n.gameId,
2556
+ data: { seed_a: r },
2557
+ game: "tanks"
2558
+ })).catch(() => {}) : n.error || s((e) => ({ games: {
2559
+ ...e.games,
2560
+ [t]: {
2561
+ ...e.games[t],
2562
+ error: "La semilla de esta partida no está en este dispositivo. Ciérrala e invita de nuevo."
2563
+ }
2564
+ } }));
2565
+ },
2566
+ restoreTanks: (e, t) => {
2567
+ let n = !1;
2568
+ return _r(e).forEach(({ snapshot: r }) => {
2569
+ if (!r || t && r.gameId !== t || [
2570
+ "closed",
2571
+ "declined",
2572
+ "won",
2573
+ "draw"
2574
+ ].includes(r.status)) return;
2575
+ let i = Cr(e, r.roomId, r.gameId);
2576
+ if (c().games[i]) return;
2577
+ let a = ir(Kn({
2578
+ key: i,
2579
+ gameId: r.gameId,
2580
+ game_id: r.gameId,
2581
+ scope: e,
2582
+ roomId: r.roomId,
2583
+ ownId: r.ownId,
2584
+ hostId: r.hostId,
2585
+ guestId: r.guestId,
2586
+ createdAt: r.createdAt,
2587
+ inviteEventId: r.inviteEventId,
2588
+ lastEventId: r.inviteEventId,
2589
+ seen: {},
2590
+ sync: { ...Dr }
2591
+ }, {
2592
+ seed_commit: r.seedCommit,
2593
+ first_player_id: r.firstPlayerId,
2594
+ rematch_of: r.rematchOf ?? void 0
2595
+ }), r);
2596
+ if (!a) return;
2597
+ n = !0;
2598
+ let o = {
2599
+ ...a,
2600
+ seen: or({ [r.inviteEventId]: !0 }, a),
2601
+ status: "conflict",
2602
+ error: "Partida recuperada en este dispositivo. Sincronizando con el rival…"
2603
+ };
2604
+ s((e) => ({ games: wr({
2605
+ ...e.games,
2606
+ [i]: o
2607
+ }) })), queueMicrotask(() => {
2608
+ c().requestResync(i, { auto: !0 });
2609
+ });
2610
+ }), n;
2611
+ },
2612
+ sendEvent: async (t, n) => {
2613
+ if (!e) throw Error("Chat no disponible");
2614
+ let r = e, i = r.getScope(), a = String(r.getUserId() ?? ""), o = Cr(i, t, n.game_id), l = be(n);
2615
+ if (c().ingest({
2616
+ room_id: t,
2617
+ user_id: a,
2618
+ message: l
2619
+ }, i, a), !c().games[o]?.seen[n.event_id]) throw Error("Evento de partida inválido");
2620
+ let u = (e, t = !0) => s((r) => {
2621
+ let i = r.games[o];
2622
+ return !i || t && i.pendingEvent?.event_id !== n.event_id ? r : { games: {
2623
+ ...r.games,
2624
+ [o]: {
2625
+ ...i,
2626
+ ...e
2627
+ }
2628
+ } };
2629
+ });
2630
+ u({
2631
+ pending: !0,
2632
+ pendingEvent: n,
2633
+ error: ""
2634
+ }, !1);
2635
+ try {
2636
+ await r.send(t, l), u({
2637
+ pending: !1,
2638
+ pendingEvent: null
2639
+ }), c().afterGameChange(o);
2640
+ } catch (e) {
2641
+ throw u({
2642
+ pending: !1,
2643
+ error: e.message || "No se pudo enviar. Reintenta el mismo evento."
2644
+ }), e;
2645
+ }
2646
+ return o;
2647
+ },
2648
+ handleResync: (e, t, n, r) => {
2649
+ let i = c().games[e], a = p(i), o = {
2650
+ ...i.seen,
2651
+ [t.event_id]: !0
2652
+ }, l = (t) => {
2653
+ s((n) => ({ games: {
2654
+ ...n.games,
2655
+ [e]: t
2656
+ } })), c().afterGameChange(e);
2657
+ };
2658
+ if (n === r || ![i.hostId, i.guestId].includes(n) || ["closed", "declined"].includes(i.status)) {
2659
+ l({
2660
+ ...i,
2661
+ seen: o
2662
+ });
2663
+ return;
2664
+ }
2665
+ let u = {
2666
+ ...Dr,
2667
+ ...i.sync
2668
+ };
2669
+ if (![a.requestType, a.stateType].includes(t.type)) {
2670
+ l({
2671
+ ...i,
2672
+ seen: o
2673
+ });
2674
+ return;
2675
+ }
2676
+ let d = t.type === a.stateType;
2677
+ if (d && !u.outgoing.includes(t.data.request_event_id)) {
2678
+ l({
2679
+ ...i,
2680
+ seen: o
2681
+ });
2682
+ return;
2683
+ }
2684
+ let f = a.rebuild(i, t.data);
2685
+ if (!f) {
2686
+ l({
2687
+ ...i,
2688
+ seen: o,
2689
+ sync: d ? {
2690
+ ...u,
2691
+ status: "failed",
2692
+ message: "El rival envió un estado de partida inválido."
2693
+ } : u
2694
+ });
2695
+ return;
2696
+ }
2697
+ let m = a.compare(i, t.data), h = {
2698
+ ...u,
2699
+ status: "ok",
2700
+ offer: null,
2701
+ auto: !1,
2702
+ message: ""
2703
+ }, g, _ = !d, v = !1, y = m === "mixed" ? a.merge(i, t.data) : null;
2704
+ if (m === "equal" || m === "behind") g = {
2705
+ ...f,
2706
+ sync: h
2707
+ }, a.covers(i, t.data) && (g = {
2708
+ ...g,
2709
+ pendingEvent: null
2710
+ });
2711
+ else if (y) {
2712
+ let e = a.rebuild(i, y);
2713
+ g = e ? {
2714
+ ...e,
2715
+ sync: h
2716
+ } : {
2717
+ ...i,
2718
+ sync: {
2719
+ ...u,
2720
+ status: "failed",
2721
+ message: "No se pudo reconstruir la partida local."
2722
+ }
2723
+ }, _ = !!e, v = !!e;
2724
+ } else if (m === "ahead" || n === i.guestId) {
2725
+ let e = a.rebuild(i, a.historyOf(i));
2726
+ g = e ? {
2727
+ ...e,
2728
+ sync: h
2729
+ } : {
2730
+ ...i,
2731
+ sync: {
2732
+ ...u,
2733
+ status: "failed",
2734
+ message: "No se pudo reconstruir la partida local."
2735
+ }
2736
+ }, _ = !!e, v = !!e;
2737
+ } else g = {
2738
+ ...i,
2739
+ status: "conflict",
2740
+ error: "El anfitrión tiene otra versión de la partida. Revísala antes de aceptarla.",
2741
+ sync: {
2742
+ ...u,
2743
+ status: "incompatible",
2744
+ offer: a.offerOf(t.data),
2745
+ message: ""
2746
+ }
2747
+ };
2748
+ g = {
2749
+ ...g,
2750
+ seen: a.markSeen(o, g)
2751
+ };
2752
+ let b = Date.now(), x = g.sync.replies.filter((e) => b - e < 3e4), S = null;
2753
+ if (_ && x.length < 6) try {
2754
+ S = Lr(i, a.stateType, {
2755
+ ...a.historyOf(g),
2756
+ request_event_id: t.event_id
2757
+ });
2758
+ } catch {
2759
+ S = null;
2760
+ }
2761
+ S && (g = {
2762
+ ...g,
2763
+ seen: {
2764
+ ...g.seen,
2765
+ [S.event_id]: !0
2766
+ },
2767
+ sync: {
2768
+ ...g.sync,
2769
+ replies: [...x, b],
2770
+ outgoing: [...g.sync.outgoing, S.event_id].slice(-8)
2771
+ }
2772
+ }), l(g), S && c().sendResync(e, S).then(() => {
2773
+ v && (s((t) => {
2774
+ let n = t.games[e];
2775
+ return !n || !p(n).covers(n, p(n).historyOf(n)) ? t : { games: {
2776
+ ...t.games,
2777
+ [e]: {
2778
+ ...n,
2779
+ pendingEvent: null,
2780
+ error: ""
2781
+ }
2782
+ } };
2783
+ }), c().afterGameChange(e));
2784
+ }).catch(() => {});
2785
+ },
2786
+ sendResync: async (t, n) => {
2787
+ let r = c().games[t];
2788
+ if (!e || !r || r.scope !== e.getScope?.()) throw Error("Chat no disponible");
2789
+ await e.send(r.roomId, be(n));
2790
+ },
2791
+ requestResync: async (t, { auto: n = !1 } = {}) => {
2792
+ let r = c().games[t];
2793
+ if (!r || !e || ["closed", "declined"].includes(r.status) || r.scope !== e.getScope?.()) return;
2794
+ let i = {
2795
+ ...Dr,
2796
+ ...r.sync
2797
+ };
2798
+ if (i.status === "requesting" && Date.now() - i.requestedAt < Er || n && i.auto) return;
2799
+ let a;
2800
+ try {
2801
+ a = Lr(r, p(r).requestType, p(r).historyOf(r));
2802
+ } catch {
2803
+ return;
2804
+ }
2805
+ let l = (e) => s((n) => {
2806
+ let r = n.games[t];
2807
+ return r?.sync?.requestId !== a.event_id || r.sync.status !== "requesting" ? n : { games: {
2808
+ ...n.games,
2809
+ [t]: {
2810
+ ...r,
2811
+ sync: {
2812
+ ...r.sync,
2813
+ status: "failed",
2814
+ message: e
2815
+ }
2816
+ }
2817
+ } };
2818
+ });
2819
+ s((e) => {
2820
+ let r = e.games[t];
2821
+ return r ? { games: {
2822
+ ...e.games,
2823
+ [t]: {
2824
+ ...r,
2825
+ seen: {
2826
+ ...r.seen,
2827
+ [a.event_id]: !0
2828
+ },
2829
+ sync: {
2830
+ ...i,
2831
+ status: "requesting",
2832
+ requestId: a.event_id,
2833
+ requestedAt: Date.now(),
2834
+ auto: i.auto || n,
2835
+ message: "",
2836
+ outgoing: [...i.outgoing, a.event_id].slice(-8)
2837
+ }
2838
+ }
2839
+ } } : e;
2840
+ });
2841
+ let u = setTimeout(() => {
2842
+ o.delete(u), l("El rival no respondió a la sincronización. Reintenta cuando esté conectado.");
2843
+ }, Er);
2844
+ o.add(u);
2845
+ try {
2846
+ await c().sendResync(t, a);
2847
+ } catch (e) {
2848
+ l(e.message || "No se pudo enviar la solicitud de sincronización.");
2849
+ }
2850
+ },
2851
+ adoptResyncOffer: (e) => {
2852
+ let t = c().games[e], n = t?.sync?.offer;
2853
+ if (!n || t.sync.status !== "incompatible") return !1;
2854
+ let r = p(t), i = r.rebuild(t, n);
2855
+ return s((n) => ({ games: {
2856
+ ...n.games,
2857
+ [e]: i ? {
2858
+ ...i,
2859
+ seen: r.markSeen(t.seen, i),
2860
+ pending: !1,
2861
+ pendingEvent: null,
2862
+ sync: {
2863
+ ...t.sync,
2864
+ status: "ok",
2865
+ offer: null,
2866
+ auto: !1,
2867
+ message: ""
2868
+ }
2869
+ } : {
2870
+ ...t,
2871
+ sync: {
2872
+ ...t.sync,
2873
+ status: "failed",
2874
+ offer: null,
2875
+ message: "El estado del anfitrión ya no es válido."
2876
+ }
2877
+ }
2878
+ } })), i && c().afterGameChange(e), !!i;
2879
+ },
2880
+ resyncConflicts: (e) => {
2881
+ c().restoreTanks(e), Object.values(c().games).filter((t) => t.scope === e && t.status === "conflict").forEach((e) => {
2882
+ c().requestResync(e.key, { auto: !0 });
2883
+ });
2884
+ },
2885
+ retry: (t) => {
2886
+ let n = c().games[t];
2887
+ 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."));
2888
+ }
2889
+ }));
2890
+ }
2891
+ var zr = Rr(), Br = (e) => l(zr, e);
2892
+ Object.assign(Br, {
2893
+ getState: zr.getState,
2894
+ setState: zr.setState,
2895
+ subscribe: zr.subscribe
2896
+ });
2897
+ // src/assets/chatAssets.js
2898
+ var Vr = "/sounds", Hr = Vr, Ur = (e) => String(e).replace(/\/+$/, "");
2899
+ function Wr(e) {
2900
+ Hr = e == null ? Vr : Ur(e);
2901
+ }
2902
+ function Gr() {
2903
+ return Hr;
2904
+ }
2905
+ function Kr(e) {
2906
+ return `${Hr}/${String(e).replace(/^\/+/, "")}`;
2907
+ }
2908
+ // src/core/connection/connectionStore.js
2909
+ var qr = c(() => ({ status: "idle" }));
2910
+ function Jr(e) {
2911
+ qr.setState({ status: e });
2912
+ }
2913
+ function Yr() {
2914
+ return l(qr, (e) => e.status);
2915
+ }
2916
+ // src/games/shared/gameStatus.js
2917
+ var X = (e, t) => e != null && t != null && String(e) === String(t), Xr = (e) => [
2918
+ "won",
2919
+ "draw",
2920
+ "declined",
2921
+ "closed"
2922
+ ].includes(e?.status), Zr = (e) => !!e && ([
2923
+ "invited",
2924
+ "placement",
2925
+ "seeding",
2926
+ "active",
2927
+ "conflict"
2928
+ ].includes(e.status) || !!e.pendingEvent), Qr = (e) => e?.game === "battleship", $r = (e) => e?.game === "tanks", ei = {
2929
+ connect4: "Conecta 4",
2930
+ battleship: "Batalla Naval",
2931
+ tanks: "Tanques de guerra"
2932
+ }, ti = (e) => ei[e?.game] ?? "Conecta 4", ni = {
2933
+ ok: "Partida verificada",
2934
+ mismatch: "Resultados inconsistentes del rival",
2935
+ pending: "Verificando…"
2936
+ }, ri = (e) => ni[e?.verification] || "";
2937
+ function ii(e, t) {
2938
+ let n = X(t, e.turnId);
2939
+ 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" ? X(t, e.winnerId) ? "¡Ganaste!" : "Tu rival ganó" : null;
2940
+ }
2941
+ function ai(e, t) {
2942
+ if (e.status === "seeding") return "Preparando el campo de batalla…";
2943
+ if (e.status === "active") return X(t, e.turnId) ? "Tu turno · apunta y dispara" : "Turno del rival";
2944
+ if (e.status === "won") {
2945
+ let n = X(t, e.winnerId), r = e.logic?.reason;
2946
+ return r === "resign" ? n ? "¡Victoria! Tu rival se rindió" : "Te rendiste" : r === "timeout" ? n ? "¡Victoria! Tu rival dejó pasar sus turnos" : "Perdiste por inactividad" : r === "max_shots" ? n ? "¡Victoria por vida restante!" : "Tu rival terminó con más vida" : n ? "¡Victoria! Destruiste al rival" : "Tu tanque fue destruido";
2947
+ }
2948
+ return e.status === "draw" ? e.logic?.reason === "max_shots" ? "Empate · misma vida al agotar los disparos" : "Empate · ambos tanques destruidos" : null;
2949
+ }
2950
+ function oi(e, t) {
2951
+ if (Qr(e)) {
2952
+ let n = ii(e, t);
2953
+ if (n) return n;
2954
+ }
2955
+ if ($r(e)) {
2956
+ let n = ai(e, t);
2957
+ if (n) return n;
2958
+ }
2959
+ let n = e.status === "active" && X(t, e.turnId);
2960
+ return e.status === "invited" ? X(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" ? X(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";
2961
+ }
2962
+ function si(e, t) {
2963
+ if (Qr(e)) {
2964
+ if (e.status === "placement") return e.myReady ? "Esperando al rival" : "Coloca tu flota";
2965
+ if (e.status === "active" && e.pendingShot) return "Esperando resultado…";
2966
+ }
2967
+ return $r(e) && e.status === "seeding" ? "Preparando…" : e.status === "active" ? X(t, e.turnId) ? "Tu turno" : "Turno del rival" : e.status === "invited" ? X(t, e.guestId) ? "Invitación recibida" : "Invitación enviada" : e.status === "conflict" ? e.sync?.status === "requesting" ? "Sincronizando…" : "Sin sincronizar" : oi(e, t);
2968
+ }
2969
+ // src/audio/useSoundSettings.js
2970
+ function ci(e) {
2971
+ return s(e.subscribe, e.getSettings, e.getSettings);
2972
+ }
2973
+ // src/games/shared/GameSoundControls.jsx
2974
+ function li({ manager: e }) {
2975
+ let { volume: t, muted: n } = ci(e), r = n || t === 0;
2976
+ return /* @__PURE__ */ p("div", {
2977
+ className: "chat-game-sound",
2978
+ children: [/* @__PURE__ */ f("button", {
2979
+ type: "button",
2980
+ className: "chat-game-sound-toggle",
2981
+ onClick: e.toggleMuted,
2982
+ "aria-pressed": r,
2983
+ "aria-label": r ? "Activar sonido del juego" : "Silenciar sonido del juego",
2984
+ title: r ? "Activar sonido" : "Silenciar",
2985
+ children: f(r ? d : u, { size: 15 })
2986
+ }), /* @__PURE__ */ f("input", {
2987
+ type: "range",
2988
+ min: "0",
2989
+ max: "100",
2990
+ step: "5",
2991
+ value: Math.round((n ? 0 : t) * 100),
2992
+ onChange: (t) => e.setVolume(Number(t.target.value) / 100),
2993
+ "aria-label": "Volumen del juego"
2994
+ })]
2995
+ });
2996
+ }
2997
+ // src/audio/createSoundManager.js
2998
+ var ui = [
2999
+ "pointerdown",
3000
+ "keydown",
3001
+ "touchend"
3002
+ ], di = 300, fi = 800, pi = (e) => Math.min(1, Math.max(0, Number(e) || 0));
3003
+ function mi(e, t) {
3004
+ try {
3005
+ let n = JSON.parse(localStorage.getItem(e) ?? "null");
3006
+ if (n && typeof n == "object") return {
3007
+ volume: pi(n.volume ?? t.volume),
3008
+ muted: !!n.muted
3009
+ };
3010
+ } catch {}
3011
+ return {
3012
+ volume: pi(t.volume),
3013
+ muted: !1
3014
+ };
3015
+ }
3016
+ var hi = 1.5, gi = .6;
3017
+ function _i({ id: e, baseUrl: t, sounds: n, levels: r = {}, defaultVolume: i = .6, settingsFrom: a = null }) {
3018
+ let o = `lira.sound.${e}`, s = typeof window < "u" ? window.AudioContext || window.webkitAudioContext : null, c = a ? a.getSettings() : mi(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 = /* @__PURE__ */ new Map(), b = !1, x = !1, S = null, ee = (e) => `${String(typeof t == "function" ? t() : t).replace(/\/$/, "")}/${n[e]}`, te = (e) => (f.has(e) || f.set(e, fetch(ee(e)).then((e) => e.ok ? e.arrayBuffer() : null).catch(() => null)), f.get(e)), C = () => {
3019
+ if (!s) return null;
3020
+ if (!l) try {
3021
+ l = new s(), u = l.createGain(), u.gain.value = c.muted ? 0 : c.volume, u.connect(l.destination);
3022
+ } catch {
3023
+ return l = null, null;
3024
+ }
3025
+ return l.state === "suspended" && l.resume().catch(() => {}), l;
3026
+ }, w = (e) => {
3027
+ if (m.has(e) || !n[e]) return Promise.resolve(null);
3028
+ if (!p.has(e)) {
3029
+ let t = C();
3030
+ if (!t) return Promise.resolve(null);
3031
+ p.set(e, te(e).then((e) => e ? new Promise((n) => {
3032
+ t.decodeAudioData(e.slice(0), n, () => n(null))?.catch?.(() => n(null));
3033
+ }) : null).then((t) => (t || m.add(e), t)).catch(() => (m.add(e), null)));
3034
+ }
3035
+ return p.get(e);
3036
+ }, ne = (e) => pi(r[e] ?? 1), re = (e) => {
3037
+ if (!_.has(e) || v.has(e) || !d) return;
3038
+ let t = C();
3039
+ if (!t) return;
3040
+ let n = {};
3041
+ v.set(e, n), w(e).then((r) => {
3042
+ if (v.get(e) === n) {
3043
+ if (!r || t.state === "closed") v.delete(e);
3044
+ else try {
3045
+ let { fadeIn: n = hi, trim: i = 0 } = y.get(e) ?? {}, a = t.createGain();
3046
+ a.gain.setValueAtTime(0, t.currentTime), a.gain.linearRampToValueAtTime(ne(e), t.currentTime + n), a.connect(u);
3047
+ let o = t.createBufferSource();
3048
+ o.buffer = r, o.loop = !0, i > 0 && r.duration > i * 4 && (o.loopStart = i, o.loopEnd = r.duration - i), o.connect(a), o.start(0, i > 0 && r.duration > i * 4 ? i : 0), v.set(e, {
3049
+ source: o,
3050
+ level: a
3051
+ });
3052
+ } catch {
3053
+ v.delete(e);
3054
+ }
3055
+ }
3056
+ });
3057
+ }, ie = (e) => {
3058
+ let t = v.get(e);
3059
+ if (v.delete(e), t?.source && l) try {
3060
+ let n = y.get(e)?.fadeOut ?? gi, r = l.currentTime;
3061
+ t.level.gain.cancelScheduledValues(r), t.level.gain.setValueAtTime(t.level.gain.value, r), t.level.gain.linearRampToValueAtTime(0, r + n), t.source.stop(r + n + .05);
3062
+ } catch {}
3063
+ }, ae = () => {
3064
+ d || (d = !0, T(), C() && Object.keys(n).forEach((e) => {
3065
+ f.has(e) && w(e);
3066
+ }), _.forEach(re));
3067
+ };
3068
+ function T() {
3069
+ x && (x = !1, ui.forEach((e) => window.removeEventListener(e, ae, !0)));
3070
+ }
3071
+ let E = (e) => !h.has(e) && (h.add(e), h.size > di && h.delete(h.values().next().value), !0), D = () => g.forEach((e) => e()), oe = (e) => {
3072
+ c = e, u && (u.gain.value = c.muted ? 0 : c.volume), D();
3073
+ }, O = (e) => {
3074
+ let t = {
3075
+ volume: pi(e.volume ?? c.volume),
3076
+ muted: e.muted ?? c.muted
3077
+ };
3078
+ try {
3079
+ localStorage.setItem(o, JSON.stringify(t));
3080
+ } catch {}
3081
+ oe(t);
3082
+ }, k = () => {
3083
+ b || (b = !0, a && (c = a.getSettings(), S = a.subscribe(() => oe(a.getSettings()))), !(typeof window > "u" || d) && (typeof navigator < "u" && navigator.userActivation?.hasBeenActive ? d = !0 : (x = !0, ui.forEach((e) => window.addEventListener(e, ae, {
3084
+ capture: !0,
3085
+ passive: !0
3086
+ })))));
3087
+ };
3088
+ return {
3089
+ start: k,
3090
+ dispose: () => {
3091
+ T(), S && (S(), S = null), b = !1, _.clear(), v.forEach((e) => {
3092
+ try {
3093
+ e?.source?.stop();
3094
+ } catch {}
3095
+ }), v.clear(), p.clear();
3096
+ let e = l;
3097
+ l = null, u = null, e && e.state !== "closed" && e.close().catch(() => {});
3098
+ },
3099
+ preload(e = Object.keys(n)) {
3100
+ k(), e.forEach((e) => {
3101
+ n[e] && !m.has(e) && (te(e), l && w(e));
3102
+ });
3103
+ },
3104
+ play(e, { key: t } = {}) {
3105
+ if (k(), t != null && !E(`${e}:${t}`) || !n[e] || m.has(e) || !d || c.muted || c.volume === 0) return !1;
3106
+ let r = C();
3107
+ if (!r) return !1;
3108
+ let i = Date.now();
3109
+ return w(e).then((t) => {
3110
+ if (!(!t || r.state === "closed" || Date.now() - i > fi)) try {
3111
+ let n = r.createBufferSource();
3112
+ n.buffer = t;
3113
+ let i = ne(e);
3114
+ if (i === 1) n.connect(u);
3115
+ else {
3116
+ let e = r.createGain();
3117
+ e.gain.value = i, n.connect(e), e.connect(u);
3118
+ }
3119
+ n.start();
3120
+ } catch {}
3121
+ }), !0;
3122
+ },
3123
+ markPlayed(e, t) {
3124
+ E(`${e}:${t}`);
3125
+ },
3126
+ startLoop(e, t) {
3127
+ k(), n[e] && !m.has(e) && (t && y.set(e, t), _.add(e), re(e));
3128
+ },
3129
+ stopLoop(e) {
3130
+ _.delete(e), ie(e);
3131
+ },
3132
+ getSettings: () => a && !b ? a.getSettings() : c,
3133
+ setVolume: a ? a.setVolume : (e) => O({
3134
+ volume: e,
3135
+ muted: pi(e) === 0 && c.muted
3136
+ }),
3137
+ setMuted: a ? a.setMuted : (e) => O({ muted: !!e }),
3138
+ toggleMuted: a ? a.toggleMuted : () => O({ muted: !c.muted }),
3139
+ subscribe(e) {
3140
+ return k(), g.add(e), () => g.delete(e);
3141
+ }
3142
+ };
3143
+ }
3144
+ // src/games/connect4/connect4Sounds.js
3145
+ var Z = _i({
3146
+ id: "connect4",
3147
+ baseUrl: () => Kr("connect4"),
3148
+ sounds: {
3149
+ invite: "invite.ogg",
3150
+ start: "start.ogg",
3151
+ drop: "drop.ogg",
3152
+ turn: "turn.ogg",
3153
+ win: "win.ogg",
3154
+ lose: "lose.ogg",
3155
+ draw: "draw.ogg",
3156
+ close: "close.ogg"
3157
+ }
3158
+ }), vi = 140, Q = /* @__PURE__ */ new Map(), yi = /* @__PURE__ */ new Set(), $ = null, bi = (e, t) => e != null && t != null && String(e) === String(t), xi = () => typeof window < "u" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
3159
+ function Si(e, t) {
3160
+ e.status === "won" ? Z.play(bi(e.winnerId, e.ownId) ? "win" : "lose", { key: t }) : e.status === "draw" ? Z.play("draw", { key: t }) : e.status === "active" && bi(e.turnId, e.ownId) && Z.play("turn", { key: t });
3161
+ }
3162
+ function Ci(e) {
3163
+ let t = Q.get(e);
3164
+ if (!t) return;
3165
+ clearTimeout(t.timer), Q.delete(e), Z.play("drop", { key: e });
3166
+ let n = setTimeout(() => {
3167
+ yi.delete(n), Si(t.game, e);
3168
+ }, vi);
3169
+ yi.add(n);
3170
+ }
3171
+ function wi(e) {
3172
+ let t = e.lastMove?.eventId;
3173
+ if (!t || Q.has(t)) return;
3174
+ let n = xi() ? 0 : 440;
3175
+ Q.set(t, {
3176
+ game: e,
3177
+ timer: setTimeout(() => Ci(t), n)
3178
+ });
3179
+ }
3180
+ function Ti(e, t) {
3181
+ t ? t.status === "invited" && e.status === "active" ? Z.play("start", { key: e.lastEventId }) : e.ply > t.ply ? wi(e) : (e.status === "closed" && e.closedBy != null || e.status === "declined") && t.status !== e.status && Z.play("close", { key: e.gameId }) : e.status === "invited" && bi(e.guestId, e.ownId) && Z.play("invite", { key: e.inviteEventId });
3182
+ }
3183
+ var Ei = () => $ != null;
3184
+ function Di() {
3185
+ if ($) return $;
3186
+ Z.start();
3187
+ let e = Br.subscribe((e, t) => {
3188
+ e.games !== t.games && Object.entries(e.games).forEach(([e, n]) => {
3189
+ let r = t.games[e];
3190
+ n.game && n.game !== "connect4" || n !== r && n.ownId != null && Ti(n, r);
3191
+ });
3192
+ }), t = () => {
3193
+ $ === t && ($ = null, e(), Q.forEach(({ timer: e }) => clearTimeout(e)), Q.clear(), yi.forEach(clearTimeout), yi.clear());
3194
+ };
3195
+ return $ = t, t;
3196
+ }
3197
+ export { Bt as A, Br as C, an as D, vn as E, re as M, me as N, L as O, zr as S, gn as T, Jr as _, _i as a, Gr as b, ti as c, Qr as d, Zr as f, qr as g, X as h, Di as i, P as j, Jt as k, si as l, Xr as m, Ei as n, li as o, $r as p, Ci as r, oi as s, Z as t, ri as u, Yr as v, Jn as w, Wr as x, Kr as y };
3198
+
3199
+ //# sourceMappingURL=connect4Sounds-BDXQAvU1.js.map