@minicode-dev/chat 0.1.7 → 0.1.9
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/README.md +25 -0
- package/dist/chunks/{BattleshipGameCard-CAWHxqJE.js → BattleshipGameCard-BFqA0cjT.js} +247 -246
- package/dist/chunks/{BattleshipGameCard-CAWHxqJE.js.map → BattleshipGameCard-BFqA0cjT.js.map} +1 -1
- package/dist/chunks/{ChatContext-CUiEAMKK.js → ChatContext-dty_KPDX.js} +2 -2
- package/dist/chunks/{ChatContext-CUiEAMKK.js.map → ChatContext-dty_KPDX.js.map} +1 -1
- package/dist/chunks/TanksGameCard-D0n-lzTs.js +1535 -0
- package/dist/chunks/TanksGameCard-D0n-lzTs.js.map +1 -0
- package/dist/chunks/TanksLiveGameCard-BmNRXP66.js +849 -0
- package/dist/chunks/TanksLiveGameCard-BmNRXP66.js.map +1 -0
- package/dist/chunks/WebRtcLab-B7xBlJy1.js +510 -0
- package/dist/chunks/WebRtcLab-B7xBlJy1.js.map +1 -0
- package/dist/chunks/{connect4Sounds-BDXQAvU1.js → connect4Sounds-BN7d_TM2.js} +654 -618
- package/dist/chunks/connect4Sounds-BN7d_TM2.js.map +1 -0
- package/dist/chunks/createLiveScene-CtYPcOPo.js +364 -0
- package/dist/chunks/createLiveScene-CtYPcOPo.js.map +1 -0
- package/dist/chunks/createPeerLink-qei05vpV.js +478 -0
- package/dist/chunks/createPeerLink-qei05vpV.js.map +1 -0
- package/dist/chunks/createTankScene-CV7Brxmt.js +685 -0
- package/dist/chunks/createTankScene-CV7Brxmt.js.map +1 -0
- package/dist/chunks/fx-BHsl4S_J.js +1470 -0
- package/dist/chunks/fx-BHsl4S_J.js.map +1 -0
- package/dist/chunks/gameStatus-Cu1Z8un9.js +69 -0
- package/dist/chunks/gameStatus-Cu1Z8un9.js.map +1 -0
- package/dist/chunks/signalFaults-Dv2YjjKy.js +36 -0
- package/dist/chunks/signalFaults-Dv2YjjKy.js.map +1 -0
- package/dist/chunks/tanksSounds-C99OD2xD.js +177 -0
- package/dist/chunks/tanksSounds-C99OD2xD.js.map +1 -0
- package/dist/index.js +1956 -1857
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/index.d.ts +61 -0
- package/package.json +1 -1
- package/dist/chunks/TanksGameCard-BEnXTz_J.js +0 -1705
- package/dist/chunks/TanksGameCard-BEnXTz_J.js.map +0 -1
- package/dist/chunks/connect4Sounds-BDXQAvU1.js.map +0 -1
- package/dist/chunks/createTankScene-BuliAxwR.js +0 -2150
- package/dist/chunks/createTankScene-BuliAxwR.js.map +0 -1
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { a as e, s as t, t as n } from "./connect4Sounds-BN7d_TM2.js";
|
|
2
|
+
import { i as r, o as i } from "./ChatContext-dty_KPDX.js";
|
|
3
|
+
// src/games/tanks/sound/cues.js
|
|
4
|
+
var a = [
|
|
5
|
+
"engine_loop",
|
|
6
|
+
"tracks_loop",
|
|
7
|
+
"turret_loop"
|
|
8
|
+
], o = (e) => ({
|
|
9
|
+
name: e,
|
|
10
|
+
action: "play"
|
|
11
|
+
}), s = (e) => ({
|
|
12
|
+
name: e,
|
|
13
|
+
action: "loop_start"
|
|
14
|
+
}), c = (e) => ({
|
|
15
|
+
name: e,
|
|
16
|
+
action: "loop_stop"
|
|
17
|
+
}), l = {
|
|
18
|
+
terrain: "terrain_impact",
|
|
19
|
+
obstacle: "terrain_impact",
|
|
20
|
+
ground: "terrain_impact"
|
|
21
|
+
};
|
|
22
|
+
function u(e) {
|
|
23
|
+
switch (typeof e == "string" ? e : e?.type) {
|
|
24
|
+
case "engine_start": return [o("engine_start")];
|
|
25
|
+
case "move_start": return [s("engine_loop"), s("tracks_loop")];
|
|
26
|
+
case "move_end": return [c("tracks_loop"), c("engine_loop")];
|
|
27
|
+
case "turret_start": return [s("turret_loop")];
|
|
28
|
+
case "turret_end": return [c("turret_loop")];
|
|
29
|
+
case "fire": return [o("cannon_fire")];
|
|
30
|
+
case "projectile_start": return [o("projectile_whistle")];
|
|
31
|
+
case "impact": {
|
|
32
|
+
let t = l[e?.kind];
|
|
33
|
+
return t ? [o(t)] : [];
|
|
34
|
+
}
|
|
35
|
+
case "tank_hit": return [o("tank_hit")];
|
|
36
|
+
case "big_explosion": return [o("big_explosion")];
|
|
37
|
+
case "destroyed": return [o("tank_destroyed")];
|
|
38
|
+
default: return [];
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function d(e) {
|
|
42
|
+
return e === "victory" || e === "defeat" ? [...a.map(c), o(e)] : [];
|
|
43
|
+
}
|
|
44
|
+
// src/games/tanks/sound/tanksSounds.js
|
|
45
|
+
var f = [
|
|
46
|
+
"engine_start",
|
|
47
|
+
"engine_loop",
|
|
48
|
+
"tracks_loop",
|
|
49
|
+
"turret_loop",
|
|
50
|
+
"cannon_fire",
|
|
51
|
+
"projectile_whistle",
|
|
52
|
+
"terrain_impact",
|
|
53
|
+
"tank_hit",
|
|
54
|
+
"big_explosion",
|
|
55
|
+
"tank_destroyed",
|
|
56
|
+
"victory",
|
|
57
|
+
"defeat",
|
|
58
|
+
"turn_start",
|
|
59
|
+
"your_turn",
|
|
60
|
+
"timer_warning"
|
|
61
|
+
], p = {
|
|
62
|
+
engine_start: .6,
|
|
63
|
+
engine_loop: .45,
|
|
64
|
+
tracks_loop: .5,
|
|
65
|
+
turret_loop: .5,
|
|
66
|
+
cannon_fire: .8,
|
|
67
|
+
projectile_whistle: .6,
|
|
68
|
+
terrain_impact: .85,
|
|
69
|
+
tank_hit: .85,
|
|
70
|
+
big_explosion: .9,
|
|
71
|
+
tank_destroyed: 1,
|
|
72
|
+
victory: .8,
|
|
73
|
+
defeat: .8,
|
|
74
|
+
turn_start: .35,
|
|
75
|
+
your_turn: .4,
|
|
76
|
+
timer_warning: .35
|
|
77
|
+
}, m = [
|
|
78
|
+
"engine_start",
|
|
79
|
+
"engine_loop",
|
|
80
|
+
"tracks_loop",
|
|
81
|
+
"turret_loop",
|
|
82
|
+
"cannon_fire",
|
|
83
|
+
"projectile_whistle",
|
|
84
|
+
"terrain_impact",
|
|
85
|
+
"tank_hit",
|
|
86
|
+
"big_explosion",
|
|
87
|
+
"tank_destroyed",
|
|
88
|
+
"victory",
|
|
89
|
+
"defeat"
|
|
90
|
+
], h = 120, g = {
|
|
91
|
+
engine_loop: {
|
|
92
|
+
fadeIn: .5,
|
|
93
|
+
fadeOut: .35
|
|
94
|
+
},
|
|
95
|
+
tracks_loop: {
|
|
96
|
+
fadeIn: .12,
|
|
97
|
+
fadeOut: .2
|
|
98
|
+
},
|
|
99
|
+
turret_loop: {
|
|
100
|
+
fadeIn: .06,
|
|
101
|
+
fadeOut: .12
|
|
102
|
+
}
|
|
103
|
+
}, _ = .03, v = { tank_destroyed: {
|
|
104
|
+
name: "big_explosion",
|
|
105
|
+
ms: 1500
|
|
106
|
+
} }, y = () => {
|
|
107
|
+
try {
|
|
108
|
+
return typeof Audio < "u" && new Audio().canPlayType("audio/ogg; codecs=\"vorbis\"") !== "";
|
|
109
|
+
} catch {
|
|
110
|
+
return !1;
|
|
111
|
+
}
|
|
112
|
+
}, b = {}, x = (e, t) => `${e}.${String(t).replace(/^\./, "")}`, S = !1, C = "ogg";
|
|
113
|
+
function w({ extension: e = "auto", available: t = m, files: n } = {}) {
|
|
114
|
+
S = !0, C = e === "auto" ? y() ? "ogg" : "mp3" : e, f.forEach((e) => {
|
|
115
|
+
t.includes(e) ? b[e] = x(e, C) : delete b[e];
|
|
116
|
+
}), Object.entries(n || {}).forEach(([e, t]) => {
|
|
117
|
+
t ? b[e] = String(t) : delete b[e];
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
var T = null;
|
|
121
|
+
function E() {
|
|
122
|
+
return S || w(), T || (T = e({
|
|
123
|
+
id: "tanks",
|
|
124
|
+
baseUrl: () => t("tanks"),
|
|
125
|
+
settingsFrom: n,
|
|
126
|
+
sounds: b,
|
|
127
|
+
levels: p
|
|
128
|
+
})), T;
|
|
129
|
+
}
|
|
130
|
+
var D = () => typeof document < "u" && document.hidden, O = () => r() && !D(), k = /* @__PURE__ */ new Set(), A = () => {
|
|
131
|
+
if (!T) return;
|
|
132
|
+
let e = O();
|
|
133
|
+
(/* @__PURE__ */ new Set([...a, ...k])).forEach((t) => {
|
|
134
|
+
e && k.has(t) ? T.startLoop(t, {
|
|
135
|
+
...g[t],
|
|
136
|
+
trim: C === "mp3" ? _ : 0
|
|
137
|
+
}) : T.stopLoop(t);
|
|
138
|
+
});
|
|
139
|
+
}, j = !1;
|
|
140
|
+
function M() {
|
|
141
|
+
E().preload(), !j && (j = !0, i(A), typeof document < "u" && document.addEventListener("visibilitychange", A));
|
|
142
|
+
}
|
|
143
|
+
var N = /* @__PURE__ */ new Map(), P = /* @__PURE__ */ new Map();
|
|
144
|
+
function F(e, t) {
|
|
145
|
+
P.set(e, Math.max(P.get(e) ?? 0, Date.now() + t));
|
|
146
|
+
}
|
|
147
|
+
function I(e, t) {
|
|
148
|
+
if (S || w(), Date.now() < (P.get(e) ?? 0)) return !1;
|
|
149
|
+
if (!O()) return t != null && E().markPlayed(e, t), !1;
|
|
150
|
+
let n = Date.now();
|
|
151
|
+
if (n - (N.get(e) ?? 0) < h) return !1;
|
|
152
|
+
let r = E().play(e, t == null ? void 0 : { key: t });
|
|
153
|
+
return r && (N.set(e, n), v[e] && F(v[e].name, v[e].ms)), r;
|
|
154
|
+
}
|
|
155
|
+
function L(e) {
|
|
156
|
+
k.add(e), E(), A();
|
|
157
|
+
}
|
|
158
|
+
function R(e) {
|
|
159
|
+
k.delete(e), T?.stopLoop(e);
|
|
160
|
+
}
|
|
161
|
+
function z() {
|
|
162
|
+
let e = [...a, ...k];
|
|
163
|
+
k.clear(), e.forEach((e) => T?.stopLoop(e));
|
|
164
|
+
}
|
|
165
|
+
var B = (e, t) => e.forEach(({ name: e, action: n }) => {
|
|
166
|
+
n === "loop_start" ? L(e) : n === "loop_stop" ? R(e) : I(e, t == null ? void 0 : `${t}:${e}`);
|
|
167
|
+
});
|
|
168
|
+
function V(e, t) {
|
|
169
|
+
let n = e?.tankId == null ? "" : `:${e.tankId}`;
|
|
170
|
+
B(u(e), t == null ? void 0 : `${t}${n}`);
|
|
171
|
+
}
|
|
172
|
+
function H(e, t) {
|
|
173
|
+
B(d(e), t);
|
|
174
|
+
}
|
|
175
|
+
export { z as a, M as i, V as n, F as o, H as r, E as t };
|
|
176
|
+
|
|
177
|
+
//# sourceMappingURL=tanksSounds-C99OD2xD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tanksSounds-C99OD2xD.js","names":["createSoundManager","chatSoundUrl","connect4Sounds","isSoundEnabled","subscribeSoundPreference","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// 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];\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};\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];\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};\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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"}
|