@minicode-dev/chat 0.1.6 → 0.1.8

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