@minicode-dev/chat 0.1.13 → 0.1.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +112 -5
- package/README.md +401 -312
- package/assets/sounds/effects/avalanche.mp3 +0 -0
- package/assets/sounds/racing/car_boost.mp3 +0 -0
- package/assets/sounds/racing/car_boost.ogg +0 -0
- package/assets/sounds/racing/car_bump.mp3 +0 -0
- package/assets/sounds/racing/car_bump.ogg +0 -0
- package/assets/sounds/racing/car_drift_loop.mp3 +0 -0
- package/assets/sounds/racing/car_drift_loop.ogg +0 -0
- package/assets/sounds/racing/car_engine_loop.mp3 +0 -0
- package/assets/sounds/racing/car_engine_loop.ogg +0 -0
- package/assets/sounds/racing/car_engine_start.mp3 +0 -0
- package/assets/sounds/racing/car_engine_start.ogg +0 -0
- package/assets/sounds/racing/countdown_beep.mp3 +0 -0
- package/assets/sounds/racing/countdown_beep.ogg +0 -0
- package/assets/sounds/racing/countdown_go.mp3 +0 -0
- package/assets/sounds/racing/countdown_go.ogg +0 -0
- package/assets/sounds/racing/final_lap.mp3 +0 -0
- package/assets/sounds/racing/final_lap.ogg +0 -0
- package/assets/sounds/racing/finish_line.mp3 +0 -0
- package/assets/sounds/racing/finish_line.ogg +0 -0
- package/assets/sounds/racing/lap_complete.mp3 +0 -0
- package/assets/sounds/racing/lap_complete.ogg +0 -0
- package/assets/sounds/racing/music_circuit.mp3 +0 -0
- package/assets/sounds/racing/music_circuit.ogg +0 -0
- package/assets/sounds/racing/music_final_lap.mp3 +0 -0
- package/assets/sounds/racing/music_final_lap.ogg +0 -0
- package/assets/sounds/racing/race_defeat.mp3 +0 -0
- package/assets/sounds/racing/race_defeat.ogg +0 -0
- package/assets/sounds/racing/race_victory.mp3 +0 -0
- package/assets/sounds/racing/race_victory.ogg +0 -0
- package/assets/sounds/tanks/barrel_explode.mp3 +0 -0
- package/assets/sounds/tanks/barrel_explode.ogg +0 -0
- package/assets/sounds/tanks/crate_break.mp3 +0 -0
- package/assets/sounds/tanks/crate_break.ogg +0 -0
- package/assets/sounds/tanks/health_pickup.mp3 +0 -0
- package/assets/sounds/tanks/health_pickup.ogg +0 -0
- package/assets/sounds/tanks/last_life.mp3 +0 -0
- package/assets/sounds/tanks/last_life.ogg +0 -0
- package/assets/sounds/tanks/life_lost.mp3 +0 -0
- package/assets/sounds/tanks/life_lost.ogg +0 -0
- package/assets/sounds/tanks/respawn.mp3 +0 -0
- package/assets/sounds/tanks/respawn.ogg +0 -0
- package/assets/sounds/tanks/shield_end.mp3 +0 -0
- package/assets/sounds/tanks/shield_end.ogg +0 -0
- package/assets/sounds/tanks/shield_loop.mp3 +0 -0
- package/assets/sounds/tanks/shield_loop.ogg +0 -0
- package/assets/sounds/tanks/wall_hit.mp3 +0 -0
- package/assets/sounds/tanks/wall_hit.ogg +0 -0
- package/dist/chunks/{BattleshipGameCard-iRk8d4vR.js → BattleshipGameCard-B-B4r7lK.js} +146 -144
- package/dist/chunks/{BattleshipGameCard-iRk8d4vR.js.map → BattleshipGameCard-B-B4r7lK.js.map} +1 -1
- package/dist/chunks/{ChatContext-DjIEifGY.js → ChatContext-DQtKsR6Z.js} +2 -2
- package/dist/chunks/{ChatContext-DjIEifGY.js.map → ChatContext-DQtKsR6Z.js.map} +1 -1
- package/dist/chunks/RacingLiveGameCard-c1G7uoDI.js +1654 -0
- package/dist/chunks/RacingLiveGameCard-c1G7uoDI.js.map +1 -0
- package/dist/chunks/{TanksGameCard-GrqmdwJ7.js → TanksGameCard-CvTaF7tu.js} +164 -162
- package/dist/chunks/{TanksGameCard-GrqmdwJ7.js.map → TanksGameCard-CvTaF7tu.js.map} +1 -1
- package/dist/chunks/TanksLiveGameCard-COr9Oay5.js +1011 -0
- package/dist/chunks/TanksLiveGameCard-COr9Oay5.js.map +1 -0
- package/dist/chunks/avalancheScene3d-Z5QyZIid.js +1299 -0
- package/dist/chunks/avalancheScene3d-Z5QyZIid.js.map +1 -0
- package/dist/chunks/connect4Sounds-DmD-E9kX.js +235 -0
- package/dist/chunks/connect4Sounds-DmD-E9kX.js.map +1 -0
- package/dist/chunks/connectionStore-DwgIUl30.js +13 -0
- package/dist/chunks/connectionStore-DwgIUl30.js.map +1 -0
- package/dist/chunks/createLiveScene-CWBunxPi.js +367 -0
- package/dist/chunks/{createLiveScene-819NWv84.js.map → createLiveScene-CWBunxPi.js.map} +1 -1
- package/dist/chunks/createRaceScene-C7Rw89kj.js +305 -0
- package/dist/chunks/createRaceScene-C7Rw89kj.js.map +1 -0
- package/dist/chunks/{createTankScene-6asWHKFf.js → createTankScene-yhX6la27.js} +125 -123
- package/dist/chunks/{createTankScene-6asWHKFf.js.map → createTankScene-yhX6la27.js.map} +1 -1
- package/dist/chunks/decor-CyyCnmct.js +418 -0
- package/dist/chunks/decor-CyyCnmct.js.map +1 -0
- package/dist/chunks/fx-1ZwzmPWj.js +458 -0
- package/dist/chunks/fx-1ZwzmPWj.js.map +1 -0
- package/dist/chunks/fx-UZwhOmdl.js +584 -0
- package/dist/chunks/fx-UZwhOmdl.js.map +1 -0
- package/dist/chunks/gameStatus-BChd29yI.js +62 -0
- package/dist/chunks/gameStatus-BChd29yI.js.map +1 -0
- package/dist/chunks/{connect4Sounds-Cv0q31VW.js → games-BvYTWgaR.js} +814 -951
- package/dist/chunks/games-BvYTWgaR.js.map +1 -0
- package/dist/chunks/rolldown-runtime-CGnMp29N.js +10 -0
- package/dist/chunks/tank-DjEQ4FXF.js +553 -0
- package/dist/chunks/tank-DjEQ4FXF.js.map +1 -0
- package/dist/chunks/tanks-live-BcKmrhnV.js +261 -0
- package/dist/chunks/tanks-live-BcKmrhnV.js.map +1 -0
- package/dist/chunks/{tanksSounds-CUNDIOal.js → tanksSounds-DwjfSp3W.js} +43 -11
- package/dist/chunks/tanksSounds-DwjfSp3W.js.map +1 -0
- package/dist/chunks/track-BcnnpnAm.js +259 -0
- package/dist/chunks/track-BcnnpnAm.js.map +1 -0
- package/dist/chunks/util-DwI9bfS7.js +57 -0
- package/dist/chunks/util-DwI9bfS7.js.map +1 -0
- package/dist/index.js +812 -625
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/index.d.ts +3 -1
- package/package.json +1 -1
- package/dist/chunks/TanksLiveGameCard-DSmQcUMh.js +0 -1225
- package/dist/chunks/TanksLiveGameCard-DSmQcUMh.js.map +0 -1
- package/dist/chunks/avalancheScene3d-Dnl2E3EA.js +0 -1878
- package/dist/chunks/avalancheScene3d-Dnl2E3EA.js.map +0 -1
- package/dist/chunks/connect4Sounds-Cv0q31VW.js.map +0 -1
- package/dist/chunks/createLiveScene-819NWv84.js +0 -365
- package/dist/chunks/fx-BNJvJYOu.js +0 -871
- package/dist/chunks/fx-BNJvJYOu.js.map +0 -1
- package/dist/chunks/gameStatus-Cu1Z8un9.js +0 -69
- package/dist/chunks/gameStatus-Cu1Z8un9.js.map +0 -1
- package/dist/chunks/tank-DIn6Jyt8.js +0 -605
- package/dist/chunks/tank-DIn6Jyt8.js.map +0 -1
- package/dist/chunks/tanksSounds-CUNDIOal.js.map +0 -1
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { r as e } from "./createPeerLink-DBVs_yvQ.js";
|
|
2
|
+
import { useEffect as t, useId as n, useRef as r, useState as i } from "react";
|
|
3
|
+
import { CheckCircle2 as a, Link2 as o, Loader2 as s, ShieldCheck as c, X as l } from "lucide-react";
|
|
4
|
+
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
5
|
+
// src/games/tanks-live/ManualTurnDialog.jsx
|
|
6
|
+
var f = "{\n \"iceServers\": [{\n \"urls\": [\"turn:turn.cloudflare.com:3478?transport=udp\"],\n \"username\": \"usuario-temporal\",\n \"credential\": \"credencial-temporal\"\n }]\n}";
|
|
7
|
+
function p({ open: p, onClose: m, onApply: h, manualTurn: g }) {
|
|
8
|
+
let _ = r(null), v = r(0), y = n(), b = n(), x = n(), [S, C] = i(""), [w, T] = i(""), [E, D] = i(!1), [O, k] = i(""), [A, j] = i(!1), [M, N] = i(!1);
|
|
9
|
+
t(() => {
|
|
10
|
+
let e = _.current;
|
|
11
|
+
if (!p) {
|
|
12
|
+
v.current += 1, C(""), T(""), D(!1), k(""), j(!1), N(!1), e?.open && e.close();
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
let t = document.activeElement;
|
|
16
|
+
return e.showModal(), () => {
|
|
17
|
+
v.current += 1, e.open && e.close(), t instanceof HTMLElement && t.isConnected && t.focus({ preventScroll: !0 });
|
|
18
|
+
};
|
|
19
|
+
}, [p]);
|
|
20
|
+
let P = async (t) => {
|
|
21
|
+
if (t.preventDefault(), A || !S.trim()) return;
|
|
22
|
+
k("");
|
|
23
|
+
let n = {
|
|
24
|
+
iceTransportPolicy: E ? "relay" : "all",
|
|
25
|
+
...w.trim() ? { ttlSeconds: Number(w) } : {}
|
|
26
|
+
};
|
|
27
|
+
try {
|
|
28
|
+
e(S, n);
|
|
29
|
+
} catch (e) {
|
|
30
|
+
k(e.message);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
let r = ++v.current;
|
|
34
|
+
j(!0), N(!1);
|
|
35
|
+
try {
|
|
36
|
+
if (await h(S, n), r !== v.current) return;
|
|
37
|
+
C(""), T(""), N(!0);
|
|
38
|
+
} catch (e) {
|
|
39
|
+
r === v.current && k(e.message || "No se pudo compartir la configuración. Inténtalo de nuevo.");
|
|
40
|
+
} finally {
|
|
41
|
+
r === v.current && j(!1);
|
|
42
|
+
}
|
|
43
|
+
}, F = g?.status === "applying" ? "Aplicando configuración en ambos jugadores…" : g?.status === "waiting_peer" ? "Esperando al otro jugador para compartir la configuración…" : "Sincronizando con el otro jugador…";
|
|
44
|
+
return /* @__PURE__ */ d("dialog", {
|
|
45
|
+
ref: _,
|
|
46
|
+
className: "tl-turn-dialog",
|
|
47
|
+
"aria-labelledby": y,
|
|
48
|
+
"aria-describedby": b,
|
|
49
|
+
onCancel: (e) => {
|
|
50
|
+
e.preventDefault(), m();
|
|
51
|
+
},
|
|
52
|
+
onClick: (e) => {
|
|
53
|
+
if (e.target === e.currentTarget) {
|
|
54
|
+
let t = e.currentTarget.getBoundingClientRect();
|
|
55
|
+
(e.clientX < t.left || e.clientX > t.right || e.clientY < t.top || e.clientY > t.bottom) && m();
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
children: [/* @__PURE__ */ d("header", {
|
|
59
|
+
className: "tl-turn-dialog__header",
|
|
60
|
+
children: [
|
|
61
|
+
/* @__PURE__ */ u("span", {
|
|
62
|
+
className: "tl-turn-dialog__icon",
|
|
63
|
+
"aria-hidden": "true",
|
|
64
|
+
children: /* @__PURE__ */ u(o, { size: 22 })
|
|
65
|
+
}),
|
|
66
|
+
/* @__PURE__ */ d("div", { children: [/* @__PURE__ */ u("h2", {
|
|
67
|
+
id: y,
|
|
68
|
+
children: "Configurar conexión alternativa"
|
|
69
|
+
}), /* @__PURE__ */ u("p", { children: "Se comparte con el otro jugador." })] }),
|
|
70
|
+
/* @__PURE__ */ u("button", {
|
|
71
|
+
type: "button",
|
|
72
|
+
className: "tl-turn-dialog__close",
|
|
73
|
+
"aria-label": "Cerrar configuración de conexión",
|
|
74
|
+
onClick: m,
|
|
75
|
+
children: /* @__PURE__ */ u(l, { size: 18 })
|
|
76
|
+
})
|
|
77
|
+
]
|
|
78
|
+
}), /* @__PURE__ */ d("form", {
|
|
79
|
+
onSubmit: P,
|
|
80
|
+
children: [/* @__PURE__ */ d("div", {
|
|
81
|
+
className: "tl-turn-dialog__body",
|
|
82
|
+
children: [
|
|
83
|
+
/* @__PURE__ */ u("p", {
|
|
84
|
+
id: b,
|
|
85
|
+
children: "Pega el JSON de credenciales temporales de Cloudflare TURN. Se compartirá con el otro jugador para buscar una conexión alternativa."
|
|
86
|
+
}),
|
|
87
|
+
/* @__PURE__ */ d("label", {
|
|
88
|
+
className: "tl-turn-dialog__field",
|
|
89
|
+
children: ["Configuración JSON", /* @__PURE__ */ u("textarea", {
|
|
90
|
+
autoFocus: !0,
|
|
91
|
+
value: S,
|
|
92
|
+
onChange: (e) => {
|
|
93
|
+
C(e.target.value), k(""), N(!1);
|
|
94
|
+
},
|
|
95
|
+
placeholder: f,
|
|
96
|
+
maxLength: 6e3,
|
|
97
|
+
rows: 7,
|
|
98
|
+
required: !M,
|
|
99
|
+
readOnly: A,
|
|
100
|
+
autoComplete: "off",
|
|
101
|
+
autoCorrect: "off",
|
|
102
|
+
autoCapitalize: "off",
|
|
103
|
+
spellCheck: !1,
|
|
104
|
+
"aria-invalid": !!O,
|
|
105
|
+
"aria-describedby": O ? x : void 0
|
|
106
|
+
})]
|
|
107
|
+
}),
|
|
108
|
+
/* @__PURE__ */ d("div", {
|
|
109
|
+
className: "tl-turn-dialog__privacy",
|
|
110
|
+
children: [/* @__PURE__ */ u(c, {
|
|
111
|
+
size: 16,
|
|
112
|
+
"aria-hidden": "true"
|
|
113
|
+
}), /* @__PURE__ */ u("span", { children: "Solo credenciales temporales. No pegues tu API Token ni secretos permanentes." })]
|
|
114
|
+
}),
|
|
115
|
+
/* @__PURE__ */ d("label", {
|
|
116
|
+
className: "tl-turn-dialog__field",
|
|
117
|
+
children: [
|
|
118
|
+
"Validez restante en segundos ",
|
|
119
|
+
/* @__PURE__ */ u("span", {
|
|
120
|
+
className: "tl-turn-dialog__optional",
|
|
121
|
+
children: "Opcional"
|
|
122
|
+
}),
|
|
123
|
+
/* @__PURE__ */ u("input", {
|
|
124
|
+
type: "number",
|
|
125
|
+
min: "1",
|
|
126
|
+
max: "172800",
|
|
127
|
+
step: "1",
|
|
128
|
+
inputMode: "numeric",
|
|
129
|
+
value: w,
|
|
130
|
+
onChange: (e) => {
|
|
131
|
+
T(e.target.value), k("");
|
|
132
|
+
},
|
|
133
|
+
disabled: A,
|
|
134
|
+
placeholder: "Ej. 3600"
|
|
135
|
+
}),
|
|
136
|
+
/* @__PURE__ */ u("small", { children: "Déjalo vacío si no conoces la caducidad. Si dejan de funcionar, pega credenciales nuevas." })
|
|
137
|
+
]
|
|
138
|
+
}),
|
|
139
|
+
/* @__PURE__ */ d("label", {
|
|
140
|
+
className: "tl-turn-dialog__debug",
|
|
141
|
+
children: [/* @__PURE__ */ u("input", {
|
|
142
|
+
type: "checkbox",
|
|
143
|
+
checked: E,
|
|
144
|
+
onChange: (e) => D(e.target.checked),
|
|
145
|
+
disabled: A
|
|
146
|
+
}), /* @__PURE__ */ d("span", { children: [/* @__PURE__ */ u("strong", { children: "Forzar relay para diagnóstico" }), /* @__PURE__ */ u("small", { children: "Normalmente se permite P2P. Actívalo solo para comprobar TURN." })] })]
|
|
147
|
+
}),
|
|
148
|
+
A && /* @__PURE__ */ d("p", {
|
|
149
|
+
className: "tl-turn-dialog__feedback",
|
|
150
|
+
role: "status",
|
|
151
|
+
children: [/* @__PURE__ */ u(s, {
|
|
152
|
+
size: 16,
|
|
153
|
+
className: "tl-connection-spinner",
|
|
154
|
+
"aria-hidden": "true"
|
|
155
|
+
}), F]
|
|
156
|
+
}),
|
|
157
|
+
M && /* @__PURE__ */ d("p", {
|
|
158
|
+
className: "tl-turn-dialog__feedback tl-turn-dialog__feedback--success",
|
|
159
|
+
role: "status",
|
|
160
|
+
children: [/* @__PURE__ */ u(a, {
|
|
161
|
+
size: 17,
|
|
162
|
+
"aria-hidden": "true"
|
|
163
|
+
}), "Configuración compartida y aplicada en ambos jugadores. La ruta utilizada se mostrará al conectar."]
|
|
164
|
+
}),
|
|
165
|
+
O && /* @__PURE__ */ u("p", {
|
|
166
|
+
id: x,
|
|
167
|
+
className: "tl-turn-dialog__error",
|
|
168
|
+
role: "alert",
|
|
169
|
+
children: O
|
|
170
|
+
})
|
|
171
|
+
]
|
|
172
|
+
}), /* @__PURE__ */ d("footer", {
|
|
173
|
+
className: "tl-turn-dialog__footer",
|
|
174
|
+
children: [/* @__PURE__ */ u("button", {
|
|
175
|
+
type: "button",
|
|
176
|
+
onClick: m,
|
|
177
|
+
children: M ? "Listo" : "Cancelar"
|
|
178
|
+
}), /* @__PURE__ */ d("button", {
|
|
179
|
+
type: "submit",
|
|
180
|
+
className: "tl-turn-dialog__apply",
|
|
181
|
+
disabled: A || !S.trim(),
|
|
182
|
+
children: [A ? /* @__PURE__ */ u(s, {
|
|
183
|
+
size: 16,
|
|
184
|
+
className: "tl-connection-spinner",
|
|
185
|
+
"aria-hidden": "true"
|
|
186
|
+
}) : /* @__PURE__ */ u(o, {
|
|
187
|
+
size: 16,
|
|
188
|
+
"aria-hidden": "true"
|
|
189
|
+
}), "Aplicar y reconectar"]
|
|
190
|
+
})]
|
|
191
|
+
})]
|
|
192
|
+
})]
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
// src/games/tanks-live/net/connectionDiagnostics.js
|
|
196
|
+
var m = (e) => typeof e == "string" && /^[a-z_]+$/.test(e) ? e : e ? "connection_error" : null;
|
|
197
|
+
function h(e = {}) {
|
|
198
|
+
let t = e.route, n = e.candidates ?? {}, r = e.manualTurn ?? {};
|
|
199
|
+
return {
|
|
200
|
+
phase: e.phase ?? "idle",
|
|
201
|
+
ice: e.ice ?? "new",
|
|
202
|
+
connection: e.connection ?? "new",
|
|
203
|
+
signalingState: e.signalingState ?? "stable",
|
|
204
|
+
gathering: e.gathering ?? "new",
|
|
205
|
+
signaling: {
|
|
206
|
+
sent: e.signals?.sent ?? 0,
|
|
207
|
+
received: e.signals?.received ?? 0,
|
|
208
|
+
sendFailures: e.signals?.sendFailures ?? 0,
|
|
209
|
+
ignored: e.signals?.ignored ?? 0,
|
|
210
|
+
invalid: e.signals?.invalid ?? 0,
|
|
211
|
+
retransmits: e.signals?.retransmits ?? 0,
|
|
212
|
+
duplicates: e.signals?.duplicates ?? 0,
|
|
213
|
+
tooLarge: e.signals?.tooLarge ?? 0
|
|
214
|
+
},
|
|
215
|
+
turnConfigured: !!e.turnConfigured,
|
|
216
|
+
configuration: {
|
|
217
|
+
status: r.status ?? "idle",
|
|
218
|
+
shared: !!r.shared,
|
|
219
|
+
received: !!r.received,
|
|
220
|
+
expiresAt: r.expiresAt ?? null,
|
|
221
|
+
expired: r.expiresAt != null && r.expiresAt <= Date.now()
|
|
222
|
+
},
|
|
223
|
+
route: t?.label ?? null,
|
|
224
|
+
selectedPair: t ? {
|
|
225
|
+
relay: !!t.relay,
|
|
226
|
+
localType: t.local ?? null,
|
|
227
|
+
remoteType: t.remote ?? null,
|
|
228
|
+
protocol: t.protocol ?? null,
|
|
229
|
+
relayProtocol: t.relayProtocol ?? null
|
|
230
|
+
} : null,
|
|
231
|
+
candidates: {
|
|
232
|
+
local: n.local ?? 0,
|
|
233
|
+
remote: n.remote ?? 0,
|
|
234
|
+
accepted: n.accepted ?? 0,
|
|
235
|
+
rejected: n.rejected ?? 0,
|
|
236
|
+
localRelay: n.localRelay ?? 0,
|
|
237
|
+
remoteRelay: n.remoteRelay ?? 0
|
|
238
|
+
},
|
|
239
|
+
iceErrors: (e.iceErrors ?? []).slice(-10).map((e) => ({
|
|
240
|
+
code: Number(e.code) || 0,
|
|
241
|
+
stage: e.stage === "gathering" ? "gathering" : "remote_candidate"
|
|
242
|
+
})),
|
|
243
|
+
reconnects: e.reconnects ?? 0,
|
|
244
|
+
restarts: e.restarts ?? 0,
|
|
245
|
+
rttMs: e.rtt ?? e.statsRtt ?? null,
|
|
246
|
+
connectionTimeMs: e.elapsedMs ?? 0,
|
|
247
|
+
channels: {
|
|
248
|
+
move: e.channels?.move ?? "closed",
|
|
249
|
+
events: e.channels?.events ?? "closed"
|
|
250
|
+
},
|
|
251
|
+
movesSent: e.move?.sent ?? 0,
|
|
252
|
+
movesReceived: e.move?.received ?? 0,
|
|
253
|
+
error: m(e.error)
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
function g(e = {}) {
|
|
257
|
+
return e.phase === "connected" ? "" : e.manualTurn?.status === "applying" ? "Aplicando la configuración de conexión alternativa." : e.manualTurn?.status === "sharing" ? "Sincronizando la configuración con el otro jugador." : e.manualTurn?.status === "waiting_peer" ? "Esperando al otro jugador para compartir la configuración." : e.error === "turn_credentials_expired" || e.manualTurn?.expiresAt != null && e.manualTurn.expiresAt <= Date.now() ? "La validez indicada de TURN terminó. Pega credenciales temporales nuevas para reconectar." : e.signals?.sendFailures ? "No se pudieron enviar señales por el chat. Revisa la conexión WebSocket y reintenta." : e.ice === "checking" || e.ice === "failed" ? e.turnConfigured ? "WebRTC aún no encuentra una ruta entre los jugadores. Puedes revisar o renovar la configuración TURN." : "WebRTC aún no encuentra una ruta entre los jugadores. Algunas redes necesitan un servidor TURN; puedes configurar una conexión alternativa." : e.phase === "listening" ? "Esperando la conexión del rival. Ambos deben mantener abierta la partida y usar la misma versión del chat." : e.phase === "failed" ? "No se pudo conectar. Revisa el diagnóstico de ambos jugadores y reintenta." : "Intercambiando señales de conexión por el chat. El combate empieza cuando conecta WebRTC.";
|
|
258
|
+
}
|
|
259
|
+
export { g as n, p as r, h as t };
|
|
260
|
+
|
|
261
|
+
//# sourceMappingURL=tanks-live-BcKmrhnV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tanks-live-BcKmrhnV.js","names":["parseManualTurnConfig","PLACEHOLDER","ManualTurnDialog","dialogRef","useRef","requestRef","titleId","useId","descriptionId","errorId","json","setJson","useState","ttl","setTtl","relayOnly","setRelayOnly","error","setError","busy","setBusy","applied","setApplied","dialog","open","opener","submit","event","options","validationError","request","onApply","applyError","progress","manualTurn","onClose","bounds","Link2","X","ShieldCheck","Loader2","CheckCircle2","code","value","connectionDiagnostics","route","net","candidates","manual","connectionHint"],"sources":["../../src/games/tanks-live/ManualTurnDialog.jsx","../../src/games/tanks-live/net/connectionDiagnostics.js"],"sourcesContent":["/* eslint-disable react/prop-types */\nimport { useEffect, useId, useRef, useState } from 'react';\nimport { CheckCircle2, Link2, Loader2, ShieldCheck, X } from 'lucide-react';\nimport { parseManualTurnConfig } from '../../net/webrtc/manualTurnConfig.js';\n\nconst PLACEHOLDER = '{\\n \"iceServers\": [{\\n \"urls\": [\"turn:turn.cloudflare.com:3478?transport=udp\"],\\n \"username\": \"usuario-temporal\",\\n \"credential\": \"credencial-temporal\"\\n }]\\n}';\n\nexport default function ManualTurnDialog({ open, onClose, onApply, manualTurn }) {\n const dialogRef = useRef(null);\n const requestRef = useRef(0);\n const titleId = useId();\n const descriptionId = useId();\n const errorId = useId();\n const [json, setJson] = useState('');\n const [ttl, setTtl] = useState('');\n const [relayOnly, setRelayOnly] = useState(false);\n const [error, setError] = useState('');\n const [busy, setBusy] = useState(false);\n const [applied, setApplied] = useState(false);\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!open) {\n requestRef.current += 1;\n setJson(''); setTtl(''); setRelayOnly(false); setError(''); setBusy(false); setApplied(false);\n if (dialog?.open) dialog.close();\n return undefined;\n }\n const opener = document.activeElement;\n dialog.showModal();\n return () => {\n requestRef.current += 1;\n if (dialog.open) dialog.close();\n if (opener instanceof HTMLElement && opener.isConnected) opener.focus({ preventScroll: true });\n };\n }, [open]);\n const submit = async (event) => {\n event.preventDefault();\n if (busy || !json.trim()) return;\n setError('');\n const options = { iceTransportPolicy: relayOnly ? 'relay' : 'all', ...(ttl.trim() ? { ttlSeconds: Number(ttl) } : {}) };\n try { parseManualTurnConfig(json, options); }\n catch (validationError) { setError(validationError.message); return; }\n const request = ++requestRef.current;\n setBusy(true); setApplied(false);\n try {\n await onApply(json, options);\n if (request !== requestRef.current) return;\n setJson(''); setTtl(''); setApplied(true);\n } catch (applyError) {\n if (request === requestRef.current) setError(applyError.message || 'No se pudo compartir la configuración. Inténtalo de nuevo.');\n } finally {\n if (request === requestRef.current) setBusy(false);\n }\n };\n const progress = manualTurn?.status === 'applying' ? 'Aplicando configuración en ambos jugadores…'\n : manualTurn?.status === 'waiting_peer' ? 'Esperando al otro jugador para compartir la configuración…'\n : 'Sincronizando con el otro jugador…';\n return <dialog ref={dialogRef} className=\"tl-turn-dialog\" aria-labelledby={titleId} aria-describedby={descriptionId}\n onCancel={(event) => { event.preventDefault(); onClose(); }}\n onClick={(event) => { if (event.target === event.currentTarget) { const bounds = event.currentTarget.getBoundingClientRect(); if (event.clientX < bounds.left || event.clientX > bounds.right || event.clientY < bounds.top || event.clientY > bounds.bottom) onClose(); } }}>\n <header className=\"tl-turn-dialog__header\"><span className=\"tl-turn-dialog__icon\" aria-hidden=\"true\"><Link2 size={22} /></span><div><h2 id={titleId}>Configurar conexión alternativa</h2><p>Se comparte con el otro jugador.</p></div><button type=\"button\" className=\"tl-turn-dialog__close\" aria-label=\"Cerrar configuración de conexión\" onClick={onClose}><X size={18} /></button></header>\n <form onSubmit={submit}>\n <div className=\"tl-turn-dialog__body\">\n <p id={descriptionId}>Pega el JSON de credenciales temporales de Cloudflare TURN. Se compartirá con el otro jugador para buscar una conexión alternativa.</p>\n <label className=\"tl-turn-dialog__field\">Configuración JSON<textarea autoFocus value={json} onChange={(event) => { setJson(event.target.value); setError(''); setApplied(false); }} placeholder={PLACEHOLDER} maxLength={6000} rows={7} required={!applied} readOnly={busy} autoComplete=\"off\" autoCorrect=\"off\" autoCapitalize=\"off\" spellCheck={false} aria-invalid={Boolean(error)} aria-describedby={error ? errorId : undefined} /></label>\n <div className=\"tl-turn-dialog__privacy\"><ShieldCheck size={16} aria-hidden=\"true\" /><span>Solo credenciales temporales. No pegues tu API Token ni secretos permanentes.</span></div>\n <label className=\"tl-turn-dialog__field\">Validez restante en segundos <span className=\"tl-turn-dialog__optional\">Opcional</span><input type=\"number\" min=\"1\" max=\"172800\" step=\"1\" inputMode=\"numeric\" value={ttl} onChange={(event) => { setTtl(event.target.value); setError(''); }} disabled={busy} placeholder=\"Ej. 3600\" /><small>Déjalo vacío si no conoces la caducidad. Si dejan de funcionar, pega credenciales nuevas.</small></label>\n <label className=\"tl-turn-dialog__debug\"><input type=\"checkbox\" checked={relayOnly} onChange={(event) => setRelayOnly(event.target.checked)} disabled={busy} /><span><strong>Forzar relay para diagnóstico</strong><small>Normalmente se permite P2P. Actívalo solo para comprobar TURN.</small></span></label>\n {busy && <p className=\"tl-turn-dialog__feedback\" role=\"status\"><Loader2 size={16} className=\"tl-connection-spinner\" aria-hidden=\"true\" />{progress}</p>}\n {applied && <p className=\"tl-turn-dialog__feedback tl-turn-dialog__feedback--success\" role=\"status\"><CheckCircle2 size={17} aria-hidden=\"true\" />Configuración compartida y aplicada en ambos jugadores. La ruta utilizada se mostrará al conectar.</p>}\n {error && <p id={errorId} className=\"tl-turn-dialog__error\" role=\"alert\">{error}</p>}\n </div>\n <footer className=\"tl-turn-dialog__footer\"><button type=\"button\" onClick={onClose}>{applied ? 'Listo' : 'Cancelar'}</button><button type=\"submit\" className=\"tl-turn-dialog__apply\" disabled={busy || !json.trim()}>{busy ? <Loader2 size={16} className=\"tl-connection-spinner\" aria-hidden=\"true\" /> : <Link2 size={16} aria-hidden=\"true\" />}Aplicar y reconectar</button></footer>\n </form>\n </dialog>;\n}\n","// Never include SDP, candidate addresses, pasted JSON, passwords or TURN usernames.\nconst code = value => typeof value === 'string' && /^[a-z_]+$/.test(value) ? value : value ? 'connection_error' : null;\nexport function connectionDiagnostics(net = {}) {\n const route = net.route;\n const candidates = net.candidates ?? {};\n const manual = net.manualTurn ?? {};\n return {\n phase: net.phase ?? 'idle', ice: net.ice ?? 'new',\n connection: net.connection ?? 'new', signalingState: net.signalingState ?? 'stable', gathering: net.gathering ?? 'new',\n signaling: {\n sent: net.signals?.sent ?? 0, received: net.signals?.received ?? 0,\n sendFailures: net.signals?.sendFailures ?? 0, ignored: net.signals?.ignored ?? 0,\n invalid: net.signals?.invalid ?? 0, retransmits: net.signals?.retransmits ?? 0,\n duplicates: net.signals?.duplicates ?? 0, tooLarge: net.signals?.tooLarge ?? 0,\n },\n turnConfigured: Boolean(net.turnConfigured),\n configuration: { status: manual.status ?? 'idle', shared: Boolean(manual.shared), received: Boolean(manual.received), expiresAt: manual.expiresAt ?? null, expired: manual.expiresAt != null && manual.expiresAt <= Date.now() },\n route: route?.label ?? null,\n selectedPair: route ? { relay: Boolean(route.relay), localType: route.local ?? null, remoteType: route.remote ?? null, protocol: route.protocol ?? null, relayProtocol: route.relayProtocol ?? null } : null,\n candidates: { local: candidates.local ?? 0, remote: candidates.remote ?? 0, accepted: candidates.accepted ?? 0, rejected: candidates.rejected ?? 0, localRelay: candidates.localRelay ?? 0, remoteRelay: candidates.remoteRelay ?? 0 },\n iceErrors: (net.iceErrors ?? []).slice(-10).map(error => ({ code: Number(error.code) || 0, stage: error.stage === 'gathering' ? 'gathering' : 'remote_candidate' })),\n reconnects: net.reconnects ?? 0, restarts: net.restarts ?? 0,\n rttMs: net.rtt ?? net.statsRtt ?? null, connectionTimeMs: net.elapsedMs ?? 0,\n channels: { move: net.channels?.move ?? 'closed', events: net.channels?.events ?? 'closed' },\n movesSent: net.move?.sent ?? 0, movesReceived: net.move?.received ?? 0,\n error: code(net.error),\n };\n}\n\nexport function connectionHint(net = {}) {\n if (net.phase === 'connected') return '';\n if (net.manualTurn?.status === 'applying') return 'Aplicando la configuración de conexión alternativa.';\n if (net.manualTurn?.status === 'sharing') return 'Sincronizando la configuración con el otro jugador.';\n if (net.manualTurn?.status === 'waiting_peer') return 'Esperando al otro jugador para compartir la configuración.';\n if (net.error === 'turn_credentials_expired' || (net.manualTurn?.expiresAt != null && net.manualTurn.expiresAt <= Date.now())) return 'La validez indicada de TURN terminó. Pega credenciales temporales nuevas para reconectar.';\n if (net.signals?.sendFailures) return 'No se pudieron enviar señales por el chat. Revisa la conexión WebSocket y reintenta.';\n if (net.ice === 'checking' || net.ice === 'failed') return net.turnConfigured\n ? 'WebRTC aún no encuentra una ruta entre los jugadores. Puedes revisar o renovar la configuración TURN.'\n : 'WebRTC aún no encuentra una ruta entre los jugadores. Algunas redes necesitan un servidor TURN; puedes configurar una conexión alternativa.';\n if (net.phase === 'listening') return 'Esperando la conexión del rival. Ambos deben mantener abierta la partida y usar la misma versión del chat.';\n if (net.phase === 'failed') return 'No se pudo conectar. Revisa el diagnóstico de ambos jugadores y reintenta.';\n return 'Intercambiando señales de conexión por el chat. El combate empieza cuando conecta WebRTC.';\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { i as
|
|
1
|
+
import { t as e } from "./games-BvYTWgaR.js";
|
|
2
|
+
import { i as t, o as n } from "./ChatContext-DQtKsR6Z.js";
|
|
3
|
+
import { a as r, t as i } from "./connect4Sounds-DmD-E9kX.js";
|
|
3
4
|
// src/games/tanks/sound/cues.js
|
|
4
5
|
var a = [
|
|
5
6
|
"engine_loop",
|
|
@@ -57,7 +58,16 @@ var f = [
|
|
|
57
58
|
"defeat",
|
|
58
59
|
"turn_start",
|
|
59
60
|
"your_turn",
|
|
60
|
-
"timer_warning"
|
|
61
|
+
"timer_warning",
|
|
62
|
+
"life_lost",
|
|
63
|
+
"respawn",
|
|
64
|
+
"shield_loop",
|
|
65
|
+
"shield_end",
|
|
66
|
+
"health_pickup",
|
|
67
|
+
"crate_break",
|
|
68
|
+
"barrel_explode",
|
|
69
|
+
"wall_hit",
|
|
70
|
+
"last_life"
|
|
61
71
|
], p = {
|
|
62
72
|
engine_start: .6,
|
|
63
73
|
engine_loop: .45,
|
|
@@ -73,7 +83,16 @@ var f = [
|
|
|
73
83
|
defeat: .8,
|
|
74
84
|
turn_start: .35,
|
|
75
85
|
your_turn: .4,
|
|
76
|
-
timer_warning: .35
|
|
86
|
+
timer_warning: .35,
|
|
87
|
+
life_lost: .8,
|
|
88
|
+
respawn: .7,
|
|
89
|
+
shield_loop: .4,
|
|
90
|
+
shield_end: .55,
|
|
91
|
+
health_pickup: .6,
|
|
92
|
+
crate_break: .75,
|
|
93
|
+
barrel_explode: .9,
|
|
94
|
+
wall_hit: .6,
|
|
95
|
+
last_life: .75
|
|
77
96
|
}, m = [
|
|
78
97
|
"engine_start",
|
|
79
98
|
"engine_loop",
|
|
@@ -86,7 +105,16 @@ var f = [
|
|
|
86
105
|
"big_explosion",
|
|
87
106
|
"tank_destroyed",
|
|
88
107
|
"victory",
|
|
89
|
-
"defeat"
|
|
108
|
+
"defeat",
|
|
109
|
+
"life_lost",
|
|
110
|
+
"respawn",
|
|
111
|
+
"shield_loop",
|
|
112
|
+
"shield_end",
|
|
113
|
+
"health_pickup",
|
|
114
|
+
"crate_break",
|
|
115
|
+
"barrel_explode",
|
|
116
|
+
"wall_hit",
|
|
117
|
+
"last_life"
|
|
90
118
|
], h = 120, g = {
|
|
91
119
|
engine_loop: {
|
|
92
120
|
fadeIn: .5,
|
|
@@ -99,6 +127,10 @@ var f = [
|
|
|
99
127
|
turret_loop: {
|
|
100
128
|
fadeIn: .06,
|
|
101
129
|
fadeOut: .12
|
|
130
|
+
},
|
|
131
|
+
shield_loop: {
|
|
132
|
+
fadeIn: .15,
|
|
133
|
+
fadeOut: .25
|
|
102
134
|
}
|
|
103
135
|
}, _ = .03, v = { tank_destroyed: {
|
|
104
136
|
name: "big_explosion",
|
|
@@ -119,15 +151,15 @@ function w({ extension: e = "auto", available: t = m, files: n } = {}) {
|
|
|
119
151
|
}
|
|
120
152
|
var T = null;
|
|
121
153
|
function E() {
|
|
122
|
-
return S || w(), T || (T =
|
|
154
|
+
return S || w(), T || (T = r({
|
|
123
155
|
id: "tanks",
|
|
124
|
-
baseUrl: () =>
|
|
125
|
-
settingsFrom:
|
|
156
|
+
baseUrl: () => e("tanks"),
|
|
157
|
+
settingsFrom: i,
|
|
126
158
|
sounds: b,
|
|
127
159
|
levels: p
|
|
128
160
|
})), T;
|
|
129
161
|
}
|
|
130
|
-
var D = () => typeof document < "u" && document.hidden, O = () =>
|
|
162
|
+
var D = () => typeof document < "u" && document.hidden, O = () => t() && !D(), k = /* @__PURE__ */ new Set(), A = () => {
|
|
131
163
|
if (!T) return;
|
|
132
164
|
let e = O();
|
|
133
165
|
(/* @__PURE__ */ new Set([...a, ...k])).forEach((t) => {
|
|
@@ -138,7 +170,7 @@ var D = () => typeof document < "u" && document.hidden, O = () => r() && !D(), k
|
|
|
138
170
|
});
|
|
139
171
|
}, j = !1;
|
|
140
172
|
function M() {
|
|
141
|
-
E().preload(), !j && (j = !0,
|
|
173
|
+
E().preload(), !j && (j = !0, n(A), typeof document < "u" && document.addEventListener("visibilitychange", A));
|
|
142
174
|
}
|
|
143
175
|
var N = /* @__PURE__ */ new Map(), P = /* @__PURE__ */ new Map();
|
|
144
176
|
function F(e, t) {
|
|
@@ -174,4 +206,4 @@ function H(e, t) {
|
|
|
174
206
|
}
|
|
175
207
|
export { z as a, M as i, V as n, F as o, H as r, E as t };
|
|
176
208
|
|
|
177
|
-
//# sourceMappingURL=tanksSounds-
|
|
209
|
+
//# sourceMappingURL=tanksSounds-DwjfSp3W.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tanksSounds-DwjfSp3W.js","names":["chatSoundUrl","isSoundEnabled","subscribeSoundPreference","createSoundManager","connect4Sounds","TANKS_LOOPS","play","loopStart","loopStop","IMPACT_SOUNDS","sceneEventToCues","event","name","outcomeToCues","result","TANKS_SOUND_NAMES","LEVELS","DELIVERED_TANKS_SOUNDS","RETRIGGER_MS","LOOP_RAMPS","MP3_LOOP_TRIM","YIELDS_TO","supportsOgg","files","fileFor","extension","configured","format","configureTanksSounds","overrides","available","file","manager","getTanksSoundManager","hidden","canPlay","wantedLoops","syncLoops","allowed","started","startTanksSounds","lastPlayed","suppressedUntil","suppressTanksCue","ms","playTanksCue","key","now","played","startTanksLoop","stopTanksLoop","stopAllTanksLoops","names","runCues","cues","action","handleSceneEvent","suffix","playOutcome"],"sources":["../../src/games/tanks/sound/cues.js","../../src/games/tanks/sound/tanksSounds.js"],"sourcesContent":["// Pure sound choreography for Tanks (no audio, no DOM): maps scene events to\n// one-shot plays and loop start/stop actions.\n\nexport const TANKS_LOOPS = ['engine_loop', 'tracks_loop', 'turret_loop'];\n\nconst play = (name) => ({ name, action: 'play' });\nconst loopStart = (name) => ({ name, action: 'loop_start' });\nconst loopStop = (name) => ({ name, action: 'loop_stop' });\n\nconst IMPACT_SOUNDS = { terrain: 'terrain_impact', obstacle: 'terrain_impact', ground: 'terrain_impact' };\n\n/** Scene onEvent ({ type, ... } or a bare type string) → ordered cues. */\nexport function sceneEventToCues(event) {\n const type = typeof event === 'string' ? event : event?.type;\n switch (type) {\n case 'engine_start': return [play('engine_start')];\n case 'move_start': return [loopStart('engine_loop'), loopStart('tracks_loop')];\n case 'move_end': return [loopStop('tracks_loop'), loopStop('engine_loop')];\n case 'turret_start': return [loopStart('turret_loop')];\n case 'turret_end': return [loopStop('turret_loop')];\n case 'fire': return [play('cannon_fire')];\n case 'projectile_start': return [play('projectile_whistle')];\n case 'impact': {\n const name = IMPACT_SOUNDS[event?.kind];\n return name ? [play(name)] : [];\n }\n case 'tank_hit': return [play('tank_hit')];\n case 'big_explosion': return [play('big_explosion')];\n case 'destroyed': return [play('tank_destroyed')];\n default: return [];\n }\n}\n\n/** 'victory' | 'defeat' → cues; anything else (draw, unknown) stays silent. */\nexport function outcomeToCues(result) {\n if (result === 'victory' || result === 'defeat') return [...TANKS_LOOPS.map(loopStop), play(result)];\n return [];\n}\n","// Tanks (3D) sound layer.\n//\n// Expected files (host serves them from <assets>/sounds/tanks/, i.e. the\n// package's assets/sounds/tanks/), each as .ogg and .mp3: OGG Vorbis is used where\n// the browser supports it, MP3 otherwise. Only names listed in `available` are\n// fetched, so sounds not delivered (the optional UI cues) cost no requests and never error.\n// Format: 44.1 kHz, mono. True peak <= -1 dBTP; loops cut at zero crossings so\n// they repeat without clicks.\n//\n// name duration loudness\n// engine_start 1.5-2.5 s -20 LUFS\n// engine_loop 2-4 s (loop) -24 LUFS\n// tracks_loop 1-2 s (loop) -24 LUFS\n// turret_loop 1-2 s (loop) -26 LUFS\n// cannon_fire 1.5-2.5 s -16 LUFS\n// projectile_whistle 1.5-3 s -22 LUFS\n// terrain_impact 1-2 s -17 LUFS\n// tank_hit 1-2 s -16 LUFS\n// big_explosion 2.5-4 s -14 LUFS\n// tank_destroyed 3-5 s -18 LUFS\n// victory 3-4 s -18 LUFS\n// defeat 2.5-4 s -19 LUFS\n// Tanques LIVE (lives, shield, destructibles): life_lost, respawn, shield_loop (loop),\n// shield_end, health_pickup, crate_break, barrel_explode, wall_hit, last_life\n// optional: turn_start, your_turn, timer_warning (short UI cues, ~-22 LUFS)\n//\n// Gating: the games' shared mute/volume (connect4Sounds) applies through the\n// manager; the GLOBAL chat mute (isSoundEnabled) and a hidden page silence\n// every play and stop all loops.\n\nimport { createSoundManager } from '../../../audio/createSoundManager.js';\nimport { connect4Sounds } from '../../connect4/connect4Sounds.js';\nimport { chatSoundUrl } from '../../../assets/chatAssets.js';\nimport { isSoundEnabled, subscribeSoundPreference } from '../../../notifications/chatSounds.js';\nimport { outcomeToCues, sceneEventToCues, TANKS_LOOPS } from './cues.js';\n\nexport { outcomeToCues, sceneEventToCues } from './cues.js';\n\nexport const TANKS_SOUND_NAMES = [\n 'engine_start', 'engine_loop', 'tracks_loop', 'turret_loop', 'cannon_fire', 'projectile_whistle',\n 'terrain_impact', 'tank_hit', 'big_explosion', 'tank_destroyed', 'victory', 'defeat',\n 'turn_start', 'your_turn', 'timer_warning',\n 'life_lost', 'respawn', 'shield_loop', 'shield_end', 'health_pickup', 'crate_break', 'barrel_explode', 'wall_hit', 'last_life',\n];\n\n// Relative mix, set from the delivered files' measured loudness (blasts ~-16 LUFS,\n// impacts/stingers ~-20, loops -23..-25) so weapons lead and the engine sits under them.\nconst LEVELS = {\n engine_start: 0.6, engine_loop: 0.45, tracks_loop: 0.5, turret_loop: 0.5, cannon_fire: 0.8,\n projectile_whistle: 0.6, terrain_impact: 0.85, tank_hit: 0.85, big_explosion: 0.9, tank_destroyed: 1,\n victory: 0.8, defeat: 0.8, turn_start: 0.35, your_turn: 0.4, timer_warning: 0.35,\n life_lost: 0.8, respawn: 0.7, shield_loop: 0.4, shield_end: 0.55, health_pickup: 0.6, crate_break: 0.75,\n barrel_explode: 0.9, wall_hit: 0.6, last_life: 0.75,\n};\n\n// Sounds shipped in assets/sounds/tanks/ (the UI cues are optional and not delivered).\nexport const DELIVERED_TANKS_SOUNDS = [\n 'engine_start', 'engine_loop', 'tracks_loop', 'turret_loop', 'cannon_fire', 'projectile_whistle',\n 'terrain_impact', 'tank_hit', 'big_explosion', 'tank_destroyed', 'victory', 'defeat',\n 'life_lost', 'respawn', 'shield_loop', 'shield_end', 'health_pickup', 'crate_break', 'barrel_explode', 'wall_hit', 'last_life',\n];\n// The same sound within this window (cluster bomblets, impact + blast in one frame) plays once.\nconst RETRIGGER_MS = 120;\n// Short ramps so loops follow the animation without clicks (defaults are ambient-slow).\nconst LOOP_RAMPS = {\n engine_loop: { fadeIn: 0.5, fadeOut: 0.35 },\n tracks_loop: { fadeIn: 0.12, fadeOut: 0.2 },\n turret_loop: { fadeIn: 0.06, fadeOut: 0.12 },\n shield_loop: { fadeIn: 0.15, fadeOut: 0.25 },\n};\n// MP3 decoders pad both ends; trimming that keeps the Safari loops gapless.\nconst MP3_LOOP_TRIM = 0.03;\n// tank_destroyed is the cinematic destruction sound: big_explosion yields to it.\nconst YIELDS_TO = { tank_destroyed: { name: 'big_explosion', ms: 1500 } };\n\nconst supportsOgg = () => {\n try {\n return typeof Audio !== 'undefined' && new Audio().canPlayType('audio/ogg; codecs=\"vorbis\"') !== '';\n } catch {\n return false;\n }\n};\n\n// Shared by reference with the manager, so configure() still applies to files\n// not fetched yet.\nconst files = {};\nconst fileFor = (name, extension) => `${name}.${String(extension).replace(/^\\./, '')}`;\n\nlet configured = false;\nlet format = 'ogg';\n/**\n * Call before first use to change the format ('auto' | 'ogg' | 'mp3'), the delivered\n * names, or override files ({ name: 'file.ext' | null }).\n */\nexport function configureTanksSounds({ extension = 'auto', available = DELIVERED_TANKS_SOUNDS, files: overrides } = {}) {\n configured = true;\n format = extension === 'auto' ? (supportsOgg() ? 'ogg' : 'mp3') : extension;\n TANKS_SOUND_NAMES.forEach((name) => {\n if (available.includes(name)) files[name] = fileFor(name, format);\n else delete files[name];\n });\n Object.entries(overrides || {}).forEach(([name, file]) => {\n if (file) files[name] = String(file);\n else delete files[name];\n });\n}\n\nlet manager = null;\nexport function getTanksSoundManager() {\n if (!configured) configureTanksSounds();\n if (!manager) {\n manager = createSoundManager({\n id: 'tanks',\n baseUrl: () => chatSoundUrl('tanks'), // resolved lazily at fetch time\n settingsFrom: connect4Sounds, // one mute/volume preference for every chat game\n sounds: files,\n levels: LEVELS,\n });\n }\n return manager;\n}\n\nconst hidden = () => typeof document !== 'undefined' && document.hidden;\nconst canPlay = () => isSoundEnabled() && !hidden();\n\n// Loops the game currently wants; they only sound while canPlay().\nconst wantedLoops = new Set();\nconst syncLoops = () => {\n if (!manager) return;\n const allowed = canPlay();\n new Set([...TANKS_LOOPS, ...wantedLoops]).forEach((name) => {\n if (allowed && wantedLoops.has(name)) manager.startLoop(name, { ...LOOP_RAMPS[name], trim: format === 'mp3' ? MP3_LOOP_TRIM : 0 });\n else manager.stopLoop(name);\n });\n};\n\nlet started = false;\nlet unsubscribePreference = null;\n\n/** Idempotent: starts the manager, preloads files and links mute/visibility. */\nexport function startTanksSounds() {\n const sounds = getTanksSoundManager();\n sounds.preload();\n if (started) return;\n started = true;\n unsubscribePreference = subscribeSoundPreference(syncLoops);\n if (typeof document !== 'undefined') document.addEventListener('visibilitychange', syncLoops);\n}\n\n/** Stops loops and unlinks listeners (the manager restarts on next use). */\nexport function disposeTanksSounds() {\n wantedLoops.clear();\n syncLoops();\n if (unsubscribePreference) { unsubscribePreference(); unsubscribePreference = null; }\n if (typeof document !== 'undefined') document.removeEventListener('visibilitychange', syncLoops);\n started = false;\n manager?.dispose();\n}\n\nconst lastPlayed = new Map();\nconst suppressedUntil = new Map();\n\n/** Silences `name` for `ms` (e.g. a turn whose destruction already has its own sound). */\nexport function suppressTanksCue(name, ms) {\n suppressedUntil.set(name, Math.max(suppressedUntil.get(name) ?? 0, Date.now() + ms));\n}\n\n/** One-shot cue, deduplicated by key when given. Returns true when scheduled. */\nexport function playTanksCue(name, key) {\n if (!configured) configureTanksSounds();\n if (Date.now() < (suppressedUntil.get(name) ?? 0)) return false;\n if (!canPlay()) {\n // Keep keyed cues from replaying once the page/sound comes back.\n if (key != null) getTanksSoundManager().markPlayed(name, key);\n return false;\n }\n const now = Date.now();\n if (now - (lastPlayed.get(name) ?? 0) < RETRIGGER_MS) return false;\n const played = getTanksSoundManager().play(name, key != null ? { key } : undefined);\n if (played) {\n lastPlayed.set(name, now);\n if (YIELDS_TO[name]) suppressTanksCue(YIELDS_TO[name].name, YIELDS_TO[name].ms);\n }\n return played;\n}\n\nexport function startTanksLoop(name) {\n wantedLoops.add(name);\n getTanksSoundManager();\n syncLoops();\n}\n\nexport function stopTanksLoop(name) {\n wantedLoops.delete(name);\n manager?.stopLoop(name);\n}\n\nexport function stopAllTanksLoops() {\n const names = [...TANKS_LOOPS, ...wantedLoops];\n wantedLoops.clear();\n names.forEach((name) => manager?.stopLoop(name));\n}\n\nconst runCues = (cues, key) => cues.forEach(({ name, action }) => {\n if (action === 'loop_start') startTanksLoop(name);\n else if (action === 'loop_stop') stopTanksLoop(name);\n else playTanksCue(name, key != null ? `${key}:${name}` : undefined);\n});\n\n/** Maps a scene onEvent ({ type, kind?, tankId? }) to sounds. `key` dedupes one-shots (e.g. turn id). */\nexport function handleSceneEvent(event, key) {\n const suffix = event?.tankId != null ? `:${event.tankId}` : '';\n runCues(sceneEventToCues(event), key != null ? `${key}${suffix}` : undefined);\n}\n\n/** 'victory' | 'defeat': stops every loop and plays the outcome once per key. */\nexport function playOutcome(result, key) {\n runCues(outcomeToCues(result), key);\n}\n"],"mappings":"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"}
|