@adatechnology/game-weapons-three 0.12.0 → 0.13.1
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/dist/{chunk-ZVLG34JN.js → chunk-U4JAJ533.js} +178 -20
- package/dist/chunk-U4JAJ533.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.global.js +2098 -223
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +25 -1
- package/dist/index.js.map +1 -1
- package/dist/{testing-BlaMwqMW.d.ts → testing-DjtsFm2m.d.ts} +491 -6
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +9 -9
- package/dist/chunk-ZVLG34JN.js.map +0 -1
package/dist/index.global.js
CHANGED
|
@@ -26,6 +26,7 @@ var GameWeaponsThree = (() => {
|
|
|
26
26
|
BODY_ACTIONS: () => BODY_ACTIONS,
|
|
27
27
|
CLASS_REFERENCE_ENERGY: () => CLASS_REFERENCE_ENERGY,
|
|
28
28
|
COUNTER_ITEM_ID: () => COUNTER_ITEM_ID,
|
|
29
|
+
CUES_IN_SAMPLE: () => CUES_IN_SAMPLE,
|
|
29
30
|
DEFAULT_ENERGY_CURVE: () => DEFAULT_ENERGY_CURVE,
|
|
30
31
|
DEFAULT_EXPLOSIVES_SCENE: () => DEFAULT_EXPLOSIVES_SCENE,
|
|
31
32
|
DEFAULT_THUMBNAIL_BASE: () => DEFAULT_THUMBNAIL_BASE,
|
|
@@ -33,12 +34,18 @@ var GameWeaponsThree = (() => {
|
|
|
33
34
|
EXPLOSIVES_TEXT: () => EXPLOSIVES_TEXT,
|
|
34
35
|
GAME_DISTANCE_CURVE: () => GAME_DISTANCE_CURVE,
|
|
35
36
|
GAME_SOUND_CLASSES: () => GAME_SOUND_CLASSES,
|
|
37
|
+
GUNSHOT_PROFILES: () => GUNSHOT_PROFILES,
|
|
38
|
+
GUNSHOT_SAMPLE: () => GUNSHOT_SAMPLE,
|
|
39
|
+
GUNSHOT_SAMPLE_IDS: () => GUNSHOT_SAMPLE_IDS,
|
|
36
40
|
MECHANICAL_SOUNDS: () => MECHANICAL_SOUNDS,
|
|
37
41
|
MODEL_ENTRIES: () => MODEL_ENTRIES,
|
|
38
42
|
MOUNTED_M134_ITEM_ID: () => MOUNTED_M134_ITEM_ID,
|
|
39
43
|
P13_VALVE_MESH: () => P13_VALVE_MESH,
|
|
44
|
+
RELOAD_SAMPLE: () => RELOAD_SAMPLE,
|
|
45
|
+
RELOAD_SAMPLE_HITS: () => RELOAD_SAMPLE_HITS,
|
|
40
46
|
WEAPON_ITEM_PREFIX: () => WEAPON_ITEM_PREFIX,
|
|
41
47
|
WEAPON_THUMBNAILS: () => WEAPON_THUMBNAILS,
|
|
48
|
+
WEIGHT_INTENSITY: () => WEIGHT_INTENSITY,
|
|
42
49
|
WORLD_EFFECTS: () => WORLD_EFFECTS,
|
|
43
50
|
WORLD_EXPLOSIVE_IDS: () => WORLD_EXPLOSIVE_IDS,
|
|
44
51
|
WORLD_EXPLOSIVE_PREFIX: () => WORLD_EXPLOSIVE_PREFIX,
|
|
@@ -54,6 +61,9 @@ var GameWeaponsThree = (() => {
|
|
|
54
61
|
buildWeaponModel: () => buildWeaponModel,
|
|
55
62
|
buildWeaponModelById: () => buildWeaponModelById,
|
|
56
63
|
cartridgeShape: () => cartridgeShape,
|
|
64
|
+
computeCasingSound: () => computeCasingSound,
|
|
65
|
+
computeFlyby: () => computeFlyby,
|
|
66
|
+
computeGunshot: () => computeGunshot,
|
|
57
67
|
computeShotSound: () => computeShotSound,
|
|
58
68
|
createExplosivesTestModule: () => createExplosivesTestModule,
|
|
59
69
|
createWeaponAudio: () => createWeaponAudio,
|
|
@@ -77,6 +87,8 @@ var GameWeaponsThree = (() => {
|
|
|
77
87
|
rigStock: () => rigStock,
|
|
78
88
|
rigUnderbarrel: () => rigUnderbarrel,
|
|
79
89
|
weaponProp: () => weaponProp,
|
|
90
|
+
weaponSampleBank: () => weaponSampleBank,
|
|
91
|
+
weaponSampleDefaults: () => weaponSampleDefaults,
|
|
80
92
|
weaponThumbnailCredit: () => weaponThumbnailCredit,
|
|
81
93
|
weaponThumbnailUrl: () => weaponThumbnailUrl,
|
|
82
94
|
weaponsLayout: () => weaponsLayout,
|
|
@@ -228,6 +240,21 @@ var GameWeaponsThree = (() => {
|
|
|
228
240
|
const fraction = to.t > from.t ? (time - from.t) / (to.t - from.t) : 0;
|
|
229
241
|
return { position: mix(from.position, to.position, fraction), rotation: mix(from.rotation, to.rotation, fraction) };
|
|
230
242
|
};
|
|
243
|
+
var leadClipEvents = (clip) => {
|
|
244
|
+
const events = clip.events ?? [];
|
|
245
|
+
if (!events.some((event) => (event.lead ?? 0) > 0)) return clip;
|
|
246
|
+
let floor2 = 0;
|
|
247
|
+
const led = events.map((event) => {
|
|
248
|
+
const lead = Math.max(0, Math.min(event.t - floor2, event.lead ?? 0));
|
|
249
|
+
const t = event.t - lead;
|
|
250
|
+
floor2 = Math.max(floor2, t);
|
|
251
|
+
if (event.lead === void 0) return event;
|
|
252
|
+
const moved = { ...event, t, data: lead > 0 ? { ...event.data, lead } : { ...event.data } };
|
|
253
|
+
delete moved.lead;
|
|
254
|
+
return moved;
|
|
255
|
+
});
|
|
256
|
+
return { ...clip, events: led };
|
|
257
|
+
};
|
|
231
258
|
var createToolClipPlayer = (options) => {
|
|
232
259
|
const { clips, rig, onEvent } = options;
|
|
233
260
|
let instances = [];
|
|
@@ -270,7 +297,7 @@ var GameWeaponsThree = (() => {
|
|
|
270
297
|
}
|
|
271
298
|
const found = find(step.clip, step.variant);
|
|
272
299
|
if (!found) return;
|
|
273
|
-
const clip = step.duration && step.duration > 0 ? scaleClip(found.clip, step.duration) : found.clip;
|
|
300
|
+
const clip = leadClipEvents(step.duration && step.duration > 0 ? scaleClip(found.clip, step.duration) : found.clip);
|
|
274
301
|
const interval = options.repeatInterval?.() ?? 0.1;
|
|
275
302
|
instances = instances.filter((existing) => existing.name !== found.name || existing.delay > 0);
|
|
276
303
|
for (let round5 = 0; round5 < (step.repeat ?? 1); round5++) {
|
|
@@ -343,20 +370,20 @@ var GameWeaponsThree = (() => {
|
|
|
343
370
|
return result2;
|
|
344
371
|
};
|
|
345
372
|
var mergeById = (shipped, extra) => {
|
|
346
|
-
const
|
|
347
|
-
for (const entry2 of [...shipped, ...extra ?? []])
|
|
348
|
-
return
|
|
373
|
+
const entries2 = /* @__PURE__ */ new Map();
|
|
374
|
+
for (const entry2 of [...shipped, ...extra ?? []]) entries2.set(entry2.id, entry2);
|
|
375
|
+
return entries2;
|
|
349
376
|
};
|
|
350
|
-
var applyPatches = (
|
|
377
|
+
var applyPatches = (entries2, patches) => {
|
|
351
378
|
for (const [id, patch] of Object.entries(patches ?? {})) {
|
|
352
|
-
const entry2 =
|
|
353
|
-
if (entry2)
|
|
379
|
+
const entry2 = entries2.get(id);
|
|
380
|
+
if (entry2) entries2.set(id, deepMerge(entry2, patch));
|
|
354
381
|
else warnOnce(`registry.patch.${id}`, `patch for "${id}" ignored: no entry has that id`);
|
|
355
382
|
}
|
|
356
383
|
};
|
|
357
|
-
var removeIds = (
|
|
384
|
+
var removeIds = (entries2, ids) => {
|
|
358
385
|
for (const id of ids ?? []) {
|
|
359
|
-
if (!
|
|
386
|
+
if (!entries2.delete(id)) warnOnce(`registry.remove.${id}`, `remove of "${id}" ignored: no entry has that id`);
|
|
360
387
|
}
|
|
361
388
|
};
|
|
362
389
|
var KIT_ORIGIN_KEY = "kitOrigin";
|
|
@@ -12684,10 +12711,10 @@ var GameWeaponsThree = (() => {
|
|
|
12684
12711
|
]
|
|
12685
12712
|
}
|
|
12686
12713
|
];
|
|
12687
|
-
var findDuplicateIds = (kind,
|
|
12714
|
+
var findDuplicateIds = (kind, entries2) => {
|
|
12688
12715
|
const seen = /* @__PURE__ */ new Set();
|
|
12689
12716
|
const problems = [];
|
|
12690
|
-
for (const { id } of
|
|
12717
|
+
for (const { id } of entries2 ?? []) {
|
|
12691
12718
|
if (seen.has(id)) problems.push(`${kind} "${id}" is listed more than once`);
|
|
12692
12719
|
seen.add(id);
|
|
12693
12720
|
}
|
|
@@ -13567,8 +13594,8 @@ var GameWeaponsThree = (() => {
|
|
|
13567
13594
|
var FUSE_RNG_SALT = 3144134277;
|
|
13568
13595
|
var BREAK_RNG_SALT = 1013904242;
|
|
13569
13596
|
var UNDERBARREL_SEED_SALT = 2773480762;
|
|
13570
|
-
var findById = (
|
|
13571
|
-
const found =
|
|
13597
|
+
var findById = (entries2, id, label) => {
|
|
13598
|
+
const found = entries2.find((entry2) => entry2.id === id);
|
|
13572
13599
|
if (!found) throw new Error(`game-weapons: unknown ${label} "${id}"`);
|
|
13573
13600
|
return found;
|
|
13574
13601
|
};
|
|
@@ -14712,7 +14739,7 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
14712
14739
|
shade: () => shade
|
|
14713
14740
|
});
|
|
14714
14741
|
|
|
14715
|
-
// ../game-shapes/dist/chunk-
|
|
14742
|
+
// ../game-shapes/dist/chunk-M5N2SHNL.js
|
|
14716
14743
|
function canonicalJson(value) {
|
|
14717
14744
|
if (value === null) return "null";
|
|
14718
14745
|
if (typeof value === "number") return Object.is(value, -0) ? "-0" : Number.isFinite(value) ? String(value) : JSON.stringify(String(value));
|
|
@@ -15995,8 +16022,8 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
15995
16022
|
groups: []
|
|
15996
16023
|
};
|
|
15997
16024
|
}
|
|
15998
|
-
function make(
|
|
15999
|
-
switch (kind) {
|
|
16025
|
+
function make(p) {
|
|
16026
|
+
switch (p.kind) {
|
|
16000
16027
|
case "box": {
|
|
16001
16028
|
const size = p.size ?? [1, 1, 1];
|
|
16002
16029
|
const segments = p.segments ?? [1, 1, 1];
|
|
@@ -16025,7 +16052,7 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
16025
16052
|
case "mesh":
|
|
16026
16053
|
return mesh(p);
|
|
16027
16054
|
default:
|
|
16028
|
-
throw new Error(`game-shapes: unknown primitive kind "${String(kind)}"`);
|
|
16055
|
+
throw new Error(`game-shapes: unknown primitive kind "${String(p.kind)}"`);
|
|
16029
16056
|
}
|
|
16030
16057
|
}
|
|
16031
16058
|
var templates = /* @__PURE__ */ new Map();
|
|
@@ -16033,7 +16060,7 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
16033
16060
|
var stats = { hits: 0, misses: 0 };
|
|
16034
16061
|
function buildPrimitive(node, options = {}) {
|
|
16035
16062
|
const parameters = primitiveParameters(node, options);
|
|
16036
|
-
if (node.kind === "mesh" || templateLimit === 0) return make(node
|
|
16063
|
+
if (node.kind === "mesh" || templateLimit === 0) return make({ ...node, ...parameters });
|
|
16037
16064
|
const key2 = `${node.kind}:${canonicalJson(parameters)}`;
|
|
16038
16065
|
const cached = templates.get(key2);
|
|
16039
16066
|
if (cached) {
|
|
@@ -16043,7 +16070,7 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
|
|
|
16043
16070
|
return cached;
|
|
16044
16071
|
}
|
|
16045
16072
|
stats.misses++;
|
|
16046
|
-
const built2 = make(node
|
|
16073
|
+
const built2 = make({ ...node, ...parameters });
|
|
16047
16074
|
templates.set(key2, built2);
|
|
16048
16075
|
if (templates.size > templateLimit) templates.delete(templates.keys().next().value);
|
|
16049
16076
|
return built2;
|
|
@@ -18758,8 +18785,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
18758
18785
|
// was `maquina`
|
|
18759
18786
|
});
|
|
18760
18787
|
var OWN_TYPES = Object.freeze({ lamp: true, gas_piped: true });
|
|
18788
|
+
var sourceOf = (result2) => result2;
|
|
18761
18789
|
var ADAPTER_VERSION = "0.3.0";
|
|
18762
18790
|
var r3 = (n) => Math.round(n * 1e3) / 1e3;
|
|
18791
|
+
var at = (it) => ({ x: it.x ?? 0, z: it.z ?? 0, ry: it.ry ?? 0 });
|
|
18763
18792
|
function mergeRegistry(base, extra) {
|
|
18764
18793
|
const out = { ...base };
|
|
18765
18794
|
if (extra) {
|
|
@@ -18778,14 +18807,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
18778
18807
|
});
|
|
18779
18808
|
function create2(options = {}) {
|
|
18780
18809
|
const opts = options || {};
|
|
18781
|
-
const GI = opts.GameInteractables;
|
|
18782
|
-
const HH = opts.GameInteractablesHousehold;
|
|
18783
18810
|
const locale = opts.locale || "pt-BR";
|
|
18784
18811
|
const msg = createTranslator(locale, opts.messages);
|
|
18785
|
-
if (!
|
|
18812
|
+
if (!opts.GameInteractables || !opts.GameInteractablesHousehold) throw new Error(msg("error.missingKit"));
|
|
18813
|
+
const GI = opts.GameInteractables;
|
|
18814
|
+
const HH = opts.GameInteractablesHousehold;
|
|
18786
18815
|
const region = opts.region || "br";
|
|
18787
18816
|
const hh = HH.createHousehold({ locale, region });
|
|
18788
18817
|
const householdTypes = new Set(hh.types.map((t) => t.id));
|
|
18818
|
+
const recorderApi = () => HH.createRecorder().api;
|
|
18789
18819
|
const worlds = /* @__PURE__ */ new WeakMap();
|
|
18790
18820
|
const typeMap = mergeRegistry(TYPE_MAP, opts.typeMap);
|
|
18791
18821
|
const contentMap = mergeRegistry(CONTENT_MAP, opts.contentMap);
|
|
@@ -18821,7 +18851,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
18821
18851
|
function colorOf(res, color2) {
|
|
18822
18852
|
if (color2 == null) return void 0;
|
|
18823
18853
|
if (typeof color2 === "number") return color2;
|
|
18824
|
-
const v = res.colors && res.colors[color2];
|
|
18854
|
+
const v = res.colors && res.colors[String(color2)];
|
|
18825
18855
|
return typeof v === "number" ? v : void 0;
|
|
18826
18856
|
}
|
|
18827
18857
|
function paletteOf(res) {
|
|
@@ -18850,17 +18880,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
18850
18880
|
drawerItem: (s) => drawerItems.has(s.itemId)
|
|
18851
18881
|
};
|
|
18852
18882
|
const itemOfContent = (c) => {
|
|
18853
|
-
const
|
|
18883
|
+
const group = stackGroup(c);
|
|
18884
|
+
const id = contentMap[c.itemId] || (hh.items[c.itemId] ? c.itemId : null) || (group != null ? contentByGroup[group] : void 0) || contentFallback;
|
|
18854
18885
|
return hh.items[id] ? id : contentFallback;
|
|
18855
18886
|
};
|
|
18856
18887
|
const volume = (d) => d.size[0] * d.size[1] * d.size[2];
|
|
18857
18888
|
const candidates = (id, objectType) => {
|
|
18858
18889
|
const def = hh.items[id];
|
|
18859
|
-
const siblings = Object.values(hh.items).filter((i) => i.category === def
|
|
18890
|
+
const siblings = Object.values(hh.items).filter((i) => i.category === def?.category && i.id !== id).sort((a, b) => volume(a) - volume(b) || (a.id < b.id ? -1 : 1));
|
|
18860
18891
|
return [id].concat(siblings.map((i) => i.id), substitutes[objectType] || []);
|
|
18861
18892
|
};
|
|
18862
18893
|
function distribute(type, probeItem, stacks) {
|
|
18863
|
-
const spec = hh.build(type, probeItem,
|
|
18894
|
+
const spec = hh.build(type, probeItem, recorderApi());
|
|
18864
18895
|
const conts = spec.containers || [];
|
|
18865
18896
|
const contents = {};
|
|
18866
18897
|
for (const c of conts) contents[c.id] = c.slots.map(() => null);
|
|
@@ -18891,8 +18922,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
18891
18922
|
}
|
|
18892
18923
|
return { contents, rejected };
|
|
18893
18924
|
}
|
|
18894
|
-
function plan(
|
|
18895
|
-
|
|
18925
|
+
function plan(source, options2 = {}) {
|
|
18926
|
+
const res = sourceOf(source);
|
|
18927
|
+
const popts = options2 || {};
|
|
18896
18928
|
const o = { ox: popts.originX || 0, oz: popts.originZ || 0, inw: popts.inw || 1, base: popts.base || 0 };
|
|
18897
18929
|
const K = conv(o);
|
|
18898
18930
|
const floorSel = popts.floor;
|
|
@@ -18956,7 +18988,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
18956
18988
|
const item = {
|
|
18957
18989
|
x: K.x(m.x),
|
|
18958
18990
|
z: K.z(m.z),
|
|
18959
|
-
ry: m.frontU != null ? K.ry(m.frontU, m.frontV) : r3(m.ry || 0),
|
|
18991
|
+
ry: m.frontU != null ? K.ry(m.frontU, m.frontV ?? 0) : r3(m.ry || 0),
|
|
18960
18992
|
w: m.w,
|
|
18961
18993
|
d: m.d,
|
|
18962
18994
|
h: m.h,
|
|
@@ -18969,7 +19001,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
18969
19001
|
return item;
|
|
18970
19002
|
}
|
|
18971
19003
|
function entry2(id, type, item, origin, floor2, extra) {
|
|
18972
|
-
|
|
19004
|
+
const e = { id, type, item, origin, floor: floor2, floorY: floorYOf(res, o, floor2), connections: {} };
|
|
19005
|
+
return Object.assign(e, extra || {});
|
|
18973
19006
|
}
|
|
18974
19007
|
function store(targets, stacks) {
|
|
18975
19008
|
let rest2 = stacks || [];
|
|
@@ -18982,10 +19015,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
18982
19015
|
}
|
|
18983
19016
|
const hidden = [];
|
|
18984
19017
|
function distRect(c, x, z) {
|
|
18985
|
-
const
|
|
18986
|
-
const
|
|
18987
|
-
const
|
|
18988
|
-
const
|
|
19018
|
+
const ci = at(c.item);
|
|
19019
|
+
const dx = x - ci.x;
|
|
19020
|
+
const dz = z - ci.z;
|
|
19021
|
+
const s = Math.sin(ci.ry);
|
|
19022
|
+
const co = Math.cos(ci.ry);
|
|
18989
19023
|
const lx = dx * co - dz * s;
|
|
18990
19024
|
const lz = dx * s + dz * co;
|
|
18991
19025
|
return Math.hypot(Math.max(Math.abs(lx) - (c.item.w || 0) / 2, 0), Math.max(Math.abs(lz) - (c.item.d || 0) / 2, 0));
|
|
@@ -18993,9 +19027,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
18993
19027
|
function hideCylinders() {
|
|
18994
19028
|
for (const b of hidden) {
|
|
18995
19029
|
let target = null;
|
|
19030
|
+
const bi = at(b.item);
|
|
18996
19031
|
for (const c2 of result2.items) {
|
|
18997
19032
|
if (c2.type !== "kitchen_cabinet_base" || c2.floor !== b.floor) continue;
|
|
18998
|
-
const dist2 = distRect(c2,
|
|
19033
|
+
const dist2 = distRect(c2, bi.x, bi.z);
|
|
18999
19034
|
if (!target || dist2 < target.dist) target = { c: c2, dist: dist2 };
|
|
19000
19035
|
}
|
|
19001
19036
|
if (!target) {
|
|
@@ -19003,16 +19038,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19003
19038
|
continue;
|
|
19004
19039
|
}
|
|
19005
19040
|
const c = target.c;
|
|
19006
|
-
const spec = hh.build(c.type, c.item,
|
|
19007
|
-
const
|
|
19008
|
-
const
|
|
19041
|
+
const spec = hh.build(c.type, c.item, recorderApi());
|
|
19042
|
+
const ci = at(c.item);
|
|
19043
|
+
const sn = Math.sin(ci.ry);
|
|
19044
|
+
const cs = Math.cos(ci.ry);
|
|
19009
19045
|
let door = null;
|
|
19010
19046
|
for (const it of spec.interactions || []) {
|
|
19011
|
-
const
|
|
19012
|
-
|
|
19013
|
-
|
|
19014
|
-
const
|
|
19015
|
-
const
|
|
19047
|
+
const action = it.action;
|
|
19048
|
+
const pt = action.do === "toggle_part" ? (spec.parts || []).find((q) => q.id === action.part) : null;
|
|
19049
|
+
if (!pt || !pt.motion || pt.motion.kind !== "hinge") continue;
|
|
19050
|
+
const wx = ci.x + it.pos[0] * cs + it.pos[2] * sn;
|
|
19051
|
+
const wz = ci.z - it.pos[0] * sn + it.pos[2] * cs;
|
|
19052
|
+
const dist2 = Math.hypot(wx - bi.x, wz - bi.z);
|
|
19016
19053
|
if (!door || dist2 < door.dist) door = { id: pt.id, dist: dist2 };
|
|
19017
19054
|
}
|
|
19018
19055
|
if (!door) {
|
|
@@ -19042,9 +19079,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19042
19079
|
const campCylinder = firstOfType("gas_canister");
|
|
19043
19080
|
function planFireplace(m, e, item) {
|
|
19044
19081
|
const def = hh.types.find((t) => t.id === "fireplace");
|
|
19045
|
-
const lack = (def.d - m.d) / 2;
|
|
19046
|
-
|
|
19047
|
-
item.
|
|
19082
|
+
const lack = ((def ? def.d : m.d) - m.d) / 2;
|
|
19083
|
+
const p = at(item);
|
|
19084
|
+
item.x = r3(p.x + Math.sin(p.ry) * lack);
|
|
19085
|
+
item.z = r3(p.z + Math.cos(p.ry) * lack);
|
|
19048
19086
|
const room = (res.rooms || []).find((c) => c.id === m.room && c.floor === m.floor);
|
|
19049
19087
|
const f = (res.floors || []).find((x) => x.index === m.floor);
|
|
19050
19088
|
item.h = r3(room && room.ceiling || f && f.ceiling || 2.6);
|
|
@@ -19072,7 +19110,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19072
19110
|
e.connections.gas = m.gas || "cylinder";
|
|
19073
19111
|
e.connections.cylinder = m.cylinder || null;
|
|
19074
19112
|
}
|
|
19075
|
-
if (map.type === "gas_bottle") result2.cylinders.push({ id: e.id, stove: m.link
|
|
19113
|
+
if (map.type === "gas_bottle") result2.cylinders.push({ id: e.id, stove: typeof m.link === "string" ? m.link : null, place: m.placement || null });
|
|
19076
19114
|
if (map.type === "gas_canister") {
|
|
19077
19115
|
result2.canisters.push(e.id);
|
|
19078
19116
|
if (campCylinder && campCylinder.id === m.id && campStove2) result2.cylinders.push({ id: e.id, stove: campStove2.id, place: null });
|
|
@@ -19096,7 +19134,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19096
19134
|
push(e);
|
|
19097
19135
|
}
|
|
19098
19136
|
function planCompound(m, kind) {
|
|
19099
|
-
const ry = m.frontU != null ? K.ry(m.frontU, m.frontV) : r3(m.ry || 0);
|
|
19137
|
+
const ry = m.frontU != null ? K.ry(m.frontU, m.frontV ?? 0) : r3(m.ry || 0);
|
|
19100
19138
|
const cx = K.x(m.x);
|
|
19101
19139
|
const cz = K.z(m.z);
|
|
19102
19140
|
const part = (id, type, w, d, h, y, lx, lz) => {
|
|
@@ -19148,11 +19186,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19148
19186
|
} else {
|
|
19149
19187
|
const basin = part(m.id, "sink_bathroom", m.w, m.d, m.h + 0.2, 0, 0, 0);
|
|
19150
19188
|
list2.push(basin);
|
|
19151
|
-
|
|
19152
|
-
|
|
19189
|
+
const own = contents[m.id];
|
|
19190
|
+
if (own) {
|
|
19191
|
+
if (own.length) {
|
|
19153
19192
|
const cabinet = part(m.id + "#cabinet", "bathroom_cabinet", Math.max(0.45, Math.min(0.6, m.w)), 0.15, 0.75, 1.3, 0, -(m.d / 2) + 0.075);
|
|
19154
19193
|
list2.push(cabinet);
|
|
19155
|
-
store([["bathroom_cabinet", cabinet.item], ["sink_bathroom", basin.item]],
|
|
19194
|
+
store([["bathroom_cabinet", cabinet.item], ["sink_bathroom", basin.item]], own);
|
|
19156
19195
|
} else {
|
|
19157
19196
|
store([["sink_bathroom", basin.item]], []);
|
|
19158
19197
|
}
|
|
@@ -19192,7 +19231,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19192
19231
|
result2.chairs = [];
|
|
19193
19232
|
if (opts.chairs !== false && popts.chairs !== false) {
|
|
19194
19233
|
const blocked = blockedOf(res, { originX: o.ox, originZ: o.oz, inw: o.inw });
|
|
19195
|
-
const floorKind = (q) => !q.decor && !q.flat && (q.y || 0) < 0.9 && q.aabb;
|
|
19234
|
+
const floorKind = (q) => !q.decor && !q.flat && (q.y || 0) < 0.9 && !!q.aabb;
|
|
19196
19235
|
const placed = [];
|
|
19197
19236
|
const free = (m, cu, cv, half) => {
|
|
19198
19237
|
const a = [cu - half + 0.03, cv - half + 0.03, cu + half - 0.03, cv + half - 0.03];
|
|
@@ -19208,8 +19247,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19208
19247
|
for (const m of res.items || []) {
|
|
19209
19248
|
const mode = chairTables[m.type];
|
|
19210
19249
|
if (!mode || !onFloor(m.floor, m.outdoor) || m.frontU == null) continue;
|
|
19211
|
-
const
|
|
19212
|
-
const
|
|
19250
|
+
const fv = m.frontV ?? 0;
|
|
19251
|
+
const f = [m.frontU, fv];
|
|
19252
|
+
const pp = [-fv, m.frontU];
|
|
19213
19253
|
const seats = [];
|
|
19214
19254
|
if (mode === "dining") {
|
|
19215
19255
|
const n = Math.max(1, Math.min(3, Math.floor((m.w - 0.1) / 0.55)));
|
|
@@ -19278,8 +19318,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19278
19318
|
const item = { x: K.x(s.u), z: K.z(s.v), ry: K.ry(s.frontU, s.frontV), y: s.y, seed: seedOf2(s.id) };
|
|
19279
19319
|
item.controls = (s.controls || []).map((id) => id + ":lamp");
|
|
19280
19320
|
const e = entry2(s.id, "wall_switch", item, s.id, s.floor);
|
|
19281
|
-
|
|
19282
|
-
e.
|
|
19321
|
+
const controls = (s.controls || []).slice();
|
|
19322
|
+
e.connections.controls = controls;
|
|
19323
|
+
e.lit = controls.some((id) => result2.items.find((x) => x.id === id)?.lit === true);
|
|
19283
19324
|
if (floorSel == null) {
|
|
19284
19325
|
for (const id of s.controls || []) if (!lights.has(id)) result2.warnings.push(msg("warn.switchUnknownLamp", { id: s.id, lamp: id }));
|
|
19285
19326
|
}
|
|
@@ -19319,7 +19360,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19319
19360
|
seed: seedOf2("panel"),
|
|
19320
19361
|
circuits: circuits.map((c) => ({ id: c.id, label: c.room }))
|
|
19321
19362
|
};
|
|
19322
|
-
if (!item.circuits
|
|
19363
|
+
if (!item.circuits?.length) delete item.circuits;
|
|
19323
19364
|
const e = entry2("panel", "electrical_panel", item, "panel", q.floor);
|
|
19324
19365
|
push(e);
|
|
19325
19366
|
result2.panel = e.id;
|
|
@@ -19341,10 +19382,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19341
19382
|
}
|
|
19342
19383
|
}
|
|
19343
19384
|
const piped = result2.items.filter((e) => e.type === "stove" && e.connections.gas === "piped");
|
|
19344
|
-
|
|
19385
|
+
const firstPiped = piped[0];
|
|
19386
|
+
if (firstPiped) {
|
|
19345
19387
|
const med = utilities.gas && utilities.gas.meter;
|
|
19346
|
-
const ref = med ? { x: K.x(med.u), z: K.z(med.v), y: med.y || 1 } : { x:
|
|
19347
|
-
const e = entry2("piped_gas", "gas_piped", { x: ref.x, z: ref.z, ry: 0, y: ref.y, seed: seedOf2("piped_gas") }, "piped_gas",
|
|
19388
|
+
const ref = med ? { x: K.x(med.u), z: K.z(med.v), y: med.y || 1 } : { x: firstPiped.item.x, z: firstPiped.item.z, y: 0.3 };
|
|
19389
|
+
const e = entry2("piped_gas", "gas_piped", { x: ref.x, z: ref.z, ry: 0, y: ref.y, seed: seedOf2("piped_gas") }, "piped_gas", firstPiped.floor);
|
|
19348
19390
|
e.floorY = o.base;
|
|
19349
19391
|
push(e);
|
|
19350
19392
|
for (const f of piped) f.connections.fuel = "piped_gas:gas";
|
|
@@ -19391,9 +19433,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19391
19433
|
for (const dv of spec.devices || []) if (L.outlet && dv.socket === "auto") dv.socket = L.outlet + ":socket";
|
|
19392
19434
|
} else {
|
|
19393
19435
|
const sh = L.shower || {};
|
|
19394
|
-
const
|
|
19436
|
+
const devices = spec.devices || [];
|
|
19437
|
+
const heater = devices.find((d) => d.id === "heater");
|
|
19395
19438
|
if (heater && sh.electric === false) {
|
|
19396
|
-
spec.devices =
|
|
19439
|
+
spec.devices = devices.filter((d) => d !== heater);
|
|
19397
19440
|
for (const f of spec.fixtures || []) if (f.heater === "heater") delete f.heater;
|
|
19398
19441
|
} else if (heater) {
|
|
19399
19442
|
if (sh.powerW) heater.watts = sh.powerW;
|
|
@@ -19404,7 +19447,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19404
19447
|
for (const b of spec.burners || []) if (b.fuel === "auto") b.fuel = L.fuel;
|
|
19405
19448
|
}
|
|
19406
19449
|
if (entry2.type === "fireplace" && L.chimneyTop) {
|
|
19407
|
-
const it = entry2.item;
|
|
19450
|
+
const it = at(entry2.item);
|
|
19408
19451
|
const dx = L.chimneyTop[0] - it.x;
|
|
19409
19452
|
const dz = L.chimneyTop[2] - it.z;
|
|
19410
19453
|
const lx = Math.cos(it.ry) * dx - Math.sin(it.ry) * dz;
|
|
@@ -19423,8 +19466,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19423
19466
|
}
|
|
19424
19467
|
return spec;
|
|
19425
19468
|
}
|
|
19426
|
-
function createWorld(
|
|
19427
|
-
|
|
19469
|
+
function createWorld(source, options2 = {}) {
|
|
19470
|
+
const res = sourceOf(source);
|
|
19471
|
+
const copts = options2 || {};
|
|
19428
19472
|
const info = { points: /* @__PURE__ */ new Map(), water: copts.water || null, lightsOn: copts.lightsOn };
|
|
19429
19473
|
const electrical = res.utilities && res.utilities.electrical;
|
|
19430
19474
|
const world = GI.createWorld({
|
|
@@ -19452,8 +19496,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19452
19496
|
const info = worlds.get(world);
|
|
19453
19497
|
return info ? info.points.get(fixtureId) : void 0;
|
|
19454
19498
|
}
|
|
19455
|
-
function blockedOf(
|
|
19456
|
-
|
|
19499
|
+
function blockedOf(source, options2 = {}) {
|
|
19500
|
+
const res = sourceOf(source);
|
|
19501
|
+
const bopts = options2 || {};
|
|
19457
19502
|
const ox = bopts.originX || 0;
|
|
19458
19503
|
const oz = bopts.originZ || 0;
|
|
19459
19504
|
const inw = bopts.inw || 1;
|
|
@@ -19488,33 +19533,33 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19488
19533
|
return false;
|
|
19489
19534
|
};
|
|
19490
19535
|
}
|
|
19491
|
-
function add2(world, planned,
|
|
19492
|
-
aopts =
|
|
19536
|
+
function add2(world, planned, options2 = {}) {
|
|
19537
|
+
const aopts = options2 || {};
|
|
19493
19538
|
const info = worlds.get(world);
|
|
19494
|
-
const build = aopts.build || ((type, item) => hh.build(type, item,
|
|
19539
|
+
const build = aopts.build || ((type, item) => hh.build(type, item, recorderApi()));
|
|
19495
19540
|
const isBlocked2 = aopts.isBlocked || null;
|
|
19496
19541
|
const out = { added: 0, parts: [], hinges: {}, moved: {}, warnings: [] };
|
|
19497
19542
|
const override = aopts.lightsOn !== void 0 ? aopts.lightsOn : info && info.lightsOn;
|
|
19498
19543
|
if (override !== void 0) {
|
|
19499
19544
|
for (const e of planned.items) if (e.type === "lamp") e.lit = typeof override === "function" ? !!override(e.id, e) : !!override;
|
|
19500
19545
|
for (const e of planned.items) if (e.type === "lantern_lamp") e.lit = typeof override === "function" ? !!override(e.id, e) : !!override;
|
|
19501
|
-
for (const e of planned.items) if (e.type === "wall_switch") e.lit = (e.connections.controls || []).some((id) =>
|
|
19546
|
+
for (const e of planned.items) if (e.type === "wall_switch") e.lit = (e.connections.controls || []).some((id) => planned.items.find((x) => x.id === id)?.lit === true);
|
|
19502
19547
|
}
|
|
19503
19548
|
for (const e of planned.items) if (e.type === "lantern_lamp") e.item.on = !!e.lit;
|
|
19504
19549
|
let scratch2 = null;
|
|
19505
|
-
function probe(e, hinge, setback) {
|
|
19550
|
+
function probe(e, hinge, setback, blockedAt) {
|
|
19506
19551
|
if (!scratch2) scratch2 = GI.createWorld({ locale, strings: hh.strings, items: hh.items, loot: hh.loot, grid: false });
|
|
19507
|
-
const it = e.item;
|
|
19552
|
+
const it = at(e.item);
|
|
19508
19553
|
const x = it.x + Math.sin(it.ry) * setback;
|
|
19509
19554
|
const z = it.z + Math.cos(it.ry) * setback;
|
|
19510
|
-
const spec = hh.build(e.type, Object.assign({},
|
|
19555
|
+
const spec = hh.build(e.type, Object.assign({}, e.item, { hinge }), recorderApi());
|
|
19511
19556
|
scratch2.add("__probe", spec, { x, y: e.floorY, z, ry: it.ry });
|
|
19512
|
-
const blocks = (px, pz) =>
|
|
19557
|
+
const blocks = (px, pz) => blockedAt(px, pz, e.floor);
|
|
19513
19558
|
let sum2 = 0;
|
|
19514
19559
|
let min2 = 1;
|
|
19515
19560
|
let n = 0;
|
|
19516
19561
|
for (const p of spec.parts || []) {
|
|
19517
|
-
if (p.motion.kind !== "hinge" || !(p.bounds || p.sweep)) continue;
|
|
19562
|
+
if (!p.motion || p.motion.kind !== "hinge" || !(p.bounds || p.sweep)) continue;
|
|
19518
19563
|
const t = scratch2.fitSweep("__probe", p.id, blocks);
|
|
19519
19564
|
sum2 += t;
|
|
19520
19565
|
min2 = Math.min(min2, t);
|
|
@@ -19526,12 +19571,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19526
19571
|
const better = (a, b) => a.sum > b.sum + 1e-9 || Math.abs(a.sum - b.sum) <= 1e-9 && a.min > b.min + 1e-9;
|
|
19527
19572
|
function fitDoors(e) {
|
|
19528
19573
|
if (!isBlocked2 || !householdTypes.has(e.type)) return;
|
|
19529
|
-
const standard = probe(e, void 0, 0);
|
|
19574
|
+
const standard = probe(e, void 0, 0, isBlocked2);
|
|
19530
19575
|
if (!standard.n || standard.min >= 1) return;
|
|
19531
19576
|
let bestSide;
|
|
19532
19577
|
let m = standard;
|
|
19533
19578
|
for (const side of ["left", "right"]) {
|
|
19534
|
-
const r = probe(e, side, 0);
|
|
19579
|
+
const r = probe(e, side, 0, isBlocked2);
|
|
19535
19580
|
if (better(r, m)) {
|
|
19536
19581
|
m = r;
|
|
19537
19582
|
bestSide = side;
|
|
@@ -19544,13 +19589,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19544
19589
|
if (m.min >= 1) return;
|
|
19545
19590
|
let target = { setback: 0, r: m };
|
|
19546
19591
|
for (const setback of [0.01, 0.02, 0.03, 0.04]) {
|
|
19547
|
-
const r = probe(e, bestSide, setback);
|
|
19592
|
+
const r = probe(e, bestSide, setback, isBlocked2);
|
|
19548
19593
|
if (better(r, target.r)) target = { setback, r };
|
|
19549
19594
|
if (r.min >= 1) break;
|
|
19550
19595
|
}
|
|
19551
19596
|
if (target.setback > 0 && target.r.sum > m.sum + 0.2) {
|
|
19552
|
-
|
|
19553
|
-
e.item.
|
|
19597
|
+
const p = at(e.item);
|
|
19598
|
+
e.item.x = r3(p.x + Math.sin(p.ry) * target.setback);
|
|
19599
|
+
e.item.z = r3(p.z + Math.cos(p.ry) * target.setback);
|
|
19554
19600
|
e.moved = target.setback;
|
|
19555
19601
|
out.moved[e.id] = target.setback;
|
|
19556
19602
|
}
|
|
@@ -19573,7 +19619,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19573
19619
|
}
|
|
19574
19620
|
}
|
|
19575
19621
|
connect(e, spec);
|
|
19576
|
-
|
|
19622
|
+
const pose = at(e.item);
|
|
19623
|
+
world.add(e.id, spec, { x: pose.x, y: e.floorY, z: pose.z, ry: pose.ry });
|
|
19577
19624
|
out.added++;
|
|
19578
19625
|
if (!isBlocked2) continue;
|
|
19579
19626
|
for (const p of spec.parts || []) {
|
|
@@ -22322,7 +22369,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22322
22369
|
const typed = listeners.get(e.type);
|
|
22323
22370
|
if (typed) for (const fn of [...typed]) fn(e);
|
|
22324
22371
|
};
|
|
22325
|
-
|
|
22372
|
+
let blow3;
|
|
22373
|
+
const base = (o, source) => ({
|
|
22374
|
+
object: o.id,
|
|
22375
|
+
time,
|
|
22376
|
+
...source === void 0 ? {} : { source },
|
|
22377
|
+
...blow3 === void 0 ? {} : { blow: blow3 }
|
|
22378
|
+
});
|
|
22326
22379
|
const pendingCollapse = /* @__PURE__ */ new Map();
|
|
22327
22380
|
let runDepth = 0;
|
|
22328
22381
|
const drainBlasts = () => {
|
|
@@ -24467,7 +24520,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
24467
24520
|
res.events = cur.slice(start);
|
|
24468
24521
|
return res;
|
|
24469
24522
|
};
|
|
24470
|
-
const
|
|
24523
|
+
const withBlow = (type, fn) => () => {
|
|
24524
|
+
const outer = blow3;
|
|
24525
|
+
blow3 = type;
|
|
24526
|
+
try {
|
|
24527
|
+
return fn();
|
|
24528
|
+
} finally {
|
|
24529
|
+
blow3 = outer;
|
|
24530
|
+
}
|
|
24531
|
+
};
|
|
24532
|
+
const doHit = (o, hit, only) => withBlow(hit.type, () => resolveHit(o, hit, only))();
|
|
24533
|
+
const resolveHit = (o, hit, only) => {
|
|
24471
24534
|
let point = hit.point;
|
|
24472
24535
|
let dir = hit.direction;
|
|
24473
24536
|
if (hit.space === "local") {
|
|
@@ -24906,6 +24969,44 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
24906
24969
|
blastProbe() {
|
|
24907
24970
|
return { ...blastProbe };
|
|
24908
24971
|
},
|
|
24972
|
+
blastReach(point, target, options2 = {}) {
|
|
24973
|
+
const L = vec.distance(point, target);
|
|
24974
|
+
if (L < 1e-4) return 1;
|
|
24975
|
+
const shelter = { ...SHELTER_DEFAULTS, ...options2.shelter };
|
|
24976
|
+
const ignore = new Set(options2.ignore ?? []);
|
|
24977
|
+
const d = vec.scale(vec.sub(target, point), 1 / L);
|
|
24978
|
+
let t = 1;
|
|
24979
|
+
for (const o of objects.values()) {
|
|
24980
|
+
if (ignore.has(o.id) || raySphereMiss(point, d, toWorld(o.st.position, o.st.rotation, o.bc), o.br, L)) continue;
|
|
24981
|
+
for (const p of o.parts) {
|
|
24982
|
+
if (isLost(p) || p.st.stripped) continue;
|
|
24983
|
+
const r = rayPart(o, p, point, d);
|
|
24984
|
+
if (!r) continue;
|
|
24985
|
+
const t0 = Math.max(r.t0, 0);
|
|
24986
|
+
const path = Math.min(r.t1, L) - t0;
|
|
24987
|
+
if (path < shelter.minPath) continue;
|
|
24988
|
+
if (p.st.opening && insideOpening(o, p, toLocal(o.st.position, o.st.rotation, vec.madd(point, d, t0 + path / 2)))) continue;
|
|
24989
|
+
t *= Math.exp(-(p.mat.hpPerKg * p.mat.density * path * (p.mat.damageScale?.shelter ?? 1)) / shelter.k);
|
|
24990
|
+
if (t < 1e-4) return 0;
|
|
24991
|
+
}
|
|
24992
|
+
}
|
|
24993
|
+
for (const im of impls.values()) {
|
|
24994
|
+
if (ignore.has(im.impl.id)) continue;
|
|
24995
|
+
for (const ps of im.impl.describe().parts) {
|
|
24996
|
+
const mat = materials.get(ps.material);
|
|
24997
|
+
if (!mat) continue;
|
|
24998
|
+
const ov = im.poses.get(ps.id);
|
|
24999
|
+
const r = rayPartRaw(im.position, im.rotation, ps, ov?.q ?? quatFromEuler(...ps.rotation ?? [0, 0, 0]), point, d, ov?.pos);
|
|
25000
|
+
if (!r || r.t1 < 0 || r.t0 > L) continue;
|
|
25001
|
+
let path = Math.min(r.t1, L) - Math.max(r.t0, 0);
|
|
25002
|
+
if (ps.thickness !== void 0 && ps.thickness > 0) path = Math.min(path, 2 * ps.thickness);
|
|
25003
|
+
else if (path < shelter.minPath) continue;
|
|
25004
|
+
t *= Math.exp(-(mat.hpPerKg * mat.density * path * (mat.damageScale?.shelter ?? 1)) / shelter.k);
|
|
25005
|
+
if (t < 1e-4) return 0;
|
|
25006
|
+
}
|
|
25007
|
+
}
|
|
25008
|
+
return t;
|
|
25009
|
+
},
|
|
24909
25010
|
explode(point, energy, radius, source, blast) {
|
|
24910
25011
|
blastProbe.partsTested = 0;
|
|
24911
25012
|
blastProbe.partsNear = 0;
|
|
@@ -24930,7 +25031,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
24930
25031
|
},
|
|
24931
25032
|
shoot(origin, direction, energy, caliber, source, round5) {
|
|
24932
25033
|
const extras = typeof round5 === "number" ? { piercing: round5 } : round5 ?? {};
|
|
24933
|
-
return withCollapses(run(() => {
|
|
25034
|
+
return withCollapses(run(withBlow("ballistic", () => {
|
|
24934
25035
|
const results = [];
|
|
24935
25036
|
const d = vec.normalize(direction);
|
|
24936
25037
|
const ignore = /* @__PURE__ */ new Set();
|
|
@@ -24941,10 +25042,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
24941
25042
|
if (!rh) break;
|
|
24942
25043
|
const im = impls.get(rh.object);
|
|
24943
25044
|
if (im) {
|
|
24944
|
-
const
|
|
25045
|
+
const scaled2 = extras.penetration && E < energy ? { ...extras, penetration: Object.fromEntries(Object.entries(extras.penetration).map(([k, mm]) => [k, mm * (E / energy)])) } : extras;
|
|
25046
|
+
const r = implHit(im, { type: "ballistic", point: rh.point, part: rh.part, normal: rh.normal, direction: d, energy: E, caliber, ...scaled2, ...source !== void 0 ? { source } : {} });
|
|
24945
25047
|
r.part = rh.part;
|
|
24946
25048
|
r.point = rh.point;
|
|
24947
|
-
|
|
25049
|
+
const left = r.events.find((e) => e.type === "hole" && e.energyLeft !== void 0);
|
|
25050
|
+
r.exitEnergy = r.penetrated ? left?.energyLeft ?? E * 0.5 : 0;
|
|
24948
25051
|
results.push(r);
|
|
24949
25052
|
ignore.add(`${im.impl.id}\0${rh.part}`);
|
|
24950
25053
|
if (!r.penetrated) break;
|
|
@@ -24963,7 +25066,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
24963
25066
|
E = out.exitEnergy;
|
|
24964
25067
|
}
|
|
24965
25068
|
return results;
|
|
24966
|
-
}));
|
|
25069
|
+
})));
|
|
24967
25070
|
},
|
|
24968
25071
|
disassemble(objectId, jointId, tool2, dt) {
|
|
24969
25072
|
const im = impls.get(objectId);
|
|
@@ -25772,8 +25875,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
25772
25875
|
function linesOf(boxes) {
|
|
25773
25876
|
return boxes.map(([u0, v0, u1, v1]) => u1 - u0 >= v1 - v0 ? { dir: "u", at: (v0 + v1) / 2, from: u0, to: u1 } : { dir: "v", at: (u0 + u1) / 2, from: v0, to: v1 });
|
|
25774
25877
|
}
|
|
25775
|
-
function coverage(lines, dir,
|
|
25776
|
-
const spans = lines.filter((line) => line.dir === dir && Math.abs(line.at -
|
|
25878
|
+
function coverage(lines, dir, at23, from, to, options) {
|
|
25879
|
+
const spans = lines.filter((line) => line.dir === dir && Math.abs(line.at - at23) <= options.lineTolerance).map((line) => [Math.max(from, line.from), Math.min(to, line.to)]).filter(([a, b]) => b > a).sort((x, y) => x[0] - y[0]);
|
|
25777
25880
|
let covered = 0;
|
|
25778
25881
|
let end3 = from;
|
|
25779
25882
|
let start = NaN;
|
|
@@ -25795,12 +25898,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
25795
25898
|
const sorted = lines.filter((line) => line.dir === dir).map((line) => line.at).sort((a, b) => a - b);
|
|
25796
25899
|
const out = [];
|
|
25797
25900
|
let group = [];
|
|
25798
|
-
for (const
|
|
25799
|
-
if (group.length &&
|
|
25901
|
+
for (const at23 of sorted) {
|
|
25902
|
+
if (group.length && at23 - group[group.length - 1] > tolerance) {
|
|
25800
25903
|
out.push(group.reduce((s, x) => s + x, 0) / group.length);
|
|
25801
25904
|
group = [];
|
|
25802
25905
|
}
|
|
25803
|
-
group.push(
|
|
25906
|
+
group.push(at23);
|
|
25804
25907
|
}
|
|
25805
25908
|
if (group.length) out.push(group.reduce((s, x) => s + x, 0) / group.length);
|
|
25806
25909
|
return out;
|
|
@@ -25813,13 +25916,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
25813
25916
|
const tooWide = width > options.maxSpan + EPS5;
|
|
25814
25917
|
const tooDeep = depth > options.maxSpan + EPS5;
|
|
25815
25918
|
const candidates = [];
|
|
25816
|
-
for (const
|
|
25817
|
-
if (
|
|
25818
|
-
candidates.push({ dir: "v", at:
|
|
25919
|
+
for (const at23 of positions(lines, "v", options.lineTolerance)) {
|
|
25920
|
+
if (at23 < u0 + options.minPanel - EPS5 || at23 > u1 - options.minPanel + EPS5) continue;
|
|
25921
|
+
candidates.push({ dir: "v", at: at23, coverage: coverage(lines, "v", at23, v0, v1, options), skew: Math.abs(at23 - (u0 + u1) / 2) / (width / 2) });
|
|
25819
25922
|
}
|
|
25820
|
-
for (const
|
|
25821
|
-
if (
|
|
25822
|
-
candidates.push({ dir: "u", at:
|
|
25923
|
+
for (const at23 of positions(lines, "u", options.lineTolerance)) {
|
|
25924
|
+
if (at23 < v0 + options.minPanel - EPS5 || at23 > v1 - options.minPanel + EPS5) continue;
|
|
25925
|
+
candidates.push({ dir: "u", at: at23, coverage: coverage(lines, "u", at23, u0, u1, options), skew: Math.abs(at23 - (v0 + v1) / 2) / (depth / 2) });
|
|
25823
25926
|
}
|
|
25824
25927
|
const boundary = candidates.filter((c) => c.coverage >= options.lineCoverage);
|
|
25825
25928
|
if (tooWide || tooDeep) {
|
|
@@ -25905,20 +26008,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
25905
26008
|
const held = merged(supports.map(([a, b]) => [Math.max(0, a), Math.min(length2, b)]).filter(([a, b]) => b > a));
|
|
25906
26009
|
if (!held.length) return { span: Infinity, at: length2 / 2, lo: 0, hi: length2 };
|
|
25907
26010
|
let span = 0;
|
|
25908
|
-
let
|
|
26011
|
+
let at23 = length2 / 2;
|
|
25909
26012
|
let lo = 0;
|
|
25910
26013
|
let hi = length2;
|
|
25911
26014
|
const lead = held[0][0];
|
|
25912
26015
|
if (2 * lead > span) {
|
|
25913
26016
|
span = 2 * lead;
|
|
25914
|
-
|
|
26017
|
+
at23 = 0;
|
|
25915
26018
|
lo = 0;
|
|
25916
26019
|
hi = lead;
|
|
25917
26020
|
}
|
|
25918
26021
|
const trail = length2 - held[held.length - 1][1];
|
|
25919
26022
|
if (2 * trail > span) {
|
|
25920
26023
|
span = 2 * trail;
|
|
25921
|
-
|
|
26024
|
+
at23 = length2;
|
|
25922
26025
|
lo = length2 - trail;
|
|
25923
26026
|
hi = length2;
|
|
25924
26027
|
}
|
|
@@ -25926,12 +26029,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
25926
26029
|
const gap = held[k][0] - held[k - 1][1];
|
|
25927
26030
|
if (gap > span) {
|
|
25928
26031
|
span = gap;
|
|
25929
|
-
|
|
26032
|
+
at23 = (held[k][0] + held[k - 1][1]) / 2;
|
|
25930
26033
|
lo = held[k - 1][1];
|
|
25931
26034
|
hi = held[k][0];
|
|
25932
26035
|
}
|
|
25933
26036
|
}
|
|
25934
|
-
return { span, at:
|
|
26037
|
+
return { span, at: at23, lo, hi };
|
|
25935
26038
|
}
|
|
25936
26039
|
var lineOf = (aabb, dir) => dir === "u" ? { dir, at: (aabb[1] + aabb[3]) / 2, from: aabb[0], to: aabb[2] } : { dir, at: (aabb[0] + aabb[2]) / 2, from: aabb[1], to: aabb[3] };
|
|
25937
26040
|
var pointOf = (line, s) => line.dir === "u" ? [line.from + s, line.at] : [line.at, line.from + s];
|
|
@@ -25987,37 +26090,37 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
25987
26090
|
const side = options.columnSide;
|
|
25988
26091
|
const all = () => [...props, ...spots.map((spot) => ({ box: boxOfSpot(spot, side), dist: spot.dist }))];
|
|
25989
26092
|
const allowed = merged(ground.map((box22) => holds2(line, 0.02, box22)).filter((x) => x !== void 0));
|
|
25990
|
-
const place = (
|
|
25991
|
-
if (!allowed.length) return
|
|
26093
|
+
const place = (at23, lo, hi) => {
|
|
26094
|
+
if (!allowed.length) return at23;
|
|
25992
26095
|
let best;
|
|
25993
26096
|
let gap = Infinity;
|
|
25994
26097
|
for (const [a, b] of allowed) {
|
|
25995
26098
|
const from = Math.max(a + side / 2, lo + 0.2);
|
|
25996
26099
|
const to = Math.min(b - side / 2, hi - 0.2);
|
|
25997
26100
|
if (to < from) continue;
|
|
25998
|
-
const clamped = Math.min(to, Math.max(from,
|
|
25999
|
-
if (Math.abs(clamped -
|
|
26000
|
-
gap = Math.abs(clamped -
|
|
26101
|
+
const clamped = Math.min(to, Math.max(from, at23));
|
|
26102
|
+
if (Math.abs(clamped - at23) < gap) {
|
|
26103
|
+
gap = Math.abs(clamped - at23);
|
|
26001
26104
|
best = clamped;
|
|
26002
26105
|
}
|
|
26003
26106
|
}
|
|
26004
|
-
return best ??
|
|
26107
|
+
return best ?? at23;
|
|
26005
26108
|
};
|
|
26006
26109
|
let held = heldBy(line, width, all()).intervals;
|
|
26007
26110
|
for (let guard = 0; guard < 64; guard++) {
|
|
26008
|
-
let
|
|
26111
|
+
let at23;
|
|
26009
26112
|
let lo = 0;
|
|
26010
26113
|
let hi = length2;
|
|
26011
|
-
if (ends && !held.some(([a]) => a <= END_REACH))
|
|
26012
|
-
else if (ends && !held.some(([, b]) => b >= length2 - END_REACH))
|
|
26114
|
+
if (ends && !held.some(([a]) => a <= END_REACH)) at23 = 0;
|
|
26115
|
+
else if (ends && !held.some(([, b]) => b >= length2 - END_REACH)) at23 = length2;
|
|
26013
26116
|
else {
|
|
26014
26117
|
const found = beamSpan(length2, held);
|
|
26015
26118
|
if (found.span <= options.maxSpan + 1e-3) break;
|
|
26016
|
-
|
|
26119
|
+
at23 = found.at;
|
|
26017
26120
|
lo = found.lo;
|
|
26018
26121
|
hi = found.hi;
|
|
26019
26122
|
}
|
|
26020
|
-
const [u, v] = pointOf(line,
|
|
26123
|
+
const [u, v] = pointOf(line, at23 === 0 || at23 === length2 ? at23 : place(at23, lo, hi));
|
|
26021
26124
|
const spot = { u: round2(u), v: round2(v), dist: dist2 };
|
|
26022
26125
|
if (spots.some((other) => Math.hypot(other.u - spot.u, other.v - spot.v) < 0.15)) break;
|
|
26023
26126
|
spots.push(spot);
|
|
@@ -26322,7 +26425,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26322
26425
|
if (!length2) return [[from, to]];
|
|
26323
26426
|
const offset = spec.bond === "running" && row % 2 === 1 ? length2 / 2 : 0;
|
|
26324
26427
|
const cuts = [from];
|
|
26325
|
-
for (let
|
|
26428
|
+
for (let at23 = from + (offset || length2); at23 < to - MIN_UNIT; at23 += length2) cuts.push(at23);
|
|
26326
26429
|
cuts.push(to);
|
|
26327
26430
|
return cuts.slice(0, -1).map((start, k) => [start, cuts[k + 1]]).filter(([a, b]) => b - a > MIN_UNIT);
|
|
26328
26431
|
}
|
|
@@ -26733,9 +26836,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26733
26836
|
const w = s.length / n;
|
|
26734
26837
|
for (let k = 0; k < n; k++) {
|
|
26735
26838
|
const id = `glass_${f}_${s.name}_${k}`;
|
|
26736
|
-
const
|
|
26839
|
+
const at23 = -s.length / 2 + (k + 0.5) * w;
|
|
26737
26840
|
const size = s.axis === 2 ? [w - 0.01, h - 0.01, c.thickness] : [c.thickness, h - 0.01, w - 0.01];
|
|
26738
|
-
const position = s.axis === 2 ? [
|
|
26841
|
+
const position = s.axis === 2 ? [at23, yb + h / 2, s.fixed] : [s.fixed, yb + h / 2, at23];
|
|
26739
26842
|
parts.push({
|
|
26740
26843
|
id,
|
|
26741
26844
|
material: c.material,
|
|
@@ -26774,10 +26877,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26774
26877
|
const clear = length2 - g.columnSize;
|
|
26775
26878
|
const win = clear * c.window;
|
|
26776
26879
|
const pier = (clear - win) / 2;
|
|
26777
|
-
const
|
|
26880
|
+
const at23 = (u) => along === 0 ? [u, 0, fixed2] : [fixed2, 0, u];
|
|
26778
26881
|
const size = (u, h) => along === 0 ? [u, h, c.thickness] : [c.thickness, h, u];
|
|
26779
26882
|
const put = (name, u, h, y, centreU, on) => {
|
|
26780
|
-
const p =
|
|
26883
|
+
const p = at23(centreU);
|
|
26781
26884
|
wall(`infill_${f}_${side}_${k}_${name}`, size(u, h), [p[0], y, p[2]], on);
|
|
26782
26885
|
};
|
|
26783
26886
|
const id = (name) => `infill_${f}_${side}_${k}_${name}`;
|
|
@@ -26785,7 +26888,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26785
26888
|
put("pl", pier, head - sill, yb + sill + (head - sill) / 2, centre - clear / 2 + pier / 2, [c1, id("sill")]);
|
|
26786
26889
|
put("pr", pier, head - sill, yb + sill + (head - sill) / 2, centre + clear / 2 - pier / 2, [c2, id("sill")]);
|
|
26787
26890
|
put("head", clear, room - head, yb + head + (room - head) / 2, centre, [c1, c2]);
|
|
26788
|
-
const gp =
|
|
26891
|
+
const gp = at23(centre);
|
|
26789
26892
|
const gid = `glass_${f}_${side}_${k}`;
|
|
26790
26893
|
parts.push({
|
|
26791
26894
|
id: gid,
|
|
@@ -26847,13 +26950,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26847
26950
|
});
|
|
26848
26951
|
rests(joints, "roof_membrane", top, "glue");
|
|
26849
26952
|
for (let k = 0; k < count; k++) {
|
|
26850
|
-
const
|
|
26953
|
+
const at23 = -long / 2 + (k + 0.5) * spacing;
|
|
26851
26954
|
const id = `roof_drain_${k}`;
|
|
26852
26955
|
parts.push({
|
|
26853
26956
|
id,
|
|
26854
26957
|
material: "plastic",
|
|
26855
26958
|
shape: { kind: "cylinder", radius: 0.05, height: 0.1 },
|
|
26856
|
-
position: longX ? [slab.position[0] +
|
|
26959
|
+
position: longX ? [slab.position[0] + at23, my, slab.position[2]] : [slab.position[0], my, slab.position[2] + at23],
|
|
26857
26960
|
fill: 0.2,
|
|
26858
26961
|
tags: ["drain"]
|
|
26859
26962
|
});
|
|
@@ -26874,11 +26977,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26874
26977
|
const floor2 = `slab_${level - 1}`;
|
|
26875
26978
|
const y = storeyBase(g, level);
|
|
26876
26979
|
const shafts = options.shafts ?? [];
|
|
26877
|
-
const put = (id, material, size,
|
|
26878
|
-
parts.push({ id: id + sfx, material, shape: box2(size), position: [
|
|
26980
|
+
const put = (id, material, size, at23, mass, extra = {}) => {
|
|
26981
|
+
parts.push({ id: id + sfx, material, shape: box2(size), position: [at23[0], y + size[1] / 2, at23[1]], mass, fill: 0.2, structure: { role: "partition" }, tags: ["mechanical"], ...extra });
|
|
26879
26982
|
rests(joints, id + sfx, floor2, "bolt");
|
|
26880
26983
|
};
|
|
26881
|
-
shafts.forEach((
|
|
26984
|
+
shafts.forEach((at23, k) => put(`machine_${k}`, "steel", [1.2, 1, 0.8], at23, c.machineMass + c.suspendedMass, { tags: ["mechanical", "elevator_machine"] }));
|
|
26882
26985
|
const liters = options.waterLiters ?? towerWater(level, options);
|
|
26883
26986
|
const depth = 2;
|
|
26884
26987
|
const side = Math.sqrt(liters / 1e3 / depth);
|
|
@@ -26919,14 +27022,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26919
27022
|
return n === void 0 ? want : Math.round((want + span / 2) / (span / k)) * (span / k) - span / 2;
|
|
26920
27023
|
};
|
|
26921
27024
|
const colZ = column(g.spanZ, g.columnsZ, g.spanZ * 0.35);
|
|
26922
|
-
const
|
|
27025
|
+
const at23 = options.at ?? [column(g.spanX, g.columnsX, 0), colZ - Math.sign(colZ || 1) * (g.columnSize / 2 + 0.1)];
|
|
26923
27026
|
const y = storeyBase(g, g.floors - 1);
|
|
26924
27027
|
const floor2 = `slab_${g.floors - 2}`;
|
|
26925
27028
|
const part = {
|
|
26926
27029
|
id: "damper",
|
|
26927
27030
|
material: c.material,
|
|
26928
27031
|
shape: box2([side, height, side]),
|
|
26929
|
-
position: [
|
|
27032
|
+
position: [at23[0], y + height / 2, at23[1]],
|
|
26930
27033
|
mass,
|
|
26931
27034
|
structure: { role: "partition" },
|
|
26932
27035
|
tags: ["mechanical", "tuned_mass_damper"],
|
|
@@ -35428,8 +35531,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
35428
35531
|
facadeExtra: (f, rng2, w, d, op) => {
|
|
35429
35532
|
f.roof = "slab";
|
|
35430
35533
|
f.finish = rng2() < 0.55 ? "exposed_block" : "partial_plaster";
|
|
35431
|
-
|
|
35432
|
-
|
|
35534
|
+
const slab = { exposedRebar: true, waterTank: { u: r22(0.5 + rng2() * (w - 1.5)), v: r22(1 + rng2() * (d - 2)) }, annex: rng2() < 0.55 ? { rect: [0, 0, r22(w * (0.5 + rng2() * 0.3)), r22(d * 0.4)], state: "exposed_brick" } : null };
|
|
35535
|
+
f.slab = slab;
|
|
35536
|
+
if (floorsOf(op) > 1) slab.exposedRebar = rng2() < 0.6;
|
|
35433
35537
|
}
|
|
35434
35538
|
};
|
|
35435
35539
|
}
|
|
@@ -36789,7 +36893,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
36789
36893
|
};
|
|
36790
36894
|
var accessoryTextOf = (locale) => ACCESSORY_TEXT[locale] ?? ACCESSORY_TEXT.en;
|
|
36791
36895
|
|
|
36792
|
-
// ../game-audio/dist/chunk-
|
|
36896
|
+
// ../game-audio/dist/chunk-KBTUANNG.js
|
|
36793
36897
|
var DISTANCE_CURVES = {
|
|
36794
36898
|
/** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
|
|
36795
36899
|
game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
|
|
@@ -36869,15 +36973,31 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
36869
36973
|
{
|
|
36870
36974
|
id: "game",
|
|
36871
36975
|
master: 0.5,
|
|
36872
|
-
noise: {
|
|
36873
|
-
|
|
36976
|
+
noise: {
|
|
36977
|
+
seconds: 1.5,
|
|
36978
|
+
create: "lazy"
|
|
36979
|
+
},
|
|
36980
|
+
sources: [
|
|
36981
|
+
"jogo:L62077-62081 master 0.5 to the output",
|
|
36982
|
+
"jogo:L62082-62088 noise 1.5 s made by the first sound that needs it"
|
|
36983
|
+
]
|
|
36874
36984
|
},
|
|
36875
36985
|
{
|
|
36876
36986
|
id: "art_scene",
|
|
36877
36987
|
master: 0.85,
|
|
36878
|
-
compressor: {
|
|
36879
|
-
|
|
36880
|
-
|
|
36988
|
+
compressor: {
|
|
36989
|
+
threshold: -12,
|
|
36990
|
+
ratio: 5
|
|
36991
|
+
},
|
|
36992
|
+
reverb: {
|
|
36993
|
+
seconds: 2.2,
|
|
36994
|
+
decay: 3.4,
|
|
36995
|
+
wet: 0.4
|
|
36996
|
+
},
|
|
36997
|
+
noise: {
|
|
36998
|
+
seconds: 2,
|
|
36999
|
+
create: "eager"
|
|
37000
|
+
},
|
|
36881
37001
|
sources: [
|
|
36882
37002
|
"cena:L1308 compressor -12 dB, ratio 5",
|
|
36883
37003
|
"cena:L1309 master 0.85",
|
|
@@ -36885,12 +37005,36 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
36885
37005
|
"cena:L1311 wet 0.4",
|
|
36886
37006
|
"cena:L1312 noise 2 s made with the chain"
|
|
36887
37007
|
]
|
|
37008
|
+
},
|
|
37009
|
+
{
|
|
37010
|
+
id: "kit",
|
|
37011
|
+
master: 0.85,
|
|
37012
|
+
compressor: {
|
|
37013
|
+
threshold: -12,
|
|
37014
|
+
ratio: 5
|
|
37015
|
+
},
|
|
37016
|
+
reverb: {
|
|
37017
|
+
seconds: 2.2,
|
|
37018
|
+
decay: 3.4,
|
|
37019
|
+
wet: 0.4
|
|
37020
|
+
},
|
|
37021
|
+
noise: {
|
|
37022
|
+
seconds: 2,
|
|
37023
|
+
create: "eager"
|
|
37024
|
+
},
|
|
37025
|
+
sources: [
|
|
37026
|
+
"sdk: the art scene chain (cena L1308-L1312) with a limiter after the compressor: the page has none, and a blast with its debris and a fire catching reached +7 dBFS"
|
|
37027
|
+
],
|
|
37028
|
+
limiter: {
|
|
37029
|
+
ceiling: -1,
|
|
37030
|
+
knee: -6
|
|
37031
|
+
}
|
|
36888
37032
|
}
|
|
36889
37033
|
];
|
|
36890
37034
|
var MIX_PROFILES = Object.fromEntries(
|
|
36891
37035
|
mix_profiles_default.map((profile) => [profile.id, profile])
|
|
36892
37036
|
);
|
|
36893
|
-
var DEFAULT_MIX = "
|
|
37037
|
+
var DEFAULT_MIX = "kit";
|
|
36894
37038
|
function resolveMix(mix3, profiles = MIX_PROFILES) {
|
|
36895
37039
|
if (typeof mix3 !== "string") return mix3;
|
|
36896
37040
|
const profile = profiles[mix3];
|
|
@@ -36911,6 +37055,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
36911
37055
|
"jogo:L66986 one groan every 0.25 s (`groanBudget`), only nearer than 40 m",
|
|
36912
37056
|
"jogo:L70472 the budget counts down by the frame time"
|
|
36913
37057
|
]
|
|
37058
|
+
},
|
|
37059
|
+
fire_ignite: {
|
|
37060
|
+
maxConcurrent: 2,
|
|
37061
|
+
cooldown: 0.15,
|
|
37062
|
+
sources: [
|
|
37063
|
+
"sdk: many parts catching at once (a blast sets a shelf alight) are one or two ignitions, not forty"
|
|
37064
|
+
]
|
|
37065
|
+
},
|
|
37066
|
+
fire_crackle: {
|
|
37067
|
+
maxConcurrent: 4,
|
|
37068
|
+
sources: [
|
|
37069
|
+
"sdk: the crackles of every fire share four voices"
|
|
37070
|
+
]
|
|
36914
37071
|
}
|
|
36915
37072
|
};
|
|
36916
37073
|
var VOICE_GROUPS = voice_groups_default;
|
|
@@ -37002,6 +37159,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37002
37159
|
const sounds = /* @__PURE__ */ new Map();
|
|
37003
37160
|
const loops = /* @__PURE__ */ new Map();
|
|
37004
37161
|
const sets = /* @__PURE__ */ new Map();
|
|
37162
|
+
const samples = /* @__PURE__ */ new Map();
|
|
37005
37163
|
const owners = /* @__PURE__ */ new Map();
|
|
37006
37164
|
const registry = {
|
|
37007
37165
|
register(bank) {
|
|
@@ -37018,25 +37176,34 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37018
37176
|
sets.set(set2.id, set2);
|
|
37019
37177
|
owners.set(set2.id, bank.id);
|
|
37020
37178
|
}
|
|
37179
|
+
for (const sample of bank.samples ?? []) {
|
|
37180
|
+
samples.set(sample.id, sample);
|
|
37181
|
+
owners.set(sample.id, bank.id);
|
|
37182
|
+
}
|
|
37021
37183
|
},
|
|
37022
37184
|
patch(id, patch) {
|
|
37023
37185
|
const sound3 = sounds.get(id);
|
|
37024
37186
|
if (sound3) sounds.set(id, mergeRecords(sound3, patch));
|
|
37025
37187
|
const loop = loops.get(id);
|
|
37026
37188
|
if (loop) loops.set(id, mergeRecords(loop, patch));
|
|
37189
|
+
const sample = samples.get(id);
|
|
37190
|
+
if (sample) samples.set(id, mergeRecords(sample, patch));
|
|
37027
37191
|
},
|
|
37028
37192
|
remove(id) {
|
|
37029
37193
|
sounds.delete(id);
|
|
37030
37194
|
loops.delete(id);
|
|
37031
37195
|
sets.delete(id);
|
|
37196
|
+
samples.delete(id);
|
|
37032
37197
|
owners.delete(id);
|
|
37033
37198
|
},
|
|
37034
37199
|
sound: (id) => sounds.get(id),
|
|
37035
37200
|
loop: (id) => loops.get(id),
|
|
37036
37201
|
set: (id) => sets.get(id),
|
|
37202
|
+
sample: (id) => samples.get(id),
|
|
37037
37203
|
soundIds: () => [...sounds.keys()],
|
|
37038
37204
|
setIds: () => [...sets.keys()],
|
|
37039
37205
|
loopIds: () => [...loops.keys()],
|
|
37206
|
+
sampleIds: () => [...samples.keys()],
|
|
37040
37207
|
bankOf: (id) => owners.get(id)
|
|
37041
37208
|
};
|
|
37042
37209
|
for (const bank of banks) registry.register(bank);
|
|
@@ -37291,7 +37458,32 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37291
37458
|
channels.forEach((samples, channel) => buffer.getChannelData(channel).set(samples));
|
|
37292
37459
|
return buffer;
|
|
37293
37460
|
}
|
|
37461
|
+
var LIMITER_POINTS = 4097;
|
|
37462
|
+
function limiterCurve(ceilingDb, kneeDb, range3, points = LIMITER_POINTS) {
|
|
37463
|
+
const ceiling = 10 ** (ceilingDb / 20);
|
|
37464
|
+
const knee = Math.min(10 ** (kneeDb / 20), ceiling);
|
|
37465
|
+
const curve = new Float32Array(new ArrayBuffer(points * 4));
|
|
37466
|
+
for (let i = 0; i < points; i++) {
|
|
37467
|
+
const x = (i / (points - 1) * 2 - 1) * range3;
|
|
37468
|
+
const a = Math.abs(x);
|
|
37469
|
+
const y = a <= knee || ceiling === knee ? Math.min(a, ceiling) : knee + (ceiling - knee) * Math.tanh((a - knee) / (ceiling - knee));
|
|
37470
|
+
curve[i] = Math.sign(x) * y;
|
|
37471
|
+
}
|
|
37472
|
+
return curve;
|
|
37473
|
+
}
|
|
37294
37474
|
function buildChain(context, profile, random) {
|
|
37475
|
+
let limiter;
|
|
37476
|
+
if (profile.limiter) {
|
|
37477
|
+
const range3 = profile.limiter.range ?? 4;
|
|
37478
|
+
const input = context.createGain();
|
|
37479
|
+
input.gain.value = 1 / range3;
|
|
37480
|
+
const shaper = context.createWaveShaper();
|
|
37481
|
+
shaper.curve = limiterCurve(profile.limiter.ceiling, profile.limiter.knee, range3);
|
|
37482
|
+
input.connect(shaper);
|
|
37483
|
+
shaper.connect(context.destination);
|
|
37484
|
+
limiter = { input, shaper };
|
|
37485
|
+
}
|
|
37486
|
+
const output = limiter?.input ?? context.destination;
|
|
37295
37487
|
let compressor;
|
|
37296
37488
|
if (profile.compressor) {
|
|
37297
37489
|
compressor = context.createDynamicsCompressor();
|
|
@@ -37300,17 +37492,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37300
37492
|
if (profile.compressor.knee !== void 0) compressor.knee.value = profile.compressor.knee;
|
|
37301
37493
|
if (profile.compressor.attack !== void 0) compressor.attack.value = profile.compressor.attack;
|
|
37302
37494
|
if (profile.compressor.release !== void 0) compressor.release.value = profile.compressor.release;
|
|
37303
|
-
compressor.connect(
|
|
37495
|
+
compressor.connect(output);
|
|
37304
37496
|
}
|
|
37305
37497
|
const master = context.createGain();
|
|
37306
37498
|
master.gain.value = profile.master;
|
|
37307
|
-
master.connect(compressor ??
|
|
37499
|
+
master.connect(compressor ?? output);
|
|
37308
37500
|
if (!profile.reverb) {
|
|
37309
37501
|
return {
|
|
37310
37502
|
master,
|
|
37311
37503
|
disconnect: () => {
|
|
37312
37504
|
master.disconnect();
|
|
37313
37505
|
compressor?.disconnect();
|
|
37506
|
+
limiter?.input.disconnect();
|
|
37507
|
+
limiter?.shaper.disconnect();
|
|
37314
37508
|
}
|
|
37315
37509
|
};
|
|
37316
37510
|
}
|
|
@@ -37329,6 +37523,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37329
37523
|
convolver.disconnect();
|
|
37330
37524
|
master.disconnect();
|
|
37331
37525
|
compressor?.disconnect();
|
|
37526
|
+
limiter?.input.disconnect();
|
|
37527
|
+
limiter?.shaper.disconnect();
|
|
37332
37528
|
}
|
|
37333
37529
|
};
|
|
37334
37530
|
}
|
|
@@ -37338,7 +37534,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37338
37534
|
return Constructor ? new Constructor() : null;
|
|
37339
37535
|
}
|
|
37340
37536
|
function unlockContext(context) {
|
|
37341
|
-
if (context.state === "suspended") void context.resume();
|
|
37537
|
+
if (context.state === "suspended" && typeof context.close === "function") void context.resume();
|
|
37342
37538
|
}
|
|
37343
37539
|
var LOOP_START_ABOVE = 2e-3;
|
|
37344
37540
|
var LOOP_SMOOTHING = { volume: 0.15, frequency: 0.08 };
|
|
@@ -37410,9 +37606,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37410
37606
|
}
|
|
37411
37607
|
};
|
|
37412
37608
|
}
|
|
37609
|
+
function outputStage(recipe2, target, gain) {
|
|
37610
|
+
if (!recipe2.pan) {
|
|
37611
|
+
gain.connect(target.output);
|
|
37612
|
+
return { out: gain };
|
|
37613
|
+
}
|
|
37614
|
+
const panner = target.context.createStereoPanner();
|
|
37615
|
+
gain.connect(panner);
|
|
37616
|
+
panner.connect(target.output);
|
|
37617
|
+
return { out: panner, panner };
|
|
37618
|
+
}
|
|
37413
37619
|
var fixed = (range3) => typeof range3 === "number" ? range3 : 0;
|
|
37414
37620
|
var fixedFrequency = (automation) => fixed("set" in automation ? automation.set : automation.from);
|
|
37415
|
-
function
|
|
37621
|
+
function sourceOf2(recipe2, target) {
|
|
37416
37622
|
if (recipe2.source.kind === "noise") return { source: noiseSource(target, true) };
|
|
37417
37623
|
const oscillator = target.context.createOscillator();
|
|
37418
37624
|
oscillator.type = recipe2.source.wave;
|
|
@@ -37436,8 +37642,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37436
37642
|
gain.gain.value = 0;
|
|
37437
37643
|
const last = filters.reduce((previous, filter) => previous ? previous.connect(filter) : filter, void 0);
|
|
37438
37644
|
last?.connect(gain);
|
|
37439
|
-
|
|
37440
|
-
const { source, frequency } =
|
|
37645
|
+
const output = outputStage(recipe2, target, gain);
|
|
37646
|
+
const { source, frequency } = sourceOf2(recipe2, target);
|
|
37441
37647
|
recipe2.filters?.bank.forEach((spec, index) => {
|
|
37442
37648
|
const filter = filters[index];
|
|
37443
37649
|
filter.type = spec.type;
|
|
@@ -37463,11 +37669,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37463
37669
|
}
|
|
37464
37670
|
source.connect(filters[0] ?? gain);
|
|
37465
37671
|
source.start();
|
|
37466
|
-
return { gain, source, ...frequency ? { frequency } : {}, stop: stopAll(sources) };
|
|
37672
|
+
return { gain, ...output, source, ...frequency ? { frequency } : {}, ...filters[0] ? { cutoff: filters[0].frequency } : {}, stop: stopAll(sources) };
|
|
37467
37673
|
}
|
|
37468
37674
|
function realizeChainLoop(recipe2, target, volume) {
|
|
37469
37675
|
const { context } = target;
|
|
37470
|
-
const { source, frequency } =
|
|
37676
|
+
const { source, frequency } = sourceOf2(recipe2, target);
|
|
37471
37677
|
const filters = (recipe2.filters?.bank ?? []).map(
|
|
37472
37678
|
(spec) => filterNode(context, { type: spec.type, frequency: { value: fixedFrequency(spec.frequency) }, ...spec.q === void 0 ? {} : { q: fixed(spec.q) } }, target.time)
|
|
37473
37679
|
);
|
|
@@ -37484,10 +37690,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37484
37690
|
let tail = source;
|
|
37485
37691
|
for (const filter of filters) tail = tail.connect(filter);
|
|
37486
37692
|
tail.connect(gain);
|
|
37487
|
-
|
|
37693
|
+
const output = outputStage(recipe2, target, gain);
|
|
37488
37694
|
source.start();
|
|
37489
37695
|
for (const lfo of lfos) lfo.start();
|
|
37490
|
-
return { gain, source, ...frequency ? { frequency } : {}, stop: stopAll([source, ...lfos]) };
|
|
37696
|
+
return { gain, ...output, source, ...frequency ? { frequency } : {}, ...filters[0] ? { cutoff: filters[0].frequency } : {}, stop: stopAll([source, ...lfos]) };
|
|
37491
37697
|
}
|
|
37492
37698
|
var INERT = { set() {
|
|
37493
37699
|
}, stop() {
|
|
@@ -37505,12 +37711,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37505
37711
|
return nodes !== void 0;
|
|
37506
37712
|
},
|
|
37507
37713
|
rewire() {
|
|
37508
|
-
nodes?.
|
|
37509
|
-
nodes?.
|
|
37714
|
+
nodes?.out.disconnect();
|
|
37715
|
+
nodes?.out.connect(host.output(loopRecipe.bus));
|
|
37510
37716
|
},
|
|
37511
37717
|
stop() {
|
|
37512
37718
|
nodes?.stop();
|
|
37513
|
-
nodes?.
|
|
37719
|
+
nodes?.out.disconnect();
|
|
37514
37720
|
nodes = void 0;
|
|
37515
37721
|
state = createLoopState(loopRecipe);
|
|
37516
37722
|
host.unregister(entry2);
|
|
@@ -37530,16 +37736,250 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37530
37736
|
state = createLoopState({ ...loopRecipe, volume: opening }, true);
|
|
37531
37737
|
};
|
|
37532
37738
|
if (isChain) open();
|
|
37739
|
+
let position;
|
|
37740
|
+
let cutoff;
|
|
37741
|
+
const placed = loopRecipe.falloff !== void 0 || loopRecipe.pan === true;
|
|
37533
37742
|
return {
|
|
37534
37743
|
set(next) {
|
|
37535
37744
|
if (isChain && !nodes) open();
|
|
37536
37745
|
const context = host.ready();
|
|
37537
37746
|
if (!context) return;
|
|
37747
|
+
position = next.position ?? position;
|
|
37748
|
+
cutoff = next.cutoff ?? cutoff;
|
|
37538
37749
|
const action = state.set(next);
|
|
37539
37750
|
if (!action) return;
|
|
37540
37751
|
nodes ?? (nodes = create4(context, 0));
|
|
37541
|
-
|
|
37752
|
+
const listener = placed && position ? host.listener?.() : void 0;
|
|
37753
|
+
const distance3 = listener && position ? listenerDistance(listener, position, host.distance) : 0;
|
|
37754
|
+
const level = listener ? falloffGain(loopRecipe.falloff, action.volume, distance3) : action.volume;
|
|
37755
|
+
nodes.gain.gain.setTargetAtTime(level, context.currentTime, smoothing.volume);
|
|
37542
37756
|
if (action.frequency !== void 0 && nodes.frequency) nodes.frequency.setTargetAtTime(action.frequency, context.currentTime, smoothing.frequency);
|
|
37757
|
+
if (cutoff !== void 0 && nodes.cutoff) nodes.cutoff.setTargetAtTime(cutoff / cutoffDivisor(loopRecipe.falloff, distance3), context.currentTime, smoothing.frequency);
|
|
37758
|
+
if (listener && position && nodes.panner) nodes.panner.pan.setTargetAtTime(panFor(listener, position), context.currentTime, smoothing.frequency);
|
|
37759
|
+
},
|
|
37760
|
+
stop: entry2.stop
|
|
37761
|
+
};
|
|
37762
|
+
}
|
|
37763
|
+
var DEFAULT_SAMPLE_FALLOFF = { model: "inverse_square", k: 2e-3, minGain: 2e-3 };
|
|
37764
|
+
var DEFAULT_CROSSOVER = { from: 30, to: 80 };
|
|
37765
|
+
var DEFAULT_SAMPLE_PITCH = 0.04;
|
|
37766
|
+
var DEFAULT_TAIL_GAIN = 0.6;
|
|
37767
|
+
var DEFAULT_SAMPLE_CUTOFF_K = 0.01;
|
|
37768
|
+
var OPEN_CUTOFF = 2e4;
|
|
37769
|
+
var LAYER_FLOOR = 1e-3;
|
|
37770
|
+
function pickTake(count, last, random) {
|
|
37771
|
+
if (count <= 1) return 0;
|
|
37772
|
+
if (last === void 0 || last < 0 || last >= count) return Math.min(count - 1, Math.floor(random() * count));
|
|
37773
|
+
const drawn = Math.min(count - 2, Math.floor(random() * (count - 1)));
|
|
37774
|
+
return drawn >= last ? drawn + 1 : drawn;
|
|
37775
|
+
}
|
|
37776
|
+
function farMixAt(crossover, distance3) {
|
|
37777
|
+
if (crossover.to <= crossover.from) return distance3 >= crossover.to ? 1 : 0;
|
|
37778
|
+
const t = (distance3 - crossover.from) / (crossover.to - crossover.from);
|
|
37779
|
+
return t <= 0 ? 0 : t >= 1 ? 1 : t;
|
|
37780
|
+
}
|
|
37781
|
+
function crossGains(farMix) {
|
|
37782
|
+
return { close: Math.cos(farMix * Math.PI / 2), far: Math.sin(farMix * Math.PI / 2) };
|
|
37783
|
+
}
|
|
37784
|
+
function sampleCutoff(cutoffK, distance3, occlusion = 0) {
|
|
37785
|
+
const byDistance = cutoffK > 0 ? OPEN_CUTOFF / (1 + distance3 * cutoffK) : OPEN_CUTOFF;
|
|
37786
|
+
const occluded = occlusion > 0 ? byDistance / (1 + occlusion * 9) : byDistance;
|
|
37787
|
+
return Math.max(80, Math.min(OPEN_CUTOFF, occluded));
|
|
37788
|
+
}
|
|
37789
|
+
function sampleUrls(sound3) {
|
|
37790
|
+
const tiers = (sound3.tiers ?? []).flatMap((tier) => [...tier.close, ...tier.far ?? []]);
|
|
37791
|
+
const all = [...sound3.close, ...sound3.far ?? [], ...tiers, ...sound3.tail?.indoor ?? [], ...sound3.tail?.outdoor ?? []].map((ref) => ref.url);
|
|
37792
|
+
return [...new Set(all)];
|
|
37793
|
+
}
|
|
37794
|
+
function tierFor(sound3, intensity) {
|
|
37795
|
+
if (intensity === void 0 || !sound3.tiers) return void 0;
|
|
37796
|
+
let chosen;
|
|
37797
|
+
for (const tier of sound3.tiers) if (tier.from <= intensity) chosen = tier;
|
|
37798
|
+
return chosen ?? sound3.tiers[0];
|
|
37799
|
+
}
|
|
37800
|
+
function planSample(sound3, input) {
|
|
37801
|
+
if (sound3.close.length === 0) throw new Error(`sample sound ${sound3.id} has no close take`);
|
|
37802
|
+
const listener = input.listener ?? DEFAULT_LISTENER;
|
|
37803
|
+
const distance3 = input.distance ?? (input.position ? listenerDistance(listener, input.position, input.distanceMode) : 0);
|
|
37804
|
+
const falloff = sound3.falloff ?? DEFAULT_SAMPLE_FALLOFF;
|
|
37805
|
+
const occlusion = Math.max(0, Math.min(1, input.occlusion ?? 0));
|
|
37806
|
+
const level = falloffGain(falloff, (input.volume ?? 1) * (sound3.gain ?? 1), distance3) * (1 - 0.45 * occlusion);
|
|
37807
|
+
if (isSilent(falloff, level) || level <= 0) return null;
|
|
37808
|
+
const pitch = sound3.pitch ?? DEFAULT_SAMPLE_PITCH;
|
|
37809
|
+
const rate = pitch > 0 ? 1 + (input.random() * 2 - 1) * pitch : 1;
|
|
37810
|
+
const environment = input.environment ?? "outdoor";
|
|
37811
|
+
const tier = tierFor(sound3, input.intensity);
|
|
37812
|
+
const close = tier?.close.length ? tier.close : sound3.close;
|
|
37813
|
+
const far = tier?.far?.length ? tier.far : sound3.far ?? [];
|
|
37814
|
+
const farMix = far.length > 0 ? farMixAt(sound3.crossover ?? DEFAULT_CROSSOVER, distance3) : 0;
|
|
37815
|
+
const gains = crossGains(farMix);
|
|
37816
|
+
const layers = [];
|
|
37817
|
+
const take = (role, refs, gain, at3) => {
|
|
37818
|
+
if (refs.length === 0 || gain < LAYER_FLOOR) return;
|
|
37819
|
+
const key2 = `${sound3.id}/${tier && role !== "tail" ? `${tier.name}/` : ""}${role}`;
|
|
37820
|
+
const index = pickTake(refs.length, input.memory?.get(key2), input.random);
|
|
37821
|
+
input.memory?.set(key2, index);
|
|
37822
|
+
const ref = refs[index];
|
|
37823
|
+
layers.push({ role, url: ref.url, take: index, gain: gain * (ref.gain ?? 1) * level, rate, at: at3 });
|
|
37824
|
+
};
|
|
37825
|
+
take("close", close, gains.close, 0);
|
|
37826
|
+
take("far", far, gains.far, 0);
|
|
37827
|
+
const tails = sound3.tail?.[environment] ?? [];
|
|
37828
|
+
take("tail", tails, sound3.tail?.gain ?? DEFAULT_TAIL_GAIN, sound3.tail?.at ?? 0);
|
|
37829
|
+
const pan = (sound3.pan ?? true) && input.position ? panFor(listener, input.position) : void 0;
|
|
37830
|
+
return {
|
|
37831
|
+
kind: "sample",
|
|
37832
|
+
id: sound3.id,
|
|
37833
|
+
bus: sound3.bus,
|
|
37834
|
+
level,
|
|
37835
|
+
distance: distance3,
|
|
37836
|
+
...pan === void 0 ? {} : { pan },
|
|
37837
|
+
cutoff: sampleCutoff(sound3.cutoffK ?? DEFAULT_SAMPLE_CUTOFF_K, distance3, occlusion),
|
|
37838
|
+
rate,
|
|
37839
|
+
environment,
|
|
37840
|
+
...tier ? { tier: tier.name } : {},
|
|
37841
|
+
farMix,
|
|
37842
|
+
layers,
|
|
37843
|
+
priority: sound3.priority ?? input.priority ?? busPriority(sound3.bus),
|
|
37844
|
+
...sound3.group ? { group: sound3.group } : {}
|
|
37845
|
+
};
|
|
37846
|
+
}
|
|
37847
|
+
var DEFAULT_LOOP_CROSSFADE = 0.25;
|
|
37848
|
+
var LOOKAHEAD = 1.5;
|
|
37849
|
+
var VOLUME_SMOOTHING = 0.05;
|
|
37850
|
+
function loopCrossfade(sound3) {
|
|
37851
|
+
if (!sound3.loop) return void 0;
|
|
37852
|
+
return sound3.loop === true ? DEFAULT_LOOP_CROSSFADE : Math.max(0, sound3.loop.crossfade ?? DEFAULT_LOOP_CROSSFADE);
|
|
37853
|
+
}
|
|
37854
|
+
var CROSSFADE_STEPS = 8;
|
|
37855
|
+
var equalPowerIn = (t) => Math.sin(Math.max(0, Math.min(1, t)) * Math.PI / 2);
|
|
37856
|
+
var ramp2 = (param2, direction, at3, seconds) => {
|
|
37857
|
+
const value = (t) => direction === "in" ? equalPowerIn(t) : equalPowerIn(1 - t);
|
|
37858
|
+
param2.setValueAtTime(value(0), at3);
|
|
37859
|
+
for (let step = 1; step <= CROSSFADE_STEPS; step++) param2.linearRampToValueAtTime(value(step / CROSSFADE_STEPS), at3 + seconds * step / CROSSFADE_STEPS);
|
|
37860
|
+
};
|
|
37861
|
+
function createSampleLoopHandle(sound3, host, volume = 0) {
|
|
37862
|
+
const crossfade = loopCrossfade(sound3) ?? DEFAULT_LOOP_CROSSFADE;
|
|
37863
|
+
let level = volume;
|
|
37864
|
+
let stopped = false;
|
|
37865
|
+
let fallback2;
|
|
37866
|
+
let master;
|
|
37867
|
+
let segments = [];
|
|
37868
|
+
let last;
|
|
37869
|
+
let timer;
|
|
37870
|
+
const entry2 = {
|
|
37871
|
+
get created() {
|
|
37872
|
+
return master !== void 0;
|
|
37873
|
+
},
|
|
37874
|
+
rewire() {
|
|
37875
|
+
master?.disconnect();
|
|
37876
|
+
master?.connect(host.output(sound3.bus));
|
|
37877
|
+
},
|
|
37878
|
+
stop() {
|
|
37879
|
+
stopped = true;
|
|
37880
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
37881
|
+
timer = void 0;
|
|
37882
|
+
for (const segment of segments) {
|
|
37883
|
+
try {
|
|
37884
|
+
segment.source.stop();
|
|
37885
|
+
} catch {
|
|
37886
|
+
}
|
|
37887
|
+
segment.source.disconnect();
|
|
37888
|
+
segment.gain.disconnect();
|
|
37889
|
+
}
|
|
37890
|
+
segments = [];
|
|
37891
|
+
master?.disconnect();
|
|
37892
|
+
master = void 0;
|
|
37893
|
+
fallback2?.stop();
|
|
37894
|
+
fallback2 = void 0;
|
|
37895
|
+
host.unregister(entry2);
|
|
37896
|
+
}
|
|
37897
|
+
};
|
|
37898
|
+
const nextBuffer = () => {
|
|
37899
|
+
const takes2 = sound3.close;
|
|
37900
|
+
const take = pickTake(takes2.length, last, host.random);
|
|
37901
|
+
last = take;
|
|
37902
|
+
const ref = takes2[take];
|
|
37903
|
+
return ref ? host.buffer(ref.url) : void 0;
|
|
37904
|
+
};
|
|
37905
|
+
const schedule = (context, output, at3, first) => {
|
|
37906
|
+
const buffer = nextBuffer();
|
|
37907
|
+
if (!buffer) return void 0;
|
|
37908
|
+
const source = context.createBufferSource();
|
|
37909
|
+
source.buffer = buffer;
|
|
37910
|
+
const gain = context.createGain();
|
|
37911
|
+
source.connect(gain);
|
|
37912
|
+
gain.connect(output);
|
|
37913
|
+
const fade = Math.min(crossfade, buffer.duration / 2);
|
|
37914
|
+
if (buffer.duration < 2 * crossfade || sound3.close.length === 1) {
|
|
37915
|
+
source.loop = true;
|
|
37916
|
+
if (!first) ramp2(gain.gain, "in", at3, Math.max(1e-3, fade));
|
|
37917
|
+
source.start(at3);
|
|
37918
|
+
segments.push({ source, gain, end: Number.POSITIVE_INFINITY });
|
|
37919
|
+
return void 0;
|
|
37920
|
+
}
|
|
37921
|
+
if (first) gain.gain.setValueAtTime(1, at3);
|
|
37922
|
+
else ramp2(gain.gain, "in", at3, fade);
|
|
37923
|
+
const end3 = at3 + buffer.duration;
|
|
37924
|
+
ramp2(gain.gain, "out", end3 - fade, fade);
|
|
37925
|
+
source.start(at3);
|
|
37926
|
+
source.stop(end3);
|
|
37927
|
+
segments.push({ source, gain, end: end3 });
|
|
37928
|
+
source.onended = () => {
|
|
37929
|
+
segments = segments.filter((segment) => segment.source !== source);
|
|
37930
|
+
source.disconnect();
|
|
37931
|
+
gain.disconnect();
|
|
37932
|
+
};
|
|
37933
|
+
return end3 - fade;
|
|
37934
|
+
};
|
|
37935
|
+
const pump = (context, output, at3, first) => {
|
|
37936
|
+
if (stopped) return;
|
|
37937
|
+
let next = schedule(context, output, at3, first);
|
|
37938
|
+
while (next !== void 0 && next < context.currentTime + LOOKAHEAD) next = schedule(context, output, Math.max(next, context.currentTime), false);
|
|
37939
|
+
if (next === void 0) return;
|
|
37940
|
+
const wait = Math.max(0, (next - context.currentTime - LOOKAHEAD / 2) * 1e3);
|
|
37941
|
+
timer = setTimeout(() => {
|
|
37942
|
+
timer = void 0;
|
|
37943
|
+
pump(context, output, next, false);
|
|
37944
|
+
}, wait);
|
|
37945
|
+
};
|
|
37946
|
+
const fileLevel = () => level * (sound3.gain ?? 1);
|
|
37947
|
+
const startFiles = () => {
|
|
37948
|
+
if (stopped || master || !host.isReady(sound3)) return master !== void 0;
|
|
37949
|
+
const context = host.ready();
|
|
37950
|
+
if (!context) return false;
|
|
37951
|
+
master = context.createGain();
|
|
37952
|
+
master.gain.setValueAtTime(fileLevel(), context.currentTime);
|
|
37953
|
+
master.connect(host.output(sound3.bus));
|
|
37954
|
+
host.register(entry2);
|
|
37955
|
+
pump(context, master, context.currentTime, true);
|
|
37956
|
+
if (fallback2) {
|
|
37957
|
+
fallback2.set({ volume: 0 });
|
|
37958
|
+
const old = fallback2;
|
|
37959
|
+
fallback2 = void 0;
|
|
37960
|
+
setTimeout(() => old.stop(), VOLUME_SMOOTHING * 6e3);
|
|
37961
|
+
}
|
|
37962
|
+
return true;
|
|
37963
|
+
};
|
|
37964
|
+
const ensure = () => {
|
|
37965
|
+
if (stopped || master) return;
|
|
37966
|
+
if (startFiles()) return;
|
|
37967
|
+
if (!fallback2) {
|
|
37968
|
+
fallback2 = host.fallback(level);
|
|
37969
|
+
void host.load(sound3).then(() => {
|
|
37970
|
+
if (level > 0 || master) startFiles();
|
|
37971
|
+
}).catch(() => void 0);
|
|
37972
|
+
}
|
|
37973
|
+
};
|
|
37974
|
+
if (volume > 0) ensure();
|
|
37975
|
+
return {
|
|
37976
|
+
set(next) {
|
|
37977
|
+
if (stopped) return;
|
|
37978
|
+
if (next.volume !== void 0) level = host.muted(sound3.bus) ? 0 : Math.max(0, next.volume);
|
|
37979
|
+
if (level > 0) ensure();
|
|
37980
|
+
const context = host.ready();
|
|
37981
|
+
if (master && context) master.gain.setTargetAtTime(fileLevel(), context.currentTime, VOLUME_SMOOTHING);
|
|
37982
|
+
fallback2?.set(next.volume === void 0 ? next : { ...next, volume: level });
|
|
37543
37983
|
},
|
|
37544
37984
|
stop: entry2.stop
|
|
37545
37985
|
};
|
|
@@ -37818,7 +38258,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37818
38258
|
return voiceOf(oscillators);
|
|
37819
38259
|
}
|
|
37820
38260
|
var end2 = (layer2, start) => start + layer2.duration + layer2.tail;
|
|
37821
|
-
function
|
|
38261
|
+
function outputStage2(plan, layer2, target) {
|
|
37822
38262
|
const { context } = target;
|
|
37823
38263
|
const level = gainNode(context, layer2.level);
|
|
37824
38264
|
let node = level;
|
|
@@ -37850,7 +38290,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37850
38290
|
let tail = source;
|
|
37851
38291
|
for (const filter of filters) tail = tail.connect(filter);
|
|
37852
38292
|
tail.connect(envelope2);
|
|
37853
|
-
envelope2.connect(
|
|
38293
|
+
envelope2.connect(outputStage2(plan, layer2, target));
|
|
37854
38294
|
source.start(time, layer2.source.kind === "noise" ? layer2.source.offset : 0);
|
|
37855
38295
|
source.stop(end2(layer2, time));
|
|
37856
38296
|
return [source];
|
|
@@ -37867,7 +38307,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37867
38307
|
const envelope2 = context.createGain();
|
|
37868
38308
|
applyEnvelope(envelope2.gain, layer2.envelope, time);
|
|
37869
38309
|
oscillator.connect(envelope2);
|
|
37870
|
-
envelope2.connect(
|
|
38310
|
+
envelope2.connect(outputStage2(plan, layer2, target));
|
|
37871
38311
|
oscillator.start(time);
|
|
37872
38312
|
oscillator.stop(end2(layer2, time));
|
|
37873
38313
|
return [oscillator];
|
|
@@ -37899,7 +38339,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
37899
38339
|
const envelope2 = context.createGain();
|
|
37900
38340
|
applyEnvelope(envelope2.gain, layer2.envelope, time);
|
|
37901
38341
|
mix3.connect(envelope2);
|
|
37902
|
-
envelope2.connect(
|
|
38342
|
+
envelope2.connect(outputStage2(plan, layer2, target));
|
|
37903
38343
|
const stop = end2(layer2, time);
|
|
37904
38344
|
oscillator.start(time);
|
|
37905
38345
|
vibrato.start(time);
|
|
@@ -38071,6 +38511,135 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38071
38511
|
reset: () => last.clear()
|
|
38072
38512
|
};
|
|
38073
38513
|
}
|
|
38514
|
+
function fetchLoader(baseUrl) {
|
|
38515
|
+
return async (url2) => {
|
|
38516
|
+
const target = baseUrl ? new URL(url2, baseUrl).toString() : url2;
|
|
38517
|
+
const response = await fetch(target);
|
|
38518
|
+
if (!response.ok) throw new Error(`${response.status} ${response.statusText} for ${target}`);
|
|
38519
|
+
return response.arrayBuffer();
|
|
38520
|
+
};
|
|
38521
|
+
}
|
|
38522
|
+
var decode = (context, bytes) => new Promise((resolve2, reject) => {
|
|
38523
|
+
const result2 = context.decodeAudioData(bytes, resolve2, reject);
|
|
38524
|
+
result2?.catch?.(reject);
|
|
38525
|
+
});
|
|
38526
|
+
function createSampleStore(loader = fetchLoader()) {
|
|
38527
|
+
const buffers = /* @__PURE__ */ new Map();
|
|
38528
|
+
const pending = /* @__PURE__ */ new Map();
|
|
38529
|
+
const failed = /* @__PURE__ */ new Map();
|
|
38530
|
+
let generation = 0;
|
|
38531
|
+
const loadOne = (url2, context) => {
|
|
38532
|
+
const existing = buffers.get(url2);
|
|
38533
|
+
if (existing) return Promise.resolve(existing);
|
|
38534
|
+
const inFlight = pending.get(url2);
|
|
38535
|
+
if (inFlight) return inFlight;
|
|
38536
|
+
const started = generation;
|
|
38537
|
+
failed.delete(url2);
|
|
38538
|
+
const promise = loader(url2).then((bytes) => decode(context, bytes)).then((buffer) => {
|
|
38539
|
+
if (started === generation) buffers.set(url2, buffer);
|
|
38540
|
+
return buffer;
|
|
38541
|
+
}).catch((error) => {
|
|
38542
|
+
if (started === generation) failed.set(url2, error instanceof Error ? error.message : String(error));
|
|
38543
|
+
throw error;
|
|
38544
|
+
}).finally(() => {
|
|
38545
|
+
if (pending.get(url2) === promise) pending.delete(url2);
|
|
38546
|
+
});
|
|
38547
|
+
pending.set(url2, promise);
|
|
38548
|
+
return promise;
|
|
38549
|
+
};
|
|
38550
|
+
return {
|
|
38551
|
+
status(url2) {
|
|
38552
|
+
if (buffers.has(url2)) return "ready";
|
|
38553
|
+
if (pending.has(url2)) return "loading";
|
|
38554
|
+
if (failed.has(url2)) return "failed";
|
|
38555
|
+
return "none";
|
|
38556
|
+
},
|
|
38557
|
+
buffer: (url2) => buffers.get(url2),
|
|
38558
|
+
ready: (urls) => urls.every((url2) => buffers.has(url2)),
|
|
38559
|
+
seconds: (url2) => buffers.get(url2)?.duration,
|
|
38560
|
+
async load(urls, context) {
|
|
38561
|
+
const results = await Promise.allSettled(urls.map((url2) => loadOne(url2, context)));
|
|
38562
|
+
const loaded = [];
|
|
38563
|
+
const errors = [];
|
|
38564
|
+
results.forEach((result2, index) => {
|
|
38565
|
+
const url2 = urls[index];
|
|
38566
|
+
if (result2.status === "fulfilled") loaded.push(url2);
|
|
38567
|
+
else errors.push({ url: url2, error: result2.reason instanceof Error ? result2.reason.message : String(result2.reason) });
|
|
38568
|
+
});
|
|
38569
|
+
return { loaded, failed: errors };
|
|
38570
|
+
},
|
|
38571
|
+
clear() {
|
|
38572
|
+
generation++;
|
|
38573
|
+
buffers.clear();
|
|
38574
|
+
pending.clear();
|
|
38575
|
+
failed.clear();
|
|
38576
|
+
}
|
|
38577
|
+
};
|
|
38578
|
+
}
|
|
38579
|
+
function realizeSample(plan, target) {
|
|
38580
|
+
const context = target.context;
|
|
38581
|
+
let head = target.output;
|
|
38582
|
+
if (plan.pan !== void 0 && typeof context.createStereoPanner === "function") {
|
|
38583
|
+
const panner = context.createStereoPanner();
|
|
38584
|
+
panner.pan.value = plan.pan;
|
|
38585
|
+
panner.connect(head);
|
|
38586
|
+
head = panner;
|
|
38587
|
+
}
|
|
38588
|
+
if (plan.cutoff < OPEN_CUTOFF) {
|
|
38589
|
+
const lowpass = context.createBiquadFilter();
|
|
38590
|
+
lowpass.type = "lowpass";
|
|
38591
|
+
lowpass.frequency.value = plan.cutoff;
|
|
38592
|
+
lowpass.Q.value = 0.7;
|
|
38593
|
+
lowpass.connect(head);
|
|
38594
|
+
head = lowpass;
|
|
38595
|
+
}
|
|
38596
|
+
const voice2 = context.createGain();
|
|
38597
|
+
voice2.connect(head);
|
|
38598
|
+
head = voice2;
|
|
38599
|
+
const sources = [];
|
|
38600
|
+
for (const layer2 of plan.layers) {
|
|
38601
|
+
const buffer = target.buffer(layer2.url);
|
|
38602
|
+
if (!buffer) continue;
|
|
38603
|
+
const source = context.createBufferSource();
|
|
38604
|
+
source.buffer = buffer;
|
|
38605
|
+
source.playbackRate.value = layer2.rate;
|
|
38606
|
+
const gain = gainNode(context, layer2.gain);
|
|
38607
|
+
source.connect(gain);
|
|
38608
|
+
gain.connect(head);
|
|
38609
|
+
source.start(target.time + layer2.at);
|
|
38610
|
+
sources.push(source);
|
|
38611
|
+
}
|
|
38612
|
+
const realized = voiceOf(sources);
|
|
38613
|
+
return {
|
|
38614
|
+
...realized,
|
|
38615
|
+
fade(at3, seconds) {
|
|
38616
|
+
voice2.gain.setValueAtTime(1, at3);
|
|
38617
|
+
voice2.gain.linearRampToValueAtTime(0, at3 + seconds);
|
|
38618
|
+
for (const source of sources) {
|
|
38619
|
+
try {
|
|
38620
|
+
source.stop(at3 + seconds);
|
|
38621
|
+
} catch {
|
|
38622
|
+
}
|
|
38623
|
+
}
|
|
38624
|
+
}
|
|
38625
|
+
};
|
|
38626
|
+
}
|
|
38627
|
+
function sampleLength(plan, seconds) {
|
|
38628
|
+
let length2 = 0;
|
|
38629
|
+
for (const layer2 of plan.layers) length2 = Math.max(length2, layer2.at + (seconds(layer2.url) ?? 0) / layer2.rate);
|
|
38630
|
+
return length2;
|
|
38631
|
+
}
|
|
38632
|
+
function limiterCurve2(knee, ceiling, range3, points = 2049) {
|
|
38633
|
+
const curve = new Float32Array(points);
|
|
38634
|
+
const room = Math.max(1e-6, ceiling - knee);
|
|
38635
|
+
for (let index = 0; index < points; index++) {
|
|
38636
|
+
const value = (index / (points - 1) * 2 - 1) * range3;
|
|
38637
|
+
const size = Math.abs(value);
|
|
38638
|
+
const bent = size <= knee ? size : knee + room * Math.tanh((size - knee) / room);
|
|
38639
|
+
curve[index] = Math.sign(value) * bent;
|
|
38640
|
+
}
|
|
38641
|
+
return curve;
|
|
38642
|
+
}
|
|
38074
38643
|
var usesNoise = (recipe2) => recipe2.layers.some((layer2) => layer2.source.kind !== "osc");
|
|
38075
38644
|
var planUsesNoise = (plan) => plan.layers.some((layer2) => layer2.source.kind !== "osc");
|
|
38076
38645
|
function createAudioEngine(options = {}) {
|
|
@@ -38090,6 +38659,43 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38090
38659
|
let chain = null;
|
|
38091
38660
|
let listener = DEFAULT_LISTENER;
|
|
38092
38661
|
let lastTime = 0;
|
|
38662
|
+
let environment = options.environment ?? "outdoor";
|
|
38663
|
+
const sampleLimiters = /* @__PURE__ */ new Map();
|
|
38664
|
+
const sampleOutput = (bus) => {
|
|
38665
|
+
const setting = options.samples?.limiter;
|
|
38666
|
+
if (setting === false || !context) return outputFor(bus);
|
|
38667
|
+
const existing = sampleLimiters.get(bus);
|
|
38668
|
+
if (existing) return existing;
|
|
38669
|
+
const range3 = 4;
|
|
38670
|
+
const input = context.createGain();
|
|
38671
|
+
input.gain.value = 1 / range3;
|
|
38672
|
+
const shaper = context.createWaveShaper();
|
|
38673
|
+
shaper.curve = limiterCurve2(setting?.knee ?? 0.5, setting?.ceiling ?? 0.891, range3);
|
|
38674
|
+
ensureBus(bus);
|
|
38675
|
+
input.connect(shaper);
|
|
38676
|
+
shaper.connect(outputFor(bus));
|
|
38677
|
+
sampleLimiters.set(bus, input);
|
|
38678
|
+
return input;
|
|
38679
|
+
};
|
|
38680
|
+
const chokes = /* @__PURE__ */ new Map();
|
|
38681
|
+
const choked = (id) => {
|
|
38682
|
+
const list2 = (chokes.get(id) ?? []).filter((entry2) => active.has(entry2.id));
|
|
38683
|
+
chokes.set(id, list2);
|
|
38684
|
+
return list2;
|
|
38685
|
+
};
|
|
38686
|
+
const watchers = /* @__PURE__ */ new Set();
|
|
38687
|
+
const announce = (event) => {
|
|
38688
|
+
options.onVoiceStart?.(event);
|
|
38689
|
+
for (const watcher of watchers) watcher(event);
|
|
38690
|
+
};
|
|
38691
|
+
const sources = [];
|
|
38692
|
+
const baseLoader = options.samples?.loader ?? fetchLoader(options.samples?.baseUrl);
|
|
38693
|
+
const sampleStore = createSampleStore((url2) => (sources.find((source) => source.accepts(url2))?.loader ?? baseLoader)(url2));
|
|
38694
|
+
const memory = /* @__PURE__ */ new Map();
|
|
38695
|
+
const latencyOf = (audio) => {
|
|
38696
|
+
const live = audio;
|
|
38697
|
+
return (live.baseLatency ?? 0) + (live.outputLatency ?? 0);
|
|
38698
|
+
};
|
|
38093
38699
|
const outputFor = (bus) => busNodes.get(bus) ?? chain?.master;
|
|
38094
38700
|
const watched = /* @__PURE__ */ new Set();
|
|
38095
38701
|
const meterOf = (bus) => {
|
|
@@ -38146,17 +38752,33 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38146
38752
|
...options.occlusion && playOptions.position && recipe2.falloff?.model !== "none" ? { occlusion: options.occlusion(playOptions.position) } : {}
|
|
38147
38753
|
});
|
|
38148
38754
|
const startQueue = options.deferredStart ? createStartQueue(options.deferredStart) : null;
|
|
38149
|
-
const build = (plan, store, delay) => {
|
|
38755
|
+
const build = (plan, store, delay, requestedAt, fallbackOf) => {
|
|
38150
38756
|
const audio = context;
|
|
38151
|
-
|
|
38757
|
+
const time = audio.currentTime + delay;
|
|
38758
|
+
const realized = realize(plan, {
|
|
38152
38759
|
context: audio,
|
|
38153
38760
|
output: outputFor(plan.bus),
|
|
38154
38761
|
...chain?.wet ? { wet: chain.wet } : {},
|
|
38155
38762
|
noise: () => noiseBuffer(store, audio, mix3.noise.seconds),
|
|
38156
|
-
time
|
|
38763
|
+
time
|
|
38764
|
+
});
|
|
38765
|
+
const recipeBank = registry.bankOf(plan.id);
|
|
38766
|
+
announce({
|
|
38767
|
+
id: plan.id,
|
|
38768
|
+
kind: "recipe",
|
|
38769
|
+
...fallbackOf ? { fallbackOf } : {},
|
|
38770
|
+
...recipeBank ? { bank: recipeBank } : {},
|
|
38771
|
+
requestedAt,
|
|
38772
|
+
startAt: time,
|
|
38773
|
+
outputLatency: latencyOf(audio),
|
|
38774
|
+
level: plan.level,
|
|
38775
|
+
distance: plan.distance,
|
|
38776
|
+
...plan.pan === void 0 ? {} : { pan: plan.pan }
|
|
38157
38777
|
});
|
|
38778
|
+
return realized;
|
|
38158
38779
|
};
|
|
38159
|
-
const deferVoice = (plan, store, voiceId, delay) => {
|
|
38780
|
+
const deferVoice = (plan, store, voiceId, delay, fallbackOf) => {
|
|
38781
|
+
const requestedAt = context?.currentTime ?? 0;
|
|
38160
38782
|
let built2 = null;
|
|
38161
38783
|
let cancelled = false;
|
|
38162
38784
|
const pending = {
|
|
@@ -38170,7 +38792,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38170
38792
|
};
|
|
38171
38793
|
startQueue.push({
|
|
38172
38794
|
run() {
|
|
38173
|
-
if (!cancelled && context) built2 = build(plan, store, delay);
|
|
38795
|
+
if (!cancelled && context) built2 = build(plan, store, delay, requestedAt, fallbackOf);
|
|
38174
38796
|
},
|
|
38175
38797
|
drop() {
|
|
38176
38798
|
if (voiceId === void 0) return;
|
|
@@ -38180,13 +38802,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38180
38802
|
});
|
|
38181
38803
|
return pending;
|
|
38182
38804
|
};
|
|
38183
|
-
const start = (plan, store, voiceId, delay = 0) => {
|
|
38184
|
-
const realized = startQueue ? deferVoice(plan, store, voiceId, delay) : build(plan, store, delay);
|
|
38805
|
+
const start = (plan, store, voiceId, delay = 0, fallbackOf, urgent = false) => {
|
|
38806
|
+
const realized = startQueue && !urgent ? deferVoice(plan, store, voiceId, delay, fallbackOf) : build(plan, store, delay, context?.currentTime ?? 0, fallbackOf);
|
|
38185
38807
|
if (voiceId === void 0) return null;
|
|
38186
38808
|
voices.setLength(voiceId, plan.length + delay);
|
|
38187
38809
|
active.set(voiceId, realized);
|
|
38188
38810
|
return {
|
|
38189
38811
|
id: voiceId,
|
|
38812
|
+
kind: "recipe",
|
|
38190
38813
|
plan,
|
|
38191
38814
|
stop() {
|
|
38192
38815
|
realized.stop();
|
|
@@ -38210,7 +38833,85 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38210
38833
|
const set2 = registry.set(id);
|
|
38211
38834
|
return set2 ? chooser.pick(set2, random) : { id, rate: 1 };
|
|
38212
38835
|
};
|
|
38213
|
-
const
|
|
38836
|
+
const loadSounds = (sounds) => {
|
|
38837
|
+
const audio = ready();
|
|
38838
|
+
if (!audio) return Promise.resolve({ loaded: [], failed: sounds.flatMap(sampleUrls).map((url2) => ({ url: url2, error: "no audio context" })) });
|
|
38839
|
+
return sampleStore.load([...new Set(sounds.flatMap(sampleUrls))], audio);
|
|
38840
|
+
};
|
|
38841
|
+
const sampleInput = (playOptions, random, withMemory) => ({
|
|
38842
|
+
random,
|
|
38843
|
+
listener,
|
|
38844
|
+
environment: playOptions.environment ?? environment,
|
|
38845
|
+
...withMemory ? { memory } : {},
|
|
38846
|
+
...options.distance ? { distanceMode: options.distance } : {},
|
|
38847
|
+
...playOptions.volume === void 0 ? {} : { volume: playOptions.volume },
|
|
38848
|
+
...playOptions.intensity === void 0 ? {} : { intensity: playOptions.intensity },
|
|
38849
|
+
...playOptions.distance === void 0 ? {} : { distance: playOptions.distance },
|
|
38850
|
+
...playOptions.position ? { position: playOptions.position } : {},
|
|
38851
|
+
...playOptions.occlusion !== void 0 ? { occlusion: playOptions.occlusion } : options.occlusion && playOptions.position ? { occlusion: options.occlusion(playOptions.position) } : {}
|
|
38852
|
+
});
|
|
38853
|
+
const playSample = (sample, playOptions, random, store) => {
|
|
38854
|
+
if (busSettings.get(sample.bus)?.muted) return null;
|
|
38855
|
+
if (!sampleStore.ready(sampleUrls(sample))) {
|
|
38856
|
+
if (options.samples?.autoLoad !== false && ready()) void loadSounds([sample]).catch(() => void 0);
|
|
38857
|
+
if (sample.fallback && sample.fallback !== sample.id) return playWith(sample.fallback, playOptions, random, store, sample.id);
|
|
38858
|
+
return registry.sound(sample.id) ? void 0 : null;
|
|
38859
|
+
}
|
|
38860
|
+
const plan = planSample(sample, sampleInput(playOptions, playOptions.seed === void 0 ? random : createRng3(playOptions.seed), true));
|
|
38861
|
+
if (!plan) return null;
|
|
38862
|
+
const audio = ready();
|
|
38863
|
+
if (!audio) return null;
|
|
38864
|
+
unlockContext(audio);
|
|
38865
|
+
advance();
|
|
38866
|
+
const voiceId = admit(plan, plan.level, plan.distance);
|
|
38867
|
+
if (voiceId === null) return null;
|
|
38868
|
+
const requestedAt = audio.currentTime;
|
|
38869
|
+
const time = requestedAt + (playOptions.delay ?? 0);
|
|
38870
|
+
const chokeList = sample.choke ? choked(sample.id) : void 0;
|
|
38871
|
+
const realized = realizeSample(plan, { context: audio, output: sampleOutput(plan.bus), buffer: (url2) => sampleStore.buffer(url2), time });
|
|
38872
|
+
const sampleBank = registry.bankOf(plan.id);
|
|
38873
|
+
announce({
|
|
38874
|
+
id: plan.id,
|
|
38875
|
+
kind: "sample",
|
|
38876
|
+
...sampleBank ? { bank: sampleBank } : {},
|
|
38877
|
+
requestedAt,
|
|
38878
|
+
startAt: time,
|
|
38879
|
+
outputLatency: latencyOf(audio),
|
|
38880
|
+
level: plan.level,
|
|
38881
|
+
distance: plan.distance,
|
|
38882
|
+
...plan.pan === void 0 ? {} : { pan: plan.pan },
|
|
38883
|
+
layers: plan.layers.map((layer2) => ({ role: layer2.role, url: layer2.url, take: layer2.take, rate: layer2.rate })),
|
|
38884
|
+
...plan.tier ? { tier: plan.tier } : {}
|
|
38885
|
+
});
|
|
38886
|
+
voices.setLength(voiceId, sampleLength(plan, (url2) => sampleStore.seconds(url2)) + (playOptions.delay ?? 0));
|
|
38887
|
+
active.set(voiceId, realized);
|
|
38888
|
+
if (chokeList && sample.choke) {
|
|
38889
|
+
chokeList.push({ id: voiceId, voice: realized });
|
|
38890
|
+
while (chokeList.length > Math.max(1, sample.choke.voices)) {
|
|
38891
|
+
const oldest = chokeList.shift();
|
|
38892
|
+
if (!oldest) break;
|
|
38893
|
+
oldest.voice.fade(time, sample.choke.fade ?? 0.03);
|
|
38894
|
+
voices.release(oldest.id);
|
|
38895
|
+
active.delete(oldest.id);
|
|
38896
|
+
}
|
|
38897
|
+
}
|
|
38898
|
+
return {
|
|
38899
|
+
id: voiceId,
|
|
38900
|
+
kind: "sample",
|
|
38901
|
+
plan,
|
|
38902
|
+
stop() {
|
|
38903
|
+
realized.stop();
|
|
38904
|
+
voices.release(voiceId);
|
|
38905
|
+
active.delete(voiceId);
|
|
38906
|
+
}
|
|
38907
|
+
};
|
|
38908
|
+
};
|
|
38909
|
+
const playWith = (asked, playOptions, streamRandom, store, fallbackOf) => {
|
|
38910
|
+
const sample = fallbackOf === void 0 ? registry.sample(asked) : void 0;
|
|
38911
|
+
if (sample) {
|
|
38912
|
+
const played = playSample(sample, playOptions, streamRandom, store);
|
|
38913
|
+
if (played !== void 0) return played;
|
|
38914
|
+
}
|
|
38214
38915
|
const seeded = playOptions.seed === void 0 ? null : createRng3(playOptions.seed);
|
|
38215
38916
|
const { id, rate } = resolve2(asked, seeded ?? streamRandom);
|
|
38216
38917
|
const random = seeded ?? streamRandom;
|
|
@@ -38228,7 +38929,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38228
38929
|
if (voiceId === null) return null;
|
|
38229
38930
|
if (!silent && usesNoise(recipe2)) prepareNoise(store, audio, mix3.noise.seconds);
|
|
38230
38931
|
const plan = planSound(recipe2, inputFor(recipe2, playOptions, random));
|
|
38231
|
-
return plan ? start(retunePlan(plan, rate), store, voiceId, playOptions.delay) : null;
|
|
38932
|
+
return plan ? start(retunePlan(plan, rate), store, voiceId, playOptions.delay, fallbackOf, playOptions.urgent) : null;
|
|
38232
38933
|
};
|
|
38233
38934
|
const randomFor = (playOptions) => {
|
|
38234
38935
|
if (playOptions.channel === void 0) return engineRandom;
|
|
@@ -38250,12 +38951,42 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38250
38951
|
prepareNoise: () => context && prepareNoise(shared2, context, mix3.noise.seconds),
|
|
38251
38952
|
noise: () => noiseBuffer(shared2, context, mix3.noise.seconds),
|
|
38252
38953
|
register: (loop) => void loops.add(loop),
|
|
38253
|
-
unregister: (loop) => void loops.delete(loop)
|
|
38954
|
+
unregister: (loop) => void loops.delete(loop),
|
|
38955
|
+
listener: () => listener,
|
|
38956
|
+
...options.distance ? { distance: options.distance } : {}
|
|
38254
38957
|
};
|
|
38255
38958
|
return {
|
|
38256
38959
|
registry,
|
|
38257
38960
|
register: (bank) => registry.register(bank),
|
|
38258
38961
|
plan: (id, playOptions = {}) => planWith(id, playOptions, createRng3(playOptions.seed ?? seed)),
|
|
38962
|
+
planSample(id, playOptions = {}) {
|
|
38963
|
+
const sample = registry.sample(id);
|
|
38964
|
+
return sample ? planSample(sample, sampleInput(playOptions, createRng3(playOptions.seed ?? seed), false)) : null;
|
|
38965
|
+
},
|
|
38966
|
+
loadSamples(ids) {
|
|
38967
|
+
const chosen = (ids ?? registry.sampleIds()).map((id) => registry.sample(id)).filter((sample) => sample !== void 0);
|
|
38968
|
+
return loadSounds(chosen);
|
|
38969
|
+
},
|
|
38970
|
+
sampleStatus(id) {
|
|
38971
|
+
const sample = registry.sample(id);
|
|
38972
|
+
if (!sample) return "none";
|
|
38973
|
+
const statuses = sampleUrls(sample).map((url2) => sampleStore.status(url2));
|
|
38974
|
+
if (statuses.every((status) => status === "ready")) return "ready";
|
|
38975
|
+
if (statuses.includes("failed")) return "failed";
|
|
38976
|
+
if (statuses.includes("loading")) return "loading";
|
|
38977
|
+
return statuses.includes("ready") ? "loading" : "none";
|
|
38978
|
+
},
|
|
38979
|
+
setEnvironment(next) {
|
|
38980
|
+
environment = next;
|
|
38981
|
+
},
|
|
38982
|
+
output: () => chain?.master ?? null,
|
|
38983
|
+
addSampleSource(accepts, loader) {
|
|
38984
|
+
sources.push({ accepts, loader });
|
|
38985
|
+
},
|
|
38986
|
+
watchVoices(listener2) {
|
|
38987
|
+
watchers.add(listener2);
|
|
38988
|
+
return () => void watchers.delete(listener2);
|
|
38989
|
+
},
|
|
38259
38990
|
play: (id, playOptions = {}) => playWith(id, playOptions, randomFor(playOptions), shared2),
|
|
38260
38991
|
playPlan(plan, playOptions = {}) {
|
|
38261
38992
|
const audio = ready();
|
|
@@ -38267,7 +38998,26 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38267
38998
|
if (planUsesNoise(plan)) prepareNoise(shared2, audio, mix3.noise.seconds);
|
|
38268
38999
|
return start(plan, shared2, voiceId, playOptions.delay);
|
|
38269
39000
|
},
|
|
38270
|
-
loop
|
|
39001
|
+
loop(id, loopOptions = {}) {
|
|
39002
|
+
const sample = registry.sample(id);
|
|
39003
|
+
if (!sample?.loop) return createLoopHandle(registry.loop(id), loopHost, loopOptions.volume);
|
|
39004
|
+
return createSampleLoopHandle(
|
|
39005
|
+
sample,
|
|
39006
|
+
{
|
|
39007
|
+
ready,
|
|
39008
|
+
output: sampleOutput,
|
|
39009
|
+
buffer: (url2) => sampleStore.buffer(url2),
|
|
39010
|
+
isReady: (sound3) => sampleStore.ready(sampleUrls(sound3)),
|
|
39011
|
+
load: (sound3) => options.samples?.autoLoad === false ? Promise.resolve() : loadSounds([sound3]),
|
|
39012
|
+
fallback: (volume) => createLoopHandle(registry.loop(sample.fallback ?? sample.id) ?? registry.loop(sample.id), loopHost, volume),
|
|
39013
|
+
random: engineRandom,
|
|
39014
|
+
register: loopHost.register,
|
|
39015
|
+
unregister: loopHost.unregister,
|
|
39016
|
+
muted: (bus) => busSettings.get(bus)?.muted === true
|
|
39017
|
+
},
|
|
39018
|
+
loopOptions.volume
|
|
39019
|
+
);
|
|
39020
|
+
},
|
|
38271
39021
|
channel(channelOptions) {
|
|
38272
39022
|
const random = channelOptions.random ?? (channelOptions.seed === void 0 ? engineRandom : createRng3(channelOptions.seed));
|
|
38273
39023
|
const store = channelOptions.ownNoise ? createNoiseStore(random) : shared2;
|
|
@@ -38348,6 +39098,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38348
39098
|
busNodes.clear();
|
|
38349
39099
|
meters.clear();
|
|
38350
39100
|
shared2.reset();
|
|
39101
|
+
sampleStore.clear();
|
|
39102
|
+
memory.clear();
|
|
39103
|
+
sampleLimiters.clear();
|
|
39104
|
+
chokes.clear();
|
|
38351
39105
|
}
|
|
38352
39106
|
};
|
|
38353
39107
|
}
|
|
@@ -38396,6 +39150,420 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38396
39150
|
}
|
|
38397
39151
|
]
|
|
38398
39152
|
};
|
|
39153
|
+
var entries = (category, list2) => list2.map(([id, priority, current]) => ({ id, category, priority, ...current ? { current } : {} }));
|
|
39154
|
+
var SFX_CATALOG = [
|
|
39155
|
+
...entries("armas", [
|
|
39156
|
+
["pistol_22lr", 2, "sfx_pistol"],
|
|
39157
|
+
["pistol_9mm", 1, "sfx_pistol"],
|
|
39158
|
+
["pistol_45", 1, "sfx_pistol"],
|
|
39159
|
+
["revolver_38_357", 2, "sfx_pistol"],
|
|
39160
|
+
["revolver_44_50ae", 3, "sfx_pistol"],
|
|
39161
|
+
["smg_9mm_auto", 1, "sfx_pistol"],
|
|
39162
|
+
["shotgun_12", 1, "sfx_shotgun"],
|
|
39163
|
+
["rifle_5_56", 1, "sfx_rifle"],
|
|
39164
|
+
["rifle_7_62x39", 1, "sfx_rifle"],
|
|
39165
|
+
["rifle_auto_burst", 1, "sfx_rifle"],
|
|
39166
|
+
["rifle_308_3006", 2, "sfx_rifle"],
|
|
39167
|
+
["sniper_338_300wm", 2, "sfx_rifle"],
|
|
39168
|
+
["antimateriel_50bmg", 3, "sfx_rifle"],
|
|
39169
|
+
["suppressed_pistol", 2],
|
|
39170
|
+
["suppressed_rifle", 2],
|
|
39171
|
+
["gunshot_far_pistol", 1],
|
|
39172
|
+
["gunshot_far_rifle", 1],
|
|
39173
|
+
["gunshot_far_shotgun", 1],
|
|
39174
|
+
["gunshot_far_heavy", 2],
|
|
39175
|
+
["gunshot_tail_indoor", 1],
|
|
39176
|
+
["gunshot_tail_outdoor", 1],
|
|
39177
|
+
["bullet_crack_by", 2],
|
|
39178
|
+
["bullet_whiz", 2],
|
|
39179
|
+
["ricochet_metal", 2, "ping"],
|
|
39180
|
+
["dry_fire", 1],
|
|
39181
|
+
["mag_out", 1],
|
|
39182
|
+
["mag_in", 1],
|
|
39183
|
+
["slide_pull_release", 1],
|
|
39184
|
+
["pump_cycle", 1],
|
|
39185
|
+
["casing_drop_concreto_pistol", 1],
|
|
39186
|
+
["casing_drop_concreto_rifle", 1],
|
|
39187
|
+
["casing_drop_concreto_shell", 1],
|
|
39188
|
+
["casing_drop_madeira_pistol", 1],
|
|
39189
|
+
["casing_drop_madeira_rifle", 1],
|
|
39190
|
+
["casing_drop_madeira_shell", 1],
|
|
39191
|
+
["casing_drop_metal_pistol", 1],
|
|
39192
|
+
["casing_drop_metal_rifle", 1],
|
|
39193
|
+
["casing_drop_metal_shell", 1],
|
|
39194
|
+
["casing_drop_terra_pistol", 1],
|
|
39195
|
+
["casing_drop_terra_rifle", 1],
|
|
39196
|
+
["casing_drop_terra_shell", 1],
|
|
39197
|
+
["rocket_fire", 2],
|
|
39198
|
+
["smg_45_auto", 2, "sfx_pistol"],
|
|
39199
|
+
["weapon_draw", 2],
|
|
39200
|
+
["suppressor_attach", 3],
|
|
39201
|
+
["suppressor_detach", 3]
|
|
39202
|
+
]),
|
|
39203
|
+
...entries("explosoes-fogo", [
|
|
39204
|
+
["explosion_grenade", 1, "boom"],
|
|
39205
|
+
["explosion_big", 1, "boom_big"],
|
|
39206
|
+
["explosion_car", 2, "boom_big"],
|
|
39207
|
+
["explosion_far", 1],
|
|
39208
|
+
["debris_rain_stone", 1],
|
|
39209
|
+
["molotov_break_ignite", 1, "glass_shatter"],
|
|
39210
|
+
["fire_ignite", 1, "hiss"],
|
|
39211
|
+
["fire_loop_small", 1],
|
|
39212
|
+
["fire_loop_large", 1],
|
|
39213
|
+
["fire_extinguish", 2, "hiss"],
|
|
39214
|
+
["gas_leak_hiss", 2],
|
|
39215
|
+
["structure_collapse", 2, "crumble"],
|
|
39216
|
+
["grenade_bounce", 1],
|
|
39217
|
+
["c4_plant", 2],
|
|
39218
|
+
["c4_beep", 2],
|
|
39219
|
+
["c4_disarm", 2]
|
|
39220
|
+
]),
|
|
39221
|
+
...entries("personagem", [
|
|
39222
|
+
["footstep_concrete_walk", 1, "sfx_step"],
|
|
39223
|
+
["footstep_wood_walk", 1, "sfx_step"],
|
|
39224
|
+
["footstep_dirt_walk", 1, "sfx_step"],
|
|
39225
|
+
["footstep_grass_walk", 1, "sfx_step"],
|
|
39226
|
+
["footstep_gravel_walk", 1, "sfx_step"],
|
|
39227
|
+
["land_concrete", 1, "sfx_step"],
|
|
39228
|
+
["punch_swing", 1],
|
|
39229
|
+
["punch_hit_body", 1, "sfx_flesh"],
|
|
39230
|
+
["kick_hit", 1, "sfx_flesh"],
|
|
39231
|
+
["knife_stab", 1],
|
|
39232
|
+
["blunt_hit", 1],
|
|
39233
|
+
["bite", 1, "sfx_flesh"],
|
|
39234
|
+
["body_fall", 1],
|
|
39235
|
+
["player_hurt", 2],
|
|
39236
|
+
["footstep_tile_walk", 1, "sfx_step"],
|
|
39237
|
+
["footstep_water_walk", 1, "sfx_step"],
|
|
39238
|
+
["footstep_grate_walk", 2, "sfx_step"],
|
|
39239
|
+
["footstep_duct_walk", 3, "sfx_step"],
|
|
39240
|
+
["ladder_climb", 2],
|
|
39241
|
+
["swim", 2],
|
|
39242
|
+
["zombie_groan", 1],
|
|
39243
|
+
["zombie_alert", 1],
|
|
39244
|
+
["zombie_attack", 1],
|
|
39245
|
+
["zombie_pain", 1],
|
|
39246
|
+
["zombie_claw_hit", 1, "sfx_flesh"],
|
|
39247
|
+
["zombie_claw_miss", 2]
|
|
39248
|
+
]),
|
|
39249
|
+
...entries("veiculos", [
|
|
39250
|
+
["engine_loop_car", 1],
|
|
39251
|
+
["engine_start", 1],
|
|
39252
|
+
["crash_light", 1, "crash"],
|
|
39253
|
+
["crash_heavy", 1, "crash"],
|
|
39254
|
+
["car_door_open", 1, "latch"],
|
|
39255
|
+
["car_door_close", 1, "shut_metal"],
|
|
39256
|
+
["horn_car", 2, "horn"],
|
|
39257
|
+
["tire_skid_asphalt", 2]
|
|
39258
|
+
]),
|
|
39259
|
+
...entries("itens-portas", [
|
|
39260
|
+
["item_pickup_metal", 1],
|
|
39261
|
+
["can_open", 1],
|
|
39262
|
+
["can_crush", 1],
|
|
39263
|
+
["door_wood_open", 1, "latch"],
|
|
39264
|
+
["door_wood_close", 1, "shut_wood"],
|
|
39265
|
+
["door_creak", 1, "creak_wood"],
|
|
39266
|
+
["door_locked_rattle", 1, "rattle"],
|
|
39267
|
+
["drawer_open", 2, "slide"],
|
|
39268
|
+
["fridge_close", 2, "shut_metal"]
|
|
39269
|
+
]),
|
|
39270
|
+
...entries("ambiente", [
|
|
39271
|
+
["rain_loop", 2],
|
|
39272
|
+
["wind_loop", 2],
|
|
39273
|
+
["thunder_near", 2],
|
|
39274
|
+
["thunder_far", 2],
|
|
39275
|
+
["water_splash", 2],
|
|
39276
|
+
["helicopter_loop", 3]
|
|
39277
|
+
])
|
|
39278
|
+
];
|
|
39279
|
+
var SFX_MATERIALS = [
|
|
39280
|
+
["steel", "metal"],
|
|
39281
|
+
["aluminium", "metal"],
|
|
39282
|
+
["wood", "wood"],
|
|
39283
|
+
["plywood", "wood"],
|
|
39284
|
+
["mdf", "wood"],
|
|
39285
|
+
["glass", "glass"],
|
|
39286
|
+
["tempered_glass", "glass"],
|
|
39287
|
+
["ceramic", "glass"],
|
|
39288
|
+
["concrete", "masonry"],
|
|
39289
|
+
["brick", "masonry"],
|
|
39290
|
+
["plaster", "masonry"],
|
|
39291
|
+
["plastic", "soft"],
|
|
39292
|
+
["fabric", "soft"],
|
|
39293
|
+
["paper", "soft"],
|
|
39294
|
+
["foliage", "soft"],
|
|
39295
|
+
["soil", "soft"],
|
|
39296
|
+
["flesh", "soft"]
|
|
39297
|
+
];
|
|
39298
|
+
var SFX_BLOWS = ["bullet", "blunt", "blade", "break", "drag"];
|
|
39299
|
+
var CURRENT_BY_GROUP = {
|
|
39300
|
+
metal: { bullet: "clang", blunt: "clang", blade: "clang", break: "clang", drag: "drag_metal" },
|
|
39301
|
+
wood: { bullet: "wood_hit", blunt: "wood_hit", blade: "wood_hit", break: "crack", drag: "drag_wood" },
|
|
39302
|
+
glass: { bullet: "ping", blunt: "ping", break: "glass_shatter", drag: "drag_glass" },
|
|
39303
|
+
masonry: { bullet: "chip", blunt: "chip", blade: "chip", break: "crumble", drag: "drag_masonry" },
|
|
39304
|
+
soft: { bullet: "thud", blunt: "thud", blade: "thud", break: "thud", drag: "drag_soft" }
|
|
39305
|
+
};
|
|
39306
|
+
var impactSoundId = (material, blow3) => `impact_${material}_${blow3}`;
|
|
39307
|
+
var SFX_IMPACTS = SFX_MATERIALS.flatMap(
|
|
39308
|
+
([material, group]) => SFX_BLOWS.map((blow3) => {
|
|
39309
|
+
const current = CURRENT_BY_GROUP[group]?.[blow3];
|
|
39310
|
+
return { id: impactSoundId(material, blow3), category: "impactos", priority: ["steel", "wood", "glass", "concrete", "brick", "soil", "flesh"].includes(material) && blow3 === "bullet" ? 1 : 2, ...current ? { current } : {} };
|
|
39311
|
+
})
|
|
39312
|
+
);
|
|
39313
|
+
var CALIBRATION_ID = "calibration_shot";
|
|
39314
|
+
var PREFIX = "calibration/";
|
|
39315
|
+
var url = (name) => `${PREFIX}${name}`;
|
|
39316
|
+
var CALIBRATION_SOUND = {
|
|
39317
|
+
id: CALIBRATION_ID,
|
|
39318
|
+
bus: "weapons",
|
|
39319
|
+
close: ["close_1.wav", "close_2.wav", "close_3.wav", "close_4.wav"].map((name) => ({ url: url(name) })),
|
|
39320
|
+
far: ["far_1.wav", "far_2.wav"].map((name) => ({ url: url(name) })),
|
|
39321
|
+
tiers: [
|
|
39322
|
+
{ name: "light", from: 0, close: ["light_1.wav", "light_2.wav"].map((name) => ({ url: url(name) })) },
|
|
39323
|
+
{ name: "medium", from: 0.34, close: ["close_1.wav", "close_2.wav", "close_3.wav", "close_4.wav"].map((name) => ({ url: url(name) })) },
|
|
39324
|
+
{ name: "heavy", from: 0.67, close: ["heavy_1.wav", "heavy_2.wav"].map((name) => ({ url: url(name) })) }
|
|
39325
|
+
],
|
|
39326
|
+
tail: { indoor: [{ url: url("tail_in.wav") }], outdoor: [{ url: url("tail_out.wav") }] },
|
|
39327
|
+
pitch: 0.04,
|
|
39328
|
+
choke: { voices: 2 },
|
|
39329
|
+
fallback: "sfx_pistol",
|
|
39330
|
+
sources: ["sdk: calibration takes synthesized by the harness (measure/calibration.ts), no file, no licence"]
|
|
39331
|
+
};
|
|
39332
|
+
var CALIBRATION_LOOP_ID = "calibration_loop";
|
|
39333
|
+
var CALIBRATION_LOOP_SOUND = {
|
|
39334
|
+
id: CALIBRATION_LOOP_ID,
|
|
39335
|
+
bus: "ambience",
|
|
39336
|
+
close: ["loop_1.wav", "loop_2.wav", "loop_3.wav"].map((name) => ({ url: url(name) })),
|
|
39337
|
+
loop: { crossfade: 0.15 },
|
|
39338
|
+
sources: ["sdk: calibration takes synthesized by the harness (measure/calibration.ts), no file, no licence"]
|
|
39339
|
+
};
|
|
39340
|
+
var CRITERIA_TARGETS = {
|
|
39341
|
+
/** C1: event to the first sample, and onset to the peak (one 60 fps frame). */
|
|
39342
|
+
syncMs: 20,
|
|
39343
|
+
peakAfterOnsetMs: 1e3 / 60,
|
|
39344
|
+
/** C3: distances measured, metres. */
|
|
39345
|
+
distances: [1, 10, 50, 200],
|
|
39346
|
+
/** C5: plays, distinct takes and the pitch range (fraction). */
|
|
39347
|
+
plays: 10,
|
|
39348
|
+
minTakes: 4,
|
|
39349
|
+
pitch: [0.03, 0.05],
|
|
39350
|
+
/** C6: the highest peak, dBFS. */
|
|
39351
|
+
peakDb: -1,
|
|
39352
|
+
/** C8: the end of each file against its peak, dB. */
|
|
39353
|
+
endDropDb: -40,
|
|
39354
|
+
/** C9: a burst of rapid fire. */
|
|
39355
|
+
burst: 20,
|
|
39356
|
+
burstSpacing: 0.06
|
|
39357
|
+
};
|
|
39358
|
+
var SFX_TIERS = { light: 0, medium: 0.34, heavy: 0.67 };
|
|
39359
|
+
function splitTier(id) {
|
|
39360
|
+
const match = /^(.*)_(light|medium|heavy)$/.exec(id);
|
|
39361
|
+
return match ? { base: match[1], tier: match[2] } : { base: id };
|
|
39362
|
+
}
|
|
39363
|
+
var refsOf = (entries2, baseUrl) => (entries2 ?? []).map((entry2) => ({ url: `${baseUrl}${entry2.file}` }));
|
|
39364
|
+
function sampleBankFromManifest(manifest, options) {
|
|
39365
|
+
const baseUrl = options.baseUrl ?? "";
|
|
39366
|
+
const samples = [];
|
|
39367
|
+
const tiersOf = /* @__PURE__ */ new Map();
|
|
39368
|
+
for (const sound3 of manifest.sounds) {
|
|
39369
|
+
const { base, tier } = splitTier(sound3.id);
|
|
39370
|
+
if (tier) tiersOf.set(base, [...tiersOf.get(base) ?? [], sound3]);
|
|
39371
|
+
}
|
|
39372
|
+
const bases = /* @__PURE__ */ new Map();
|
|
39373
|
+
for (const sound3 of manifest.sounds) {
|
|
39374
|
+
if (!splitTier(sound3.id).tier) bases.set(sound3.id, sound3);
|
|
39375
|
+
}
|
|
39376
|
+
for (const [base, tiers] of tiersOf) {
|
|
39377
|
+
if (!bases.has(base)) bases.set(base, { id: base, category: tiers[0]?.category ?? "", layers: { close: tiers[0]?.layers.close ?? [] } });
|
|
39378
|
+
}
|
|
39379
|
+
for (const sound3 of bases.values()) {
|
|
39380
|
+
const numbers = options.sounds?.[sound3.id] ?? options.defaults?.(sound3);
|
|
39381
|
+
const close = refsOf(sound3.layers.close, baseUrl);
|
|
39382
|
+
if (!numbers || close.length === 0) continue;
|
|
39383
|
+
const tiers = (tiersOf.get(sound3.id) ?? []).map((tier) => {
|
|
39384
|
+
const name = splitTier(tier.id).tier;
|
|
39385
|
+
const tierFar = refsOf(tier.layers.far, baseUrl);
|
|
39386
|
+
return { name, from: SFX_TIERS[name] ?? 0, close: refsOf(tier.layers.close, baseUrl), ...tierFar.length > 0 ? { far: tierFar } : {} };
|
|
39387
|
+
}).sort((a, b) => a.from - b.from);
|
|
39388
|
+
const far = refsOf(sound3.layers.far, baseUrl);
|
|
39389
|
+
const indoor = refsOf(sound3.layers.tail_in, baseUrl);
|
|
39390
|
+
const outdoor = refsOf(sound3.layers.tail_out, baseUrl);
|
|
39391
|
+
const files = [sound3, ...tiersOf.get(sound3.id) ?? []].flatMap((entry2) => Object.values(entry2.layers).flatMap((entries2) => entries2 ?? []));
|
|
39392
|
+
samples.push({
|
|
39393
|
+
id: sound3.id,
|
|
39394
|
+
bus: numbers.bus,
|
|
39395
|
+
close,
|
|
39396
|
+
...far.length > 0 ? { far } : {},
|
|
39397
|
+
...tiers.length > 0 ? { tiers } : {},
|
|
39398
|
+
...numbers.crossover ? { crossover: numbers.crossover } : {},
|
|
39399
|
+
...indoor.length > 0 || outdoor.length > 0 ? { tail: { ...indoor.length > 0 ? { indoor } : {}, ...outdoor.length > 0 ? { outdoor } : {}, ...numbers.tailGain === void 0 ? {} : { gain: numbers.tailGain } } } : {},
|
|
39400
|
+
...numbers.pitch === void 0 ? {} : { pitch: numbers.pitch },
|
|
39401
|
+
...numbers.gain === void 0 ? {} : { gain: numbers.gain },
|
|
39402
|
+
...numbers.falloff ? { falloff: numbers.falloff } : {},
|
|
39403
|
+
...numbers.cutoffK === void 0 ? {} : { cutoffK: numbers.cutoffK },
|
|
39404
|
+
...numbers.group ? { group: numbers.group } : {},
|
|
39405
|
+
...numbers.priority === void 0 ? {} : { priority: numbers.priority },
|
|
39406
|
+
...numbers.fallback ? { fallback: numbers.fallback } : {},
|
|
39407
|
+
sources: files.map((file) => `${file.file}: ${file.source} ${file.author} ${file.license}`)
|
|
39408
|
+
});
|
|
39409
|
+
}
|
|
39410
|
+
return { id: options.id, samples };
|
|
39411
|
+
}
|
|
39412
|
+
var PT = {
|
|
39413
|
+
group: "Som",
|
|
39414
|
+
name: "Painel de som (arquivos e C1\u2013C10)",
|
|
39415
|
+
controls: {
|
|
39416
|
+
category: "1 \xB7 Categoria",
|
|
39417
|
+
sound: "1 \xB7 Som",
|
|
39418
|
+
play: "1 \xB7 \u25B6 Tocar",
|
|
39419
|
+
play_user: "1 \xB7 \u25B6 Tocar o seu",
|
|
39420
|
+
material: "2 \xB7 Material",
|
|
39421
|
+
blow: "2 \xB7 Golpe",
|
|
39422
|
+
strike: "2 \xB7 \u25B6 Tocar golpe",
|
|
39423
|
+
distance: "3 \xB7 Dist\xE2ncia",
|
|
39424
|
+
bearing: "3 \xB7 Dire\xE7\xE3o",
|
|
39425
|
+
environment: "3 \xB7 Lugar",
|
|
39426
|
+
strength: "3 \xB7 For\xE7a",
|
|
39427
|
+
wall: "3 \xB7 Atr\xE1s da parede",
|
|
39428
|
+
burst: "3 \xB7 Rajada 20\xD7",
|
|
39429
|
+
play_a: "4 \xB7 \u25B6 A (atual)",
|
|
39430
|
+
play_b: "4 \xB7 \u25B6 B (novo)",
|
|
39431
|
+
ab_cycle: "4 \xB7 Alternar A/B",
|
|
39432
|
+
blind: "4 \xB7 \xC0s cegas (X)",
|
|
39433
|
+
reveal: "4 \xB7 Revelar X",
|
|
39434
|
+
prefer_a: "4 \xB7 Prefiro A",
|
|
39435
|
+
prefer_b: "4 \xB7 Prefiro B",
|
|
39436
|
+
measure: "5 \xB7 Medir C1\u2013C10",
|
|
39437
|
+
record: "5 \xB7 Gravar 3 s",
|
|
39438
|
+
approve: "5 \xB7 Aprovo (C10)"
|
|
39439
|
+
},
|
|
39440
|
+
hints: {
|
|
39441
|
+
play_user: "Toca a sua grava\xE7\xE3o deste som (dos seus pacotes, fora do git), mesmo quando o SDK tem uma melhor e toca na frente.",
|
|
39442
|
+
sound: "A = arquivo, S = sintetizado, F = faltando. O que tem arquivo toca o arquivo; o resto toca o som atual.",
|
|
39443
|
+
strike: "Toca impact_<material>_<golpe>: o arquivo se existir, sen\xE3o o som atual daquele material.",
|
|
39444
|
+
wall: "P\xF5e a parede de casa entre voc\xEA e a fonte: o som fica abafado (C4).",
|
|
39445
|
+
burst: "Vinte vezes a cada 60 ms, como uma rajada (C9).",
|
|
39446
|
+
ab_cycle: "A, B, A, B, um por segundo.",
|
|
39447
|
+
blind: "Toca A ou B sem dizer qual; depois revele.",
|
|
39448
|
+
measure: "Mede o som escolhido no motor real (contexto offline): sincronia, som certo, dist\xE2ncia, lado, varia\xE7\xE3o, volume, for\xE7a, cauda e rajada.",
|
|
39449
|
+
record: "Grava 3 s da sa\xEDda com o som tocando e baixa o arquivo (C10).",
|
|
39450
|
+
approve: "Marca o C10 do som escolhido como aprovado pelo seu ouvido."
|
|
39451
|
+
},
|
|
39452
|
+
categories: {
|
|
39453
|
+
armas: "Armas",
|
|
39454
|
+
impactos: "Impactos",
|
|
39455
|
+
"explosoes-fogo": "Explos\xF5es e fogo",
|
|
39456
|
+
personagem: "Personagem",
|
|
39457
|
+
veiculos: "Ve\xEDculos",
|
|
39458
|
+
"itens-portas": "Itens e portas",
|
|
39459
|
+
ambiente: "Ambiente",
|
|
39460
|
+
calibracao: "Calibra\xE7\xE3o (SDK)"
|
|
39461
|
+
},
|
|
39462
|
+
blows: { bullet: "tiro", blunt: "soco/chute", blade: "faca", break: "quebra", drag: "arrasto/queda" },
|
|
39463
|
+
materials: {
|
|
39464
|
+
steel: "a\xE7o",
|
|
39465
|
+
aluminium: "alum\xEDnio",
|
|
39466
|
+
wood: "madeira",
|
|
39467
|
+
plywood: "compensado",
|
|
39468
|
+
mdf: "MDF",
|
|
39469
|
+
glass: "vidro",
|
|
39470
|
+
tempered_glass: "vidro temperado",
|
|
39471
|
+
ceramic: "cer\xE2mica",
|
|
39472
|
+
concrete: "concreto",
|
|
39473
|
+
brick: "tijolo",
|
|
39474
|
+
plaster: "gesso",
|
|
39475
|
+
plastic: "pl\xE1stico",
|
|
39476
|
+
fabric: "tecido",
|
|
39477
|
+
paper: "papel\xE3o",
|
|
39478
|
+
foliage: "folhagem",
|
|
39479
|
+
soil: "terra",
|
|
39480
|
+
flesh: "carne"
|
|
39481
|
+
},
|
|
39482
|
+
environments: { indoor: "interior", outdoor: "exterior" },
|
|
39483
|
+
strengths: { light: "leve", medium: "m\xE9dio", heavy: "forte" },
|
|
39484
|
+
states: { file: "A", synth: "S", missing: "F" },
|
|
39485
|
+
criteria: { C1: "C1 Sincronia", C2: "C2 Certo p/ a\xE7\xE3o", C3: "C3 Dist\xE2ncia", C4: "C4 Posi\xE7\xE3o", C5: "C5 Varia\xE7\xE3o", C6: "C6 Volume", C7: "C7 Intensidade", C8: "C8 Cauda", C9: "C9 Rajada", C10: "C10 Escuta" },
|
|
39486
|
+
metrics: { source: "1 \xB7 Fonte do que tocou", chosen: "1 \xB7 Escolhido", matrix: "2 \xB7 Matriz", last: "\xDAltimo tocado", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Prefer\xEAncias", state: "5 \xB7 Medi\xE7\xE3o", count: "1 \xB7 Cat\xE1logo" },
|
|
39487
|
+
run: { idle: "parada", measuring: "medindo\u2026", done: "pronta", failed: "falhou", recording: "gravando\u2026", recorded: "grava\xE7\xE3o baixada" },
|
|
39488
|
+
words: { none: "\u2014", hidden: "? (revele)", prefers: "prefere", approved: "aprovado pelo dono" },
|
|
39489
|
+
sources: { sdk: "SDK", user: "seu som", synth: "sintetizado" },
|
|
39490
|
+
probe: "Fonte do som",
|
|
39491
|
+
wall: "Parede (oclus\xE3o)",
|
|
39492
|
+
scenarios: { pipeline: "Arquivo \u2192 decodifica \u2192 toca (round-robin, cauda)", criteria: "Crit\xE9rios C1\u2013C9 no som de calibra\xE7\xE3o", loop: "Loop de arquivo: emenda sem buraco (crossfade)", panel: "Painel: categorias, matriz, A/B e parede" }
|
|
39493
|
+
};
|
|
39494
|
+
var EN2 = {
|
|
39495
|
+
...PT,
|
|
39496
|
+
group: "Sound",
|
|
39497
|
+
name: "Sound panel (files and C1\u2013C10)",
|
|
39498
|
+
controls: {
|
|
39499
|
+
category: "1 \xB7 Category",
|
|
39500
|
+
sound: "1 \xB7 Sound",
|
|
39501
|
+
play: "1 \xB7 \u25B6 Play",
|
|
39502
|
+
play_user: "1 \xB7 \u25B6 Play yours",
|
|
39503
|
+
material: "2 \xB7 Material",
|
|
39504
|
+
blow: "2 \xB7 Blow",
|
|
39505
|
+
strike: "2 \xB7 \u25B6 Play blow",
|
|
39506
|
+
distance: "3 \xB7 Distance",
|
|
39507
|
+
bearing: "3 \xB7 Bearing",
|
|
39508
|
+
environment: "3 \xB7 Place",
|
|
39509
|
+
strength: "3 \xB7 Strength",
|
|
39510
|
+
wall: "3 \xB7 Behind the wall",
|
|
39511
|
+
burst: "3 \xB7 Burst 20\xD7",
|
|
39512
|
+
play_a: "4 \xB7 \u25B6 A (current)",
|
|
39513
|
+
play_b: "4 \xB7 \u25B6 B (new)",
|
|
39514
|
+
ab_cycle: "4 \xB7 Alternate A/B",
|
|
39515
|
+
blind: "4 \xB7 Blind (X)",
|
|
39516
|
+
reveal: "4 \xB7 Reveal X",
|
|
39517
|
+
prefer_a: "4 \xB7 Prefer A",
|
|
39518
|
+
prefer_b: "4 \xB7 Prefer B",
|
|
39519
|
+
measure: "5 \xB7 Measure C1\u2013C10",
|
|
39520
|
+
record: "5 \xB7 Record 3 s",
|
|
39521
|
+
approve: "5 \xB7 Approve (C10)"
|
|
39522
|
+
},
|
|
39523
|
+
hints: {
|
|
39524
|
+
play_user: "Plays your own take of this sound (from your packs, kept out of git), even where the SDK has a better one that plays first.",
|
|
39525
|
+
sound: "A = file, S = synthesized, F = missing. A file plays the file; the rest plays the current sound.",
|
|
39526
|
+
strike: "Plays impact_<material>_<blow>: the file if there is one, else the current sound of that material.",
|
|
39527
|
+
wall: "Puts the house wall between you and the source: the sound is muffled (C4).",
|
|
39528
|
+
burst: "Twenty times every 60 ms, like a burst (C9).",
|
|
39529
|
+
ab_cycle: "A, B, A, B, one a second.",
|
|
39530
|
+
blind: "Plays A or B without saying which; reveal it after.",
|
|
39531
|
+
measure: "Measures the chosen sound through the real engine (offline context): sync, right sound, distance, side, variation, level, strength, tail and burst.",
|
|
39532
|
+
record: "Records 3 s of the output with the sound playing and downloads it (C10).",
|
|
39533
|
+
approve: "Marks C10 of the chosen sound as approved by your ear."
|
|
39534
|
+
},
|
|
39535
|
+
categories: { armas: "Weapons", impactos: "Impacts", "explosoes-fogo": "Explosions and fire", personagem: "Character", veiculos: "Vehicles", "itens-portas": "Items and doors", ambiente: "Ambience", calibracao: "Calibration (SDK)" },
|
|
39536
|
+
blows: { bullet: "bullet", blunt: "punch/kick", blade: "knife", break: "break", drag: "drag/fall" },
|
|
39537
|
+
materials: {
|
|
39538
|
+
steel: "steel",
|
|
39539
|
+
aluminium: "aluminium",
|
|
39540
|
+
wood: "wood",
|
|
39541
|
+
plywood: "plywood",
|
|
39542
|
+
mdf: "MDF",
|
|
39543
|
+
glass: "glass",
|
|
39544
|
+
tempered_glass: "tempered glass",
|
|
39545
|
+
ceramic: "ceramic",
|
|
39546
|
+
concrete: "concrete",
|
|
39547
|
+
brick: "brick",
|
|
39548
|
+
plaster: "plaster",
|
|
39549
|
+
plastic: "plastic",
|
|
39550
|
+
fabric: "fabric",
|
|
39551
|
+
paper: "cardboard",
|
|
39552
|
+
foliage: "foliage",
|
|
39553
|
+
soil: "soil",
|
|
39554
|
+
flesh: "flesh"
|
|
39555
|
+
},
|
|
39556
|
+
environments: { indoor: "indoor", outdoor: "outdoor" },
|
|
39557
|
+
strengths: { light: "light", medium: "medium", heavy: "heavy" },
|
|
39558
|
+
criteria: { C1: "C1 Sync", C2: "C2 Right sound", C3: "C3 Distance", C4: "C4 Position", C5: "C5 Variation", C6: "C6 Level", C7: "C7 Strength", C8: "C8 Tail", C9: "C9 Burst", C10: "C10 Listening" },
|
|
39559
|
+
metrics: { source: "1 \xB7 Source of what played", chosen: "1 \xB7 Chosen", matrix: "2 \xB7 Matrix", last: "Last played", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Preferences", state: "5 \xB7 Measurement", count: "1 \xB7 Catalogue" },
|
|
39560
|
+
run: { idle: "idle", measuring: "measuring\u2026", done: "done", failed: "failed", recording: "recording\u2026", recorded: "recording downloaded" },
|
|
39561
|
+
words: { none: "\u2014", hidden: "? (reveal)", prefers: "prefers", approved: "approved by the owner" },
|
|
39562
|
+
sources: { sdk: "SDK", user: "your sound", synth: "synthesized" },
|
|
39563
|
+
probe: "Sound source",
|
|
39564
|
+
wall: "Wall (occlusion)",
|
|
39565
|
+
scenarios: { pipeline: "File \u2192 decode \u2192 play (round-robin, tail)", criteria: "Criteria C1\u2013C9 on the calibration sound", loop: "File loop: seamless joins (crossfade)", panel: "Panel: categories, matrix, A/B and wall" }
|
|
39566
|
+
};
|
|
38399
39567
|
|
|
38400
39568
|
// ../game-audio/dist/index.js
|
|
38401
39569
|
var ATTACK = 2e-3;
|
|
@@ -38460,6 +39628,570 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38460
39628
|
]
|
|
38461
39629
|
};
|
|
38462
39630
|
}
|
|
39631
|
+
var sceneMany = (count, make3) => Array.from({ length: count }, make3);
|
|
39632
|
+
var FOLEY_FALLOFF = {
|
|
39633
|
+
model: "inverse_square",
|
|
39634
|
+
k: 0.02,
|
|
39635
|
+
cutoffK: 0.04,
|
|
39636
|
+
minGain: 4e-3
|
|
39637
|
+
};
|
|
39638
|
+
var vary = (f, pct = 0.04) => [Math.round(f * (1 - pct)), Math.round(f * (1 + pct))];
|
|
39639
|
+
var foley = (id, layers, note2) => ({
|
|
39640
|
+
id,
|
|
39641
|
+
bus: "world",
|
|
39642
|
+
pan: true,
|
|
39643
|
+
layers,
|
|
39644
|
+
falloff: FOLEY_FALLOFF,
|
|
39645
|
+
sources: [`sdk: ${note2}`]
|
|
39646
|
+
});
|
|
39647
|
+
var click = (f, vol, delay = 0) => [
|
|
39648
|
+
sceneNoise({
|
|
39649
|
+
type: "bandpass",
|
|
39650
|
+
f: vary(f, 0.08),
|
|
39651
|
+
q: 4,
|
|
39652
|
+
d: [0.018, 0.03],
|
|
39653
|
+
vol: [vol * 0.85, vol * 1.1],
|
|
39654
|
+
delay
|
|
39655
|
+
}),
|
|
39656
|
+
sceneTone({
|
|
39657
|
+
f: vary(f * 0.8, 0.06),
|
|
39658
|
+
f2: Math.round(f * 0.62),
|
|
39659
|
+
d: [0.015, 0.025],
|
|
39660
|
+
vol: vol * 0.18,
|
|
39661
|
+
delay
|
|
39662
|
+
})
|
|
39663
|
+
];
|
|
39664
|
+
var meet = (body, panel, vol, latch) => [
|
|
39665
|
+
sceneTone({
|
|
39666
|
+
f: vary(body),
|
|
39667
|
+
f2: Math.round(body * 0.5),
|
|
39668
|
+
d: [0.12, 0.16],
|
|
39669
|
+
vol: [vol * 0.9, vol * 1.1]
|
|
39670
|
+
}),
|
|
39671
|
+
sceneNoise({
|
|
39672
|
+
type: "bandpass",
|
|
39673
|
+
f: vary(panel, 0.06),
|
|
39674
|
+
q: 1.2,
|
|
39675
|
+
d: [0.08, 0.12],
|
|
39676
|
+
vol: [vol * 0.9, vol * 1.1],
|
|
39677
|
+
wet: 0.25
|
|
39678
|
+
}),
|
|
39679
|
+
...click(latch, vol * 0.45, [0.012, 0.028])
|
|
39680
|
+
];
|
|
39681
|
+
var LEAF_FOLEY = [
|
|
39682
|
+
// a wooden house door or wardrobe door: latch, a short creak, the leaf on the frame (the hard slam adds the frame rattling)
|
|
39683
|
+
foley("door_wood_open", click(2400, 0.4), "the latch of a wooden door giving"),
|
|
39684
|
+
foley(
|
|
39685
|
+
"door_creak",
|
|
39686
|
+
[
|
|
39687
|
+
sceneTone({ f: [190, 240], f2: 310, d: [0.4, 0.55], vol: [0.04, 0.06] }),
|
|
39688
|
+
sceneNoise({
|
|
39689
|
+
type: "bandpass",
|
|
39690
|
+
f: [480, 560],
|
|
39691
|
+
q: 6,
|
|
39692
|
+
a: 0.05,
|
|
39693
|
+
d: [0.35, 0.5],
|
|
39694
|
+
vol: [0.1, 0.14]
|
|
39695
|
+
})
|
|
39696
|
+
],
|
|
39697
|
+
"a wooden hinge turning"
|
|
39698
|
+
),
|
|
39699
|
+
foley("door_wood_close", meet(120, 600, 0.55, 2400), "a wooden leaf meeting its frame"),
|
|
39700
|
+
foley(
|
|
39701
|
+
"door_wood_slam",
|
|
39702
|
+
[
|
|
39703
|
+
...meet(110, 560, 0.85, 2300),
|
|
39704
|
+
...sceneMany(
|
|
39705
|
+
3,
|
|
39706
|
+
() => sceneNoise({
|
|
39707
|
+
type: "bandpass",
|
|
39708
|
+
f: [900, 1500],
|
|
39709
|
+
q: 3,
|
|
39710
|
+
d: 0.03,
|
|
39711
|
+
vol: [0.08, 0.14],
|
|
39712
|
+
delay: [0.05, 0.18]
|
|
39713
|
+
})
|
|
39714
|
+
)
|
|
39715
|
+
],
|
|
39716
|
+
"a wooden door slammed: the frame and the hinges rattle after the hit"
|
|
39717
|
+
),
|
|
39718
|
+
// a metal door or gate: a hollow panel that rings a little
|
|
39719
|
+
foley("door_metal_open_close", [...meet(160, 900, 0.55, 2e3), sceneTone({ f: vary(1250), f2: 1150, d: [0.1, 0.16], vol: 0.06, wet: 0.3 })], "a metal door or gate meeting its frame"),
|
|
39720
|
+
foley(
|
|
39721
|
+
"door_creak_metal",
|
|
39722
|
+
[
|
|
39723
|
+
sceneTone({ f: [620, 760], f2: 900, d: [0.3, 0.4], vol: [0.03, 0.045] }),
|
|
39724
|
+
sceneNoise({
|
|
39725
|
+
type: "bandpass",
|
|
39726
|
+
f: [1300, 1500],
|
|
39727
|
+
q: 8,
|
|
39728
|
+
a: 0.04,
|
|
39729
|
+
d: [0.25, 0.35],
|
|
39730
|
+
vol: [0.07, 0.09]
|
|
39731
|
+
})
|
|
39732
|
+
],
|
|
39733
|
+
"a metal hinge turning"
|
|
39734
|
+
),
|
|
39735
|
+
// the handle of a locked door shaken: the latch knocking in its keeper, five to seven times in half a second
|
|
39736
|
+
foley(
|
|
39737
|
+
"door_locked_rattle",
|
|
39738
|
+
[
|
|
39739
|
+
...sceneMany(
|
|
39740
|
+
6,
|
|
39741
|
+
() => sceneNoise({
|
|
39742
|
+
type: "bandpass",
|
|
39743
|
+
f: [1600, 2600],
|
|
39744
|
+
q: 3,
|
|
39745
|
+
d: [0.025, 0.04],
|
|
39746
|
+
vol: [0.22, 0.34],
|
|
39747
|
+
delay: [0, 0.45]
|
|
39748
|
+
})
|
|
39749
|
+
),
|
|
39750
|
+
...sceneMany(
|
|
39751
|
+
3,
|
|
39752
|
+
() => sceneTone({
|
|
39753
|
+
f: [170, 210],
|
|
39754
|
+
f2: 120,
|
|
39755
|
+
d: 0.05,
|
|
39756
|
+
vol: [0.12, 0.18],
|
|
39757
|
+
delay: [0.02, 0.4]
|
|
39758
|
+
})
|
|
39759
|
+
)
|
|
39760
|
+
],
|
|
39761
|
+
"the handle of a locked door shaken: latch knocks and the leaf thumping in its frame"
|
|
39762
|
+
),
|
|
39763
|
+
// a fridge: the rubber seal lets go with a soft suck, the bottles in the door clink; closing it is a soft thump and the seal pulling shut
|
|
39764
|
+
foley(
|
|
39765
|
+
"fridge_open",
|
|
39766
|
+
[
|
|
39767
|
+
sceneNoise({
|
|
39768
|
+
type: "lowpass",
|
|
39769
|
+
f: [320, 380],
|
|
39770
|
+
a: 0.03,
|
|
39771
|
+
d: [0.14, 0.2],
|
|
39772
|
+
vol: [0.32, 0.4]
|
|
39773
|
+
}),
|
|
39774
|
+
sceneNoise({
|
|
39775
|
+
type: "bandpass",
|
|
39776
|
+
f: [800, 950],
|
|
39777
|
+
f2: 1400,
|
|
39778
|
+
q: 2,
|
|
39779
|
+
a: 0.02,
|
|
39780
|
+
d: 0.12,
|
|
39781
|
+
vol: [0.08, 0.12]
|
|
39782
|
+
}),
|
|
39783
|
+
...sceneMany(
|
|
39784
|
+
2,
|
|
39785
|
+
() => sceneTone({
|
|
39786
|
+
f: [2600, 4200],
|
|
39787
|
+
d: [0.04, 0.08],
|
|
39788
|
+
vol: [0.015, 0.03],
|
|
39789
|
+
delay: [0.08, 0.22]
|
|
39790
|
+
})
|
|
39791
|
+
)
|
|
39792
|
+
],
|
|
39793
|
+
"a fridge door: the seal letting go and the bottles in the door"
|
|
39794
|
+
),
|
|
39795
|
+
foley(
|
|
39796
|
+
"fridge_close",
|
|
39797
|
+
[
|
|
39798
|
+
sceneTone({ f: vary(85), f2: 45, d: [0.1, 0.13], vol: [0.38, 0.46] }),
|
|
39799
|
+
sceneNoise({
|
|
39800
|
+
type: "lowpass",
|
|
39801
|
+
f: [520, 620],
|
|
39802
|
+
d: [0.08, 0.12],
|
|
39803
|
+
vol: [0.3, 0.36]
|
|
39804
|
+
}),
|
|
39805
|
+
sceneNoise({
|
|
39806
|
+
type: "lowpass",
|
|
39807
|
+
f: [260, 320],
|
|
39808
|
+
a: 0.02,
|
|
39809
|
+
d: 0.1,
|
|
39810
|
+
vol: [0.12, 0.18],
|
|
39811
|
+
delay: [0.04, 0.07]
|
|
39812
|
+
}),
|
|
39813
|
+
...sceneMany(
|
|
39814
|
+
2,
|
|
39815
|
+
() => sceneTone({
|
|
39816
|
+
f: [2600, 4200],
|
|
39817
|
+
d: [0.04, 0.07],
|
|
39818
|
+
vol: [0.015, 0.03],
|
|
39819
|
+
delay: [0.03, 0.12]
|
|
39820
|
+
})
|
|
39821
|
+
)
|
|
39822
|
+
],
|
|
39823
|
+
"a fridge door shut: a soft thump, the seal pulling and the bottles"
|
|
39824
|
+
),
|
|
39825
|
+
// a microwave: the spring catch of the door, plastic on plastic
|
|
39826
|
+
foley(
|
|
39827
|
+
"microwave_open",
|
|
39828
|
+
[
|
|
39829
|
+
...click(1800, 0.34),
|
|
39830
|
+
sceneTone({
|
|
39831
|
+
f: [3e3, 3400],
|
|
39832
|
+
f2: 2800,
|
|
39833
|
+
d: 0.05,
|
|
39834
|
+
vol: 0.025,
|
|
39835
|
+
delay: [0.01, 0.02]
|
|
39836
|
+
})
|
|
39837
|
+
],
|
|
39838
|
+
"the spring catch of a microwave door"
|
|
39839
|
+
),
|
|
39840
|
+
foley(
|
|
39841
|
+
"microwave_close",
|
|
39842
|
+
[
|
|
39843
|
+
sceneNoise({
|
|
39844
|
+
type: "bandpass",
|
|
39845
|
+
f: [1200, 1450],
|
|
39846
|
+
q: 2.5,
|
|
39847
|
+
d: [0.04, 0.06],
|
|
39848
|
+
vol: [0.36, 0.44]
|
|
39849
|
+
}),
|
|
39850
|
+
sceneTone({ f: vary(180), f2: 120, d: 0.05, vol: [0.16, 0.22] }),
|
|
39851
|
+
...click(2200, 0.2, [8e-3, 0.016])
|
|
39852
|
+
],
|
|
39853
|
+
"a microwave door clacking shut"
|
|
39854
|
+
),
|
|
39855
|
+
foley("microwave_beep", [sceneTone({ wave: "square", f: 2e3, d: 0.12, vol: 0.05 })], "the beep of a microwave"),
|
|
39856
|
+
// drawers and sliding leaves: the runners, then the stop
|
|
39857
|
+
foley(
|
|
39858
|
+
"drawer_open",
|
|
39859
|
+
[
|
|
39860
|
+
sceneNoise({
|
|
39861
|
+
type: "bandpass",
|
|
39862
|
+
f: [620, 780],
|
|
39863
|
+
q: 2,
|
|
39864
|
+
a: 0.04,
|
|
39865
|
+
d: [0.28, 0.36],
|
|
39866
|
+
vol: [0.18, 0.24]
|
|
39867
|
+
}),
|
|
39868
|
+
sceneNoise({ type: "bandpass", f: [2e3, 2400], q: 5, d: 0.28, vol: 0.04 }),
|
|
39869
|
+
...click(1400, 0.16, [0.28, 0.34])
|
|
39870
|
+
],
|
|
39871
|
+
"a drawer on its runners and its stop"
|
|
39872
|
+
),
|
|
39873
|
+
foley(
|
|
39874
|
+
"drawer_close",
|
|
39875
|
+
[
|
|
39876
|
+
sceneNoise({
|
|
39877
|
+
type: "bandpass",
|
|
39878
|
+
f: [620, 780],
|
|
39879
|
+
q: 2,
|
|
39880
|
+
a: 0.03,
|
|
39881
|
+
d: [0.2, 0.28],
|
|
39882
|
+
vol: [0.18, 0.24]
|
|
39883
|
+
}),
|
|
39884
|
+
sceneTone({
|
|
39885
|
+
f: vary(150),
|
|
39886
|
+
f2: 90,
|
|
39887
|
+
d: 0.08,
|
|
39888
|
+
vol: [0.22, 0.3],
|
|
39889
|
+
delay: [0.2, 0.26]
|
|
39890
|
+
})
|
|
39891
|
+
],
|
|
39892
|
+
"a drawer pushed home"
|
|
39893
|
+
)
|
|
39894
|
+
];
|
|
39895
|
+
var ITEM_FOLEY = [
|
|
39896
|
+
// the hand closing on the item: a touch of skin and cloth, then the item's own small sound
|
|
39897
|
+
foley(
|
|
39898
|
+
"item_pickup_metal",
|
|
39899
|
+
[
|
|
39900
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
|
|
39901
|
+
sceneTone({
|
|
39902
|
+
f: [1900, 2600],
|
|
39903
|
+
f2: 1700,
|
|
39904
|
+
d: [0.05, 0.08],
|
|
39905
|
+
vol: [0.06, 0.09],
|
|
39906
|
+
delay: [0.01, 0.03]
|
|
39907
|
+
})
|
|
39908
|
+
],
|
|
39909
|
+
"picking up a metal thing"
|
|
39910
|
+
),
|
|
39911
|
+
foley(
|
|
39912
|
+
"item_pickup_plastic",
|
|
39913
|
+
[
|
|
39914
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
|
|
39915
|
+
sceneNoise({
|
|
39916
|
+
type: "bandpass",
|
|
39917
|
+
f: [1500, 1900],
|
|
39918
|
+
q: 3,
|
|
39919
|
+
d: 0.03,
|
|
39920
|
+
vol: [0.15, 0.21],
|
|
39921
|
+
delay: [0.01, 0.03]
|
|
39922
|
+
})
|
|
39923
|
+
],
|
|
39924
|
+
"picking up a plastic thing"
|
|
39925
|
+
),
|
|
39926
|
+
foley(
|
|
39927
|
+
"item_pickup_glass",
|
|
39928
|
+
[
|
|
39929
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.15 }),
|
|
39930
|
+
sceneTone({
|
|
39931
|
+
f: [3200, 4200],
|
|
39932
|
+
d: [0.05, 0.08],
|
|
39933
|
+
vol: [0.038, 0.06],
|
|
39934
|
+
delay: [0.01, 0.03]
|
|
39935
|
+
})
|
|
39936
|
+
],
|
|
39937
|
+
"picking up a glass thing"
|
|
39938
|
+
),
|
|
39939
|
+
foley(
|
|
39940
|
+
"item_pickup_paper",
|
|
39941
|
+
[
|
|
39942
|
+
sceneNoise({
|
|
39943
|
+
type: "highpass",
|
|
39944
|
+
f: [2600, 3400],
|
|
39945
|
+
a: 0.01,
|
|
39946
|
+
d: [0.1, 0.14],
|
|
39947
|
+
vol: [0.12, 0.18]
|
|
39948
|
+
}),
|
|
39949
|
+
sceneNoise({ type: "bandpass", f: [800, 1e3], q: 1, d: 0.05, vol: 0.12 })
|
|
39950
|
+
],
|
|
39951
|
+
"picking up paper or cardboard"
|
|
39952
|
+
),
|
|
39953
|
+
foley(
|
|
39954
|
+
"item_pickup_fabric",
|
|
39955
|
+
[
|
|
39956
|
+
sceneNoise({
|
|
39957
|
+
type: "bandpass",
|
|
39958
|
+
f: [900, 1300],
|
|
39959
|
+
q: 0.8,
|
|
39960
|
+
a: 0.02,
|
|
39961
|
+
d: [0.12, 0.16],
|
|
39962
|
+
vol: [0.15, 0.21]
|
|
39963
|
+
})
|
|
39964
|
+
],
|
|
39965
|
+
"picking up cloth"
|
|
39966
|
+
),
|
|
39967
|
+
foley(
|
|
39968
|
+
"item_pickup_wood",
|
|
39969
|
+
[
|
|
39970
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
|
|
39971
|
+
sceneNoise({
|
|
39972
|
+
type: "bandpass",
|
|
39973
|
+
f: [900, 1100],
|
|
39974
|
+
q: 2,
|
|
39975
|
+
d: 0.04,
|
|
39976
|
+
vol: [0.15, 0.21],
|
|
39977
|
+
delay: [0.01, 0.03]
|
|
39978
|
+
})
|
|
39979
|
+
],
|
|
39980
|
+
"picking up a wooden thing"
|
|
39981
|
+
),
|
|
39982
|
+
foley(
|
|
39983
|
+
"item_pickup_food",
|
|
39984
|
+
[
|
|
39985
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
|
|
39986
|
+
sceneNoise({
|
|
39987
|
+
type: "lowpass",
|
|
39988
|
+
f: [500, 650],
|
|
39989
|
+
d: 0.05,
|
|
39990
|
+
vol: 0.12,
|
|
39991
|
+
delay: [0.01, 0.03]
|
|
39992
|
+
})
|
|
39993
|
+
],
|
|
39994
|
+
"picking up food"
|
|
39995
|
+
),
|
|
39996
|
+
foley(
|
|
39997
|
+
"item_throw",
|
|
39998
|
+
[
|
|
39999
|
+
sceneNoise({
|
|
40000
|
+
type: "bandpass",
|
|
40001
|
+
f: [450, 650],
|
|
40002
|
+
f2: 1400,
|
|
40003
|
+
q: 1.5,
|
|
40004
|
+
a: 0.05,
|
|
40005
|
+
d: 0.18,
|
|
40006
|
+
vol: [0.1, 0.14]
|
|
40007
|
+
})
|
|
40008
|
+
],
|
|
40009
|
+
"the arm throwing something: air"
|
|
40010
|
+
),
|
|
40011
|
+
// a can: the tab cracks, the gas hisses out; drinking is gulps; crushing it crumples the sheet
|
|
40012
|
+
foley(
|
|
40013
|
+
"can_open",
|
|
40014
|
+
[
|
|
40015
|
+
...click(3200, 0.36),
|
|
40016
|
+
sceneNoise({
|
|
40017
|
+
type: "highpass",
|
|
40018
|
+
f: [3600, 4400],
|
|
40019
|
+
a: 5e-3,
|
|
40020
|
+
d: [0.22, 0.3],
|
|
40021
|
+
vol: [0.16, 0.22],
|
|
40022
|
+
delay: [0.012, 0.02]
|
|
40023
|
+
}),
|
|
40024
|
+
...sceneMany(5, () => sceneTone({ f: [4e3, 7e3], d: 0.02, vol: 0.01, delay: [0.05, 0.4] }))
|
|
40025
|
+
],
|
|
40026
|
+
"the tab of a can and the gas hissing out"
|
|
40027
|
+
),
|
|
40028
|
+
foley(
|
|
40029
|
+
"can_crush",
|
|
40030
|
+
[
|
|
40031
|
+
sceneNoise({
|
|
40032
|
+
type: "bandpass",
|
|
40033
|
+
f: [1600, 2200],
|
|
40034
|
+
q: 1.2,
|
|
40035
|
+
d: [0.18, 0.25],
|
|
40036
|
+
vol: [0.3, 0.38]
|
|
40037
|
+
}),
|
|
40038
|
+
...sceneMany(
|
|
40039
|
+
6,
|
|
40040
|
+
() => sceneTone({
|
|
40041
|
+
f: [1200, 3400],
|
|
40042
|
+
f2: 900,
|
|
40043
|
+
d: 0.03,
|
|
40044
|
+
vol: [0.03, 0.06],
|
|
40045
|
+
delay: [0, 0.2]
|
|
40046
|
+
})
|
|
40047
|
+
)
|
|
40048
|
+
],
|
|
40049
|
+
"a can crushed in the hand"
|
|
40050
|
+
),
|
|
40051
|
+
foley(
|
|
40052
|
+
"can_puncture_spray",
|
|
40053
|
+
[
|
|
40054
|
+
sceneNoise({
|
|
40055
|
+
type: "highpass",
|
|
40056
|
+
f: [2400, 3e3],
|
|
40057
|
+
a: 5e-3,
|
|
40058
|
+
d: [0.5, 0.7],
|
|
40059
|
+
vol: [0.2, 0.26]
|
|
40060
|
+
}),
|
|
40061
|
+
sceneNoise({ type: "bandpass", f: [600, 800], q: 2, d: 0.4, vol: 0.06 })
|
|
40062
|
+
],
|
|
40063
|
+
"a can holed: the jet hissing out"
|
|
40064
|
+
),
|
|
40065
|
+
foley(
|
|
40066
|
+
"bottle_open",
|
|
40067
|
+
[
|
|
40068
|
+
...sceneMany(
|
|
40069
|
+
5,
|
|
40070
|
+
() => sceneNoise({
|
|
40071
|
+
type: "bandpass",
|
|
40072
|
+
f: [2200, 3e3],
|
|
40073
|
+
q: 4,
|
|
40074
|
+
d: 8e-3,
|
|
40075
|
+
vol: [0.1, 0.16],
|
|
40076
|
+
delay: [0, 0.18]
|
|
40077
|
+
})
|
|
40078
|
+
),
|
|
40079
|
+
sceneNoise({
|
|
40080
|
+
type: "highpass",
|
|
40081
|
+
f: 3800,
|
|
40082
|
+
a: 5e-3,
|
|
40083
|
+
d: 0.12,
|
|
40084
|
+
vol: [0.06, 0.1],
|
|
40085
|
+
delay: [0.18, 0.22]
|
|
40086
|
+
})
|
|
40087
|
+
],
|
|
40088
|
+
"the screw cap of a bottle turning off"
|
|
40089
|
+
),
|
|
40090
|
+
foley(
|
|
40091
|
+
"drink_gulp",
|
|
40092
|
+
[
|
|
40093
|
+
sceneNoise({
|
|
40094
|
+
type: "lowpass",
|
|
40095
|
+
f: [280, 360],
|
|
40096
|
+
a: 0.02,
|
|
40097
|
+
d: [0.1, 0.14],
|
|
40098
|
+
vol: [0.24, 0.3]
|
|
40099
|
+
}),
|
|
40100
|
+
sceneTone({ f: [140, 170], f2: 85, d: [0.08, 0.11], vol: [0.12, 0.16] })
|
|
40101
|
+
],
|
|
40102
|
+
"a gulp"
|
|
40103
|
+
),
|
|
40104
|
+
foley(
|
|
40105
|
+
"eat_crunch",
|
|
40106
|
+
[
|
|
40107
|
+
...sceneMany(
|
|
40108
|
+
4,
|
|
40109
|
+
() => sceneNoise({
|
|
40110
|
+
type: "bandpass",
|
|
40111
|
+
f: [1800, 3200],
|
|
40112
|
+
q: 1.5,
|
|
40113
|
+
d: [0.02, 0.04],
|
|
40114
|
+
vol: [0.12, 0.2],
|
|
40115
|
+
delay: [0, 0.12]
|
|
40116
|
+
})
|
|
40117
|
+
)
|
|
40118
|
+
],
|
|
40119
|
+
"a bite of something crunchy"
|
|
40120
|
+
),
|
|
40121
|
+
foley(
|
|
40122
|
+
"eat_chew",
|
|
40123
|
+
[
|
|
40124
|
+
sceneNoise({
|
|
40125
|
+
type: "lowpass",
|
|
40126
|
+
f: [450, 600],
|
|
40127
|
+
a: 0.03,
|
|
40128
|
+
d: [0.1, 0.14],
|
|
40129
|
+
vol: [0.12, 0.16]
|
|
40130
|
+
}),
|
|
40131
|
+
sceneNoise({
|
|
40132
|
+
type: "bandpass",
|
|
40133
|
+
f: [1100, 1400],
|
|
40134
|
+
q: 2,
|
|
40135
|
+
d: 0.04,
|
|
40136
|
+
vol: 0.04,
|
|
40137
|
+
delay: [0.03, 0.06]
|
|
40138
|
+
})
|
|
40139
|
+
],
|
|
40140
|
+
"chewing"
|
|
40141
|
+
),
|
|
40142
|
+
foley(
|
|
40143
|
+
"bandage_wrap",
|
|
40144
|
+
[
|
|
40145
|
+
sceneNoise({
|
|
40146
|
+
type: "bandpass",
|
|
40147
|
+
f: [1400, 1800],
|
|
40148
|
+
f2: 2400,
|
|
40149
|
+
q: 1,
|
|
40150
|
+
a: 0.04,
|
|
40151
|
+
d: [0.3, 0.4],
|
|
40152
|
+
vol: [0.12, 0.16]
|
|
40153
|
+
})
|
|
40154
|
+
],
|
|
40155
|
+
"a bandage unrolled round a limb"
|
|
40156
|
+
),
|
|
40157
|
+
foley(
|
|
40158
|
+
"pills_shake",
|
|
40159
|
+
[
|
|
40160
|
+
...sceneMany(
|
|
40161
|
+
8,
|
|
40162
|
+
() => sceneTone({
|
|
40163
|
+
f: [2400, 3600],
|
|
40164
|
+
d: 0.015,
|
|
40165
|
+
vol: [0.03, 0.05],
|
|
40166
|
+
delay: [0, 0.25]
|
|
40167
|
+
})
|
|
40168
|
+
),
|
|
40169
|
+
sceneNoise({ type: "bandpass", f: [1500, 1900], q: 2, d: 0.25, vol: 0.05 })
|
|
40170
|
+
],
|
|
40171
|
+
"pills shaken in their bottle"
|
|
40172
|
+
),
|
|
40173
|
+
foley(
|
|
40174
|
+
"medkit_use",
|
|
40175
|
+
[
|
|
40176
|
+
...click(1700, 0.24),
|
|
40177
|
+
sceneNoise({
|
|
40178
|
+
type: "bandpass",
|
|
40179
|
+
f: [1e3, 1400],
|
|
40180
|
+
q: 1,
|
|
40181
|
+
a: 0.03,
|
|
40182
|
+
d: [0.25, 0.32],
|
|
40183
|
+
vol: [0.08, 0.12],
|
|
40184
|
+
delay: [0.05, 0.08]
|
|
40185
|
+
})
|
|
40186
|
+
],
|
|
40187
|
+
"a first aid kit opened and rummaged"
|
|
40188
|
+
),
|
|
40189
|
+
foley("flashlight_click", click(2600, 0.3), "the switch of a flashlight")
|
|
40190
|
+
];
|
|
40191
|
+
var FOLEY_BANK = {
|
|
40192
|
+
id: "foley",
|
|
40193
|
+
sounds: [...LEAF_FOLEY, ...ITEM_FOLEY]
|
|
40194
|
+
};
|
|
38463
40195
|
var TAKES = [
|
|
38464
40196
|
{ f: 1, t: 1, v: 1 },
|
|
38465
40197
|
{ f: 1.08, t: 0.9, v: 0.92 },
|
|
@@ -39548,7 +41280,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39548
41280
|
if (energy < 5e3) return "rifle_308_3006";
|
|
39549
41281
|
return energy < 12e3 ? "sniper_338_300wm" : "antimateriel_50bmg";
|
|
39550
41282
|
};
|
|
39551
|
-
var
|
|
41283
|
+
var pickTake2 = (last, random, takes2 = GUNSHOT_TAKES) => {
|
|
39552
41284
|
if (takes2 <= 1) return 0;
|
|
39553
41285
|
if (last === void 0) return Math.floor(random() * takes2) % takes2;
|
|
39554
41286
|
const next = Math.floor(random() * (takes2 - 1)) % (takes2 - 1);
|
|
@@ -39690,11 +41422,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39690
41422
|
if (surface !== "soft") voices.push({ kind: "tone", frequency: 2900 * pitch, to: 2800 * pitch, gain: 0.025 * level, seconds: surface === "metal" ? 0.06 : 0.025 });
|
|
39691
41423
|
} else {
|
|
39692
41424
|
voices.push({ kind: "noise", filter: surface === "soft" || surface === "wood" ? "lowpass" : "highpass", frequency: knock2.frequency * pitch, q: 0.7, gain: knock2.gain * level, seconds: knock2.seconds });
|
|
39693
|
-
const
|
|
39694
|
-
if (
|
|
41425
|
+
const ringSeconds2 = RING_SECONDS[surface] * (kind === "rifle" ? 1.3 : 1);
|
|
41426
|
+
if (ringSeconds2 > 0) {
|
|
39695
41427
|
const f = RING[kind] * pitch;
|
|
39696
|
-
voices.push({ kind: "tone", frequency: f, to: f * 0.985, gain: 0.07 * level, seconds:
|
|
39697
|
-
voices.push({ kind: "tone", frequency: f * PARTIAL, to: f * PARTIAL * 0.99, gain: 0.03 * level, seconds:
|
|
41428
|
+
voices.push({ kind: "tone", frequency: f, to: f * 0.985, gain: 0.07 * level, seconds: ringSeconds2 });
|
|
41429
|
+
voices.push({ kind: "tone", frequency: f * PARTIAL, to: f * PARTIAL * 0.99, gain: 0.03 * level, seconds: ringSeconds2 * 0.6 });
|
|
39698
41430
|
}
|
|
39699
41431
|
}
|
|
39700
41432
|
const surfaceName = surface === "hard" ? "concreto" : surface === "soft" ? "terra" : surface === "wood" ? "madeira" : "metal";
|
|
@@ -40455,6 +42187,72 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
40455
42187
|
});
|
|
40456
42188
|
};
|
|
40457
42189
|
|
|
42190
|
+
// src/data/reload-sample-hits.json
|
|
42191
|
+
var reload_sample_hits_default = {
|
|
42192
|
+
$comment: "Seconds from the start of each recorded reload step to its hit (median of its takes), measured on the converted files by tools/sfx-sources/hits.mjs. The reload clip starts the sound that much early, so the hit lands on the frame the part reaches its stop.",
|
|
42193
|
+
hits: {
|
|
42194
|
+
bolt_lift: 0.072,
|
|
42195
|
+
bolt_lock: 0.078,
|
|
42196
|
+
bolt_pull: 0.128,
|
|
42197
|
+
bolt_push: 0.054,
|
|
42198
|
+
charging_handle_pull: 0.074,
|
|
42199
|
+
charging_handle_release: 0.048,
|
|
42200
|
+
cylinder_close: 0.024,
|
|
42201
|
+
cylinder_eject: 0.394,
|
|
42202
|
+
cylinder_open: 0.07,
|
|
42203
|
+
lever_close: 0.147,
|
|
42204
|
+
lever_open: 0.095,
|
|
42205
|
+
mag_out: 0.012,
|
|
42206
|
+
mag_seat: 0.094,
|
|
42207
|
+
pump_back: 0.094,
|
|
42208
|
+
pump_forward: 0.118,
|
|
42209
|
+
shell_insert: 0.21,
|
|
42210
|
+
slide_release: 0.031,
|
|
42211
|
+
speedloader: 0.089
|
|
42212
|
+
}
|
|
42213
|
+
};
|
|
42214
|
+
|
|
42215
|
+
// src/audio/samples.ts
|
|
42216
|
+
var GUNSHOT_SAMPLE_IDS = [...Object.keys(gunshot_profiles_default.profiles), "suppressed_pistol", "suppressed_rifle"];
|
|
42217
|
+
var GUNSHOT_SAMPLE = {
|
|
42218
|
+
bus: "weapons",
|
|
42219
|
+
gain: 1,
|
|
42220
|
+
pitch: 0.04,
|
|
42221
|
+
crossover: { from: 20, to: 90 },
|
|
42222
|
+
falloff: { model: "inverse_square", k: 5e-4, minGain: 6e-4 },
|
|
42223
|
+
cutoffK: 0.04,
|
|
42224
|
+
priority: 3
|
|
42225
|
+
};
|
|
42226
|
+
var SUPPRESSED_SAMPLE = { ...GUNSHOT_SAMPLE, gain: 0.55, crossover: { from: 10, to: 50 }, falloff: { model: "inverse_square", k: 4e-3, minGain: 8e-4 } };
|
|
42227
|
+
var RELOAD_SAMPLE = { bus: "weapons", gain: 0.32, pitch: 0.05, falloff: { model: "inverse_square", k: 0.05, minGain: 2e-3 }, cutoffK: 0.02, priority: 2 };
|
|
42228
|
+
var CASING_SAMPLE = { bus: "weapons", gain: 0.22, pitch: 0.06, falloff: { model: "inverse_square", k: 0.08, minGain: 3e-3 }, cutoffK: 0.03, priority: 1 };
|
|
42229
|
+
var casingSampleId = (sample) => sample.replace(/_(pistol|rifle|shell)$/, "");
|
|
42230
|
+
var RELOAD_SAMPLE_HITS = reload_sample_hits_default.hits;
|
|
42231
|
+
var WEIGHT_INTENSITY = { light: 0.1, medium: 0.5, heavy: 0.9 };
|
|
42232
|
+
var CUES_IN_SAMPLE = { mag_release: "mag_out", mag_insert: "mag_seat" };
|
|
42233
|
+
var isGunshot = (id) => GUNSHOT_SAMPLE_IDS.includes(id);
|
|
42234
|
+
function weaponSampleDefaults(sound3, overrides = {}) {
|
|
42235
|
+
if (sound3.category !== "armas") return void 0;
|
|
42236
|
+
const base = sound3.id.startsWith("suppressed_") ? SUPPRESSED_SAMPLE : isGunshot(sound3.id) ? GUNSHOT_SAMPLE : sound3.id.startsWith("casing_drop_") ? CASING_SAMPLE : RELOAD_SAMPLE;
|
|
42237
|
+
return { ...base, ...overrides[sound3.id] };
|
|
42238
|
+
}
|
|
42239
|
+
function weaponSampleBank(options) {
|
|
42240
|
+
const bank = sampleBankFromManifest(options.manifest, { id: "weapons_three_samples", ...options.url ? {} : { baseUrl: options.baseUrl ?? "" }, defaults: (sound3) => weaponSampleDefaults(sound3, options.sounds) });
|
|
42241
|
+
const url2 = options.url;
|
|
42242
|
+
const remap = (refs) => refs && url2 ? refs.map((ref) => ({ ...ref, url: url2(ref.url) })) : refs ? [...refs] : void 0;
|
|
42243
|
+
const samples = (bank.samples ?? []).map((sample) => {
|
|
42244
|
+
const tiers = sample.tiers?.map((tier) => ({ ...tier, close: remap(tier.close) ?? [], ...tier.far ? { far: remap(tier.far) ?? [] } : {} }));
|
|
42245
|
+
return {
|
|
42246
|
+
...sample,
|
|
42247
|
+
close: remap(sample.close) ?? [],
|
|
42248
|
+
...sample.far ? { far: remap(sample.far) ?? [] } : {},
|
|
42249
|
+
...tiers ? { tiers } : {},
|
|
42250
|
+
...isGunshot(sample.id) ? { choke: { voices: 3, fade: 0.06 } } : {}
|
|
42251
|
+
};
|
|
42252
|
+
});
|
|
42253
|
+
return { id: bank.id, samples };
|
|
42254
|
+
}
|
|
42255
|
+
|
|
40458
42256
|
// src/audio.ts
|
|
40459
42257
|
var NOISE_SECONDS = 1.5;
|
|
40460
42258
|
var DEFAULT_SEED = 1;
|
|
@@ -40475,6 +42273,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
40475
42273
|
const channel = shared2 && options.seed !== void 0 ? shared2.channel({ seed }) : engine.channel({});
|
|
40476
42274
|
engine.register({ id: `weapons_three@${classBurstId(distanceCurve)}`, sounds: weaponRecipes(distanceCurve) });
|
|
40477
42275
|
const classBurst = classBurstId(distanceCurve);
|
|
42276
|
+
const sampleBank = options.samples ? weaponSampleBank(options.samples) : null;
|
|
42277
|
+
if (sampleBank) engine.register(sampleBank);
|
|
42278
|
+
const sampleIds = new Set((sampleBank?.samples ?? []).map((sample) => sample.id));
|
|
42279
|
+
let sampleLoad = null;
|
|
42280
|
+
const loadSamples = () => sampleLoad ?? (sampleLoad = sampleIds.size > 0 ? engine.loadSamples([...sampleIds]).then(() => void 0, () => void 0) : Promise.resolve());
|
|
42281
|
+
const sampleReady = (id) => {
|
|
42282
|
+
if (!sampleIds.has(id)) return false;
|
|
42283
|
+
if (engine.sampleStatus(id) === "ready") return true;
|
|
42284
|
+
void loadSamples();
|
|
42285
|
+
return false;
|
|
42286
|
+
};
|
|
40478
42287
|
const burst2 = (config) => {
|
|
40479
42288
|
const id = config.filter === "highpass" ? BURST_IDS.highpass : BURST_IDS.lowpass;
|
|
40480
42289
|
const params = { frequency: config.frequency, q: config.q ?? 0.8, gain: Math.max(config.gain, 2e-4), seconds: config.seconds };
|
|
@@ -40523,8 +42332,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
40523
42332
|
};
|
|
40524
42333
|
const casing2 = (input) => {
|
|
40525
42334
|
const sound3 = computeCasingSound({ ...input, pitch: input.pitch ?? 1 + (channel.random() * 2 - 1) * 0.06 });
|
|
42335
|
+
const recorded = sound3.kind === "shell" ? "" : casingSampleId(sound3.sample);
|
|
42336
|
+
if (recorded && sampleReady(recorded)) {
|
|
42337
|
+
if ((input.bounce ?? 0) === 0) channel.play(recorded, { volume: Math.min(1, Math.max(0.2, (input.speed ?? 1.5) / 2.5)) });
|
|
42338
|
+
options.onCasing?.(sound3, "sample");
|
|
42339
|
+
return;
|
|
42340
|
+
}
|
|
40526
42341
|
for (const voice2 of sound3.voices) playCasingVoice(voice2);
|
|
40527
|
-
options.onCasing?.(sound3);
|
|
42342
|
+
options.onCasing?.(sound3, "synth");
|
|
40528
42343
|
};
|
|
40529
42344
|
const lastTake = /* @__PURE__ */ new Map();
|
|
40530
42345
|
const pitchSpread = options.pitchSpread ?? 0.04;
|
|
@@ -40542,12 +42357,29 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
40542
42357
|
if (options.shotModel !== "game") {
|
|
40543
42358
|
const base = { energyJ, category, ...extras, space: extras.space ?? (extras.indoors ? "indoor" : "outdoor") };
|
|
40544
42359
|
const profile = computeGunshot(base, options.gunshot).profile;
|
|
40545
|
-
const take =
|
|
42360
|
+
const take = pickTake2(lastTake.get(profile), channel.random);
|
|
40546
42361
|
lastTake.set(profile, take);
|
|
40547
42362
|
const pitch = 1 + (channel.random() * 2 - 1) * pitchSpread;
|
|
40548
42363
|
const shot = computeGunshot({ ...base, take, pitch }, options.gunshot);
|
|
42364
|
+
const recorded = shot.samples.close;
|
|
42365
|
+
if (shot.audible && sampleReady(recorded)) {
|
|
42366
|
+
const occlusion = Math.min(1, Math.max(0, extras.occlusion ?? 0));
|
|
42367
|
+
const handle = channel.play(recorded, {
|
|
42368
|
+
volume: (extras.volume ?? 1) * (1 - 0.5 * occlusion),
|
|
42369
|
+
environment: base.space === "indoor" ? "indoor" : "outdoor",
|
|
42370
|
+
...extras.position ? { position: [extras.position[0], extras.position[1], extras.position[2]] } : {},
|
|
42371
|
+
...extras.distance === void 0 ? {} : { distance: extras.distance },
|
|
42372
|
+
...shot.delay > 0 ? { delay: shot.delay } : {}
|
|
42373
|
+
});
|
|
42374
|
+
if (base.space === "indoor") {
|
|
42375
|
+
for (const voice2 of shot.voices) if (voice2.group === "tail") playGunshotVoice(voice2, extras);
|
|
42376
|
+
}
|
|
42377
|
+
const layers = handle?.kind === "sample" ? handle.plan.layers.map((layer2) => ({ role: layer2.role, take: layer2.take, rate: layer2.rate })) : [];
|
|
42378
|
+
options.onGunshot?.(shot, { ...base, take, pitch }, { kind: "sample", id: recorded, layers });
|
|
42379
|
+
return;
|
|
42380
|
+
}
|
|
40549
42381
|
for (const voice2 of shot.voices) playGunshotVoice(voice2, extras);
|
|
40550
|
-
if (shot.audible) options.onGunshot?.(shot, { ...base, take, pitch });
|
|
42382
|
+
if (shot.audible) options.onGunshot?.(shot, { ...base, take, pitch }, { kind: "synth" });
|
|
40551
42383
|
return;
|
|
40552
42384
|
}
|
|
40553
42385
|
const sound3 = shotSound({ ...extras, energyJ, category });
|
|
@@ -40562,9 +42394,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
40562
42394
|
mechanical("dry_fire");
|
|
40563
42395
|
},
|
|
40564
42396
|
mechanical,
|
|
40565
|
-
cue(id, profile) {
|
|
40566
|
-
|
|
42397
|
+
cue(id, profile, lead = 0) {
|
|
42398
|
+
const carriedBy = CUES_IN_SAMPLE[id];
|
|
42399
|
+
if (carriedBy && sampleReady(carriedBy)) return "carried";
|
|
42400
|
+
if (sampleReady(id)) {
|
|
42401
|
+
channel.play(id, { intensity: WEIGHT_INTENSITY[(profile ?? DEFAULT_SOUND_PROFILE).weight] });
|
|
42402
|
+
return "sample";
|
|
42403
|
+
}
|
|
42404
|
+
for (const entry2 of reloadCueSteps(id, profile, cueTable)) step(lead > 0 ? { ...entry2, at: entry2.at + lead } : entry2);
|
|
42405
|
+
return "synth";
|
|
40567
42406
|
},
|
|
42407
|
+
loadSamples,
|
|
40568
42408
|
event(event) {
|
|
40569
42409
|
const id = mechanicalSoundOf(event);
|
|
40570
42410
|
if (id) mechanical(id);
|
|
@@ -47576,17 +49416,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
47576
49416
|
if (!builder) throw new Error(`game-items-three: no builder for the model "${entry2.id}"`);
|
|
47577
49417
|
return { entry: entry2, builder };
|
|
47578
49418
|
});
|
|
47579
|
-
var registryOver = (
|
|
49419
|
+
var registryOver = (entries2, builders) => ({
|
|
47580
49420
|
has: (id) => builders.has(id),
|
|
47581
|
-
entry: (id) =>
|
|
49421
|
+
entry: (id) => entries2.get(id),
|
|
47582
49422
|
builder: (id) => builders.get(id),
|
|
47583
|
-
list: () => [...
|
|
49423
|
+
list: () => [...entries2.keys()],
|
|
47584
49424
|
register(entry2, builder) {
|
|
47585
|
-
|
|
49425
|
+
entries2.set(entry2.id, entry2);
|
|
47586
49426
|
builders.set(entry2.id, builder);
|
|
47587
49427
|
},
|
|
47588
49428
|
unregister(id) {
|
|
47589
|
-
|
|
49429
|
+
entries2.delete(id);
|
|
47590
49430
|
builders.delete(id);
|
|
47591
49431
|
}
|
|
47592
49432
|
});
|
|
@@ -51275,6 +53115,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
51275
53115
|
}
|
|
51276
53116
|
|
|
51277
53117
|
// src/animation/clip-builder.ts
|
|
53118
|
+
var RELOAD_SAMPLE_HITS2 = reload_sample_hits_default.hits;
|
|
51278
53119
|
var ROOT = "root";
|
|
51279
53120
|
var AXIS_INDEX = { x: 0, y: 1, z: 2 };
|
|
51280
53121
|
var EASE_STEPS = 10;
|
|
@@ -51282,7 +53123,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
51282
53123
|
var move = (part, axis2, start, duration, from, to) => ({ part, channel: "position", axis: axis2, start, duration, from, to });
|
|
51283
53124
|
var turn = (part, axis2, start, duration, from, to) => ({ part, channel: "rotation", axis: axis2, start, duration, from, to });
|
|
51284
53125
|
var cue = (t, type, data) => ({ t, type, ...data ? { data } : {} });
|
|
51285
|
-
var sound2 = (t, id) =>
|
|
53126
|
+
var sound2 = (t, id) => {
|
|
53127
|
+
const lead = RELOAD_SAMPLE_HITS2[id];
|
|
53128
|
+
return lead ? { t, type: "sound", data: { id }, lead } : { t, type: "sound", data: { id } };
|
|
53129
|
+
};
|
|
51286
53130
|
var stage = (id, t) => ({ t, type: STAGE_EVENT, data: { stage: id } });
|
|
51287
53131
|
var valueAt = (tweens, t, includeInstants) => {
|
|
51288
53132
|
let value = 0;
|
|
@@ -54613,7 +56457,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
54613
56457
|
var ARC_HEIGHT = 2.2;
|
|
54614
56458
|
var GLASS_GREEN = 3828282;
|
|
54615
56459
|
var OBJECT_ID_DRAWS = 12;
|
|
54616
|
-
var
|
|
56460
|
+
var at2 = (offset) => vadd(TARGET, offset);
|
|
54617
56461
|
var MOLOTOV = {
|
|
54618
56462
|
id: "molotov",
|
|
54619
56463
|
pageId: "molotov",
|
|
@@ -54635,17 +56479,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
54635
56479
|
when(not(variable("landed")), [
|
|
54636
56480
|
set("landed", true),
|
|
54637
56481
|
cue2("bottle_visible", { visible: false }),
|
|
54638
|
-
repeat(scaled(12), debris({ p:
|
|
54639
|
-
burst("add", 45, { p:
|
|
54640
|
-
flash(
|
|
56482
|
+
repeat(scaled(12), debris({ p: at2([0, 0.1, 0]), dir: UP6, cone: 1.3, sp: [1, 3], size: [0.04, 0.01, 0.04], c: GLASS_GREEN, life: 12 })),
|
|
56483
|
+
burst("add", 45, { p: at2([0, 0.15, 0]), dir: UP6, cone: 1.35, sp: [2, 4], drag: 2, life: [0.3, 0.6], size: [0.3, 0.5], c0: 16765562, c1: 10493960, fi: 0.05 }),
|
|
56484
|
+
flash(at2([0, 0.6, 0]), 16747056, 6, 0.3, 12, true),
|
|
54641
56485
|
decal(TARGET[0], 0, TARGET[2], 4.2, 854793, { grow: 0.8, life: 60 })
|
|
54642
56486
|
])
|
|
54643
56487
|
]),
|
|
54644
56488
|
when(and(gt(TIME, FLIGHT), lt(TIME, 8.2)), [
|
|
54645
56489
|
set("poolRadius", min(2.2, add(0.5, mul(sub(TIME, 1), 2.1)))),
|
|
54646
56490
|
set("poolFade", ite(gt(TIME, 7), max(0.1, sub(1, div(sub(TIME, 7), 1.2))), 1)),
|
|
54647
|
-
call2("fire_emit", "mol",
|
|
54648
|
-
fireLight(0,
|
|
56491
|
+
call2("fire_emit", "mol", at2([0, 0.05, 0]), variable("poolRadius"), mul(1.6, variable("poolFade")), { smoke: 16 }),
|
|
56492
|
+
fireLight(0, at2([0, 1, 0]), mul(3.2, variable("poolFade")), TIME)
|
|
54649
56493
|
], [
|
|
54650
56494
|
when(ge(TIME, 8.2), [
|
|
54651
56495
|
fireLightOff(0),
|
|
@@ -55143,11 +56987,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
55143
56987
|
])
|
|
55144
56988
|
]
|
|
55145
56989
|
};
|
|
55146
|
-
var
|
|
55147
|
-
var FRONT_LEG =
|
|
55148
|
-
var TOP_CORNER =
|
|
55149
|
-
var TOP_PIECE =
|
|
55150
|
-
var FAR_CORNER =
|
|
56990
|
+
var at22 = (x, y, z) => [SPOT[0] + x, SPOT[1] + y, SPOT[2] + z];
|
|
56991
|
+
var FRONT_LEG = at22(-0.52, 0.2, 0.32);
|
|
56992
|
+
var TOP_CORNER = at22(0.3, 0.78, 0.2);
|
|
56993
|
+
var TOP_PIECE = at22(-0.3, 0.78, -0.2);
|
|
56994
|
+
var FAR_CORNER = at22(0.3, 0.78, -0.2);
|
|
55151
56995
|
var HOLE_OBJECT_ID_DRAWS = 12;
|
|
55152
56996
|
var HOLES = 9;
|
|
55153
56997
|
var GLOCK_FROM = [-0.4, 1, 6];
|
|
@@ -56647,35 +58491,35 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
56647
58491
|
var NOOP = () => {
|
|
56648
58492
|
};
|
|
56649
58493
|
function createSchedule() {
|
|
56650
|
-
const
|
|
58494
|
+
const entries2 = [];
|
|
56651
58495
|
const spare = [];
|
|
56652
58496
|
return {
|
|
56653
58497
|
at(time, action) {
|
|
56654
58498
|
const entry2 = spare.pop() ?? { time: 0, action: NOOP };
|
|
56655
58499
|
entry2.time = time;
|
|
56656
58500
|
entry2.action = action;
|
|
56657
|
-
|
|
58501
|
+
entries2.push(entry2);
|
|
56658
58502
|
},
|
|
56659
58503
|
update(now) {
|
|
56660
|
-
for (let index =
|
|
56661
|
-
const entry2 =
|
|
58504
|
+
for (let index = entries2.length - 1; index >= 0; index--) {
|
|
58505
|
+
const entry2 = entries2[index];
|
|
56662
58506
|
if (!entry2 || entry2.time > now) continue;
|
|
56663
58507
|
const action = entry2.action;
|
|
56664
|
-
|
|
58508
|
+
entries2.splice(index, 1);
|
|
56665
58509
|
entry2.action = NOOP;
|
|
56666
58510
|
spare.push(entry2);
|
|
56667
58511
|
action();
|
|
56668
58512
|
}
|
|
56669
58513
|
},
|
|
56670
58514
|
clear() {
|
|
56671
|
-
for (const entry2 of
|
|
58515
|
+
for (const entry2 of entries2) {
|
|
56672
58516
|
entry2.action = NOOP;
|
|
56673
58517
|
spare.push(entry2);
|
|
56674
58518
|
}
|
|
56675
|
-
|
|
58519
|
+
entries2.length = 0;
|
|
56676
58520
|
},
|
|
56677
58521
|
get pending() {
|
|
56678
|
-
return
|
|
58522
|
+
return entries2.length;
|
|
56679
58523
|
}
|
|
56680
58524
|
};
|
|
56681
58525
|
}
|
|
@@ -57430,12 +59274,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
57430
59274
|
var SCORCH_VARIANTS = 3;
|
|
57431
59275
|
var RIM_COLORS = [2829359, 3815478];
|
|
57432
59276
|
function createMarkStore() {
|
|
57433
|
-
const
|
|
59277
|
+
const entries2 = [];
|
|
57434
59278
|
let version = 0;
|
|
57435
59279
|
let bloodCount = 0;
|
|
57436
59280
|
const listeners = /* @__PURE__ */ new Set();
|
|
57437
59281
|
return {
|
|
57438
|
-
entries,
|
|
59282
|
+
entries: entries2,
|
|
57439
59283
|
get version() {
|
|
57440
59284
|
return version;
|
|
57441
59285
|
},
|
|
@@ -57444,13 +59288,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
57444
59288
|
},
|
|
57445
59289
|
lift: 0,
|
|
57446
59290
|
add(mark) {
|
|
57447
|
-
|
|
59291
|
+
entries2.push(mark);
|
|
57448
59292
|
if (mark.kind === "blood") bloodCount++;
|
|
57449
59293
|
version++;
|
|
57450
59294
|
for (const listener of listeners) listener({ type: "add", mark });
|
|
57451
59295
|
},
|
|
57452
59296
|
clear() {
|
|
57453
|
-
|
|
59297
|
+
entries2.length = 0;
|
|
57454
59298
|
bloodCount = 0;
|
|
57455
59299
|
this.lift = 0;
|
|
57456
59300
|
version++;
|
|
@@ -61741,7 +63585,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
61741
63585
|
breechRound();
|
|
61742
63586
|
break;
|
|
61743
63587
|
case "sound":
|
|
61744
|
-
world.sound(session.id, String(data.id), session.soundProfile);
|
|
63588
|
+
world.sound(session.id, String(data.id), session.soundProfile, typeof data.lead === "number" ? data.lead : void 0);
|
|
61745
63589
|
break;
|
|
61746
63590
|
default:
|
|
61747
63591
|
break;
|
|
@@ -62314,9 +64158,9 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
62314
64158
|
audio,
|
|
62315
64159
|
layers,
|
|
62316
64160
|
groundAt,
|
|
62317
|
-
sound: (weapon, cue3, profile) => {
|
|
62318
|
-
audio?.cue(cue3, profile);
|
|
62319
|
-
options.onSound?.({ weapon, cue: cue3, profile });
|
|
64161
|
+
sound: (weapon, cue3, profile, lead) => {
|
|
64162
|
+
const played = audio?.cue(cue3, profile, lead);
|
|
64163
|
+
options.onSound?.({ weapon, cue: cue3, profile, ...played ? { played } : {} });
|
|
62320
64164
|
},
|
|
62321
64165
|
schedule: (delay, seconds, step, done) => void tasks.push({ delay, seconds, elapsed: 0, step: (progress) => step(ease(progress)), done })
|
|
62322
64166
|
};
|
|
@@ -63711,7 +65555,10 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
63711
65555
|
reloadStart: "Reload started: {weapon} ({ammo}/{capacity})",
|
|
63712
65556
|
reloadClip: "Reload of {weapon}: {kind}, clip {clip} ({seconds} s)",
|
|
63713
65557
|
soundCue: "Sound: {cue} ({weapon})",
|
|
65558
|
+
cueRecorded: " \xB7 recorded",
|
|
65559
|
+
cueCarried: " \xB7 inside the next recording",
|
|
63714
65560
|
gunshotSound: "Shot sound: {profile}, take {take}/4, pitch {pitch}, {space}, {distance} m{far}",
|
|
65561
|
+
gunshotRecorded: " \xB7 recorded take {takes}",
|
|
63715
65562
|
casingSound: "Case lands: {case} on {surface}",
|
|
63716
65563
|
spaces: { indoor: "indoors", outdoor: "outdoors" },
|
|
63717
65564
|
surfaces: { hard: "concrete", wood: "wood", metal: "metal", soft: "dirt" },
|
|
@@ -63743,7 +65590,10 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
63743
65590
|
reloadStart: "Recarga iniciada: {weapon} ({ammo}/{capacity})",
|
|
63744
65591
|
reloadClip: "Recarga de {weapon}: {kind}, clipe {clip} ({seconds} s)",
|
|
63745
65592
|
soundCue: "Som: {cue} ({weapon})",
|
|
65593
|
+
cueRecorded: " \xB7 grava\xE7\xE3o",
|
|
65594
|
+
cueCarried: " \xB7 dentro da grava\xE7\xE3o seguinte",
|
|
63746
65595
|
gunshotSound: "Som do tiro: {profile}, tomada {take}/4, tom {pitch}, {space}, {distance} m{far}",
|
|
65596
|
+
gunshotRecorded: " \xB7 grava\xE7\xE3o, tomada {takes}",
|
|
63747
65597
|
casingSound: "C\xE1psula caiu: {case} em {surface}",
|
|
63748
65598
|
spaces: { indoor: "ambiente fechado", outdoor: "ao ar livre" },
|
|
63749
65599
|
surfaces: { hard: "concreto", wood: "madeira", metal: "metal", soft: "terra" },
|
|
@@ -63865,7 +65715,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
63865
65715
|
const accessoryText = accessoryTextOf(locale);
|
|
63866
65716
|
const seedOption = options.seed === void 0 ? {} : { seed: options.seed };
|
|
63867
65717
|
let audio;
|
|
63868
|
-
const ownAudio = () => audio === void 0 ? audio = options.sound === false ? null : createWeaponAudio(void 0, seedOption) : audio;
|
|
65718
|
+
const ownAudio = () => audio === void 0 ? audio = options.sound === false ? null : createWeaponAudio(void 0, { ...seedOption, ...options.samples ? { samples: options.samples } : {} }) : audio;
|
|
63869
65719
|
const weaponDefs = [...arsenal.weapons.values()].filter((def) => !BODY_ACTIONS.has(def.id));
|
|
63870
65720
|
const thumbnailBase = options.thumbnailBase ?? DEFAULT_THUMBNAIL_BASE;
|
|
63871
65721
|
const withThumbnail = (item, key2) => {
|
|
@@ -63952,18 +65802,22 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
63952
65802
|
audio = createWeaponAudio(void 0, {
|
|
63953
65803
|
...seedOption,
|
|
63954
65804
|
engine: lentEngine,
|
|
63955
|
-
|
|
63956
|
-
|
|
63957
|
-
|
|
63958
|
-
|
|
63959
|
-
|
|
63960
|
-
|
|
65805
|
+
...options.samples ? { samples: options.samples } : {},
|
|
65806
|
+
onGunshot: (shot, input, played) => {
|
|
65807
|
+
const recorded = played.kind === "sample" && played.layers.length > 0 ? fill(text.gunshotRecorded, { takes: played.layers.map((layer2) => `${layer2.role} ${layer2.take + 1}`).join(", ") }) : "";
|
|
65808
|
+
lent.log(
|
|
65809
|
+
fill(text.gunshotSound, { profile: shot.profile, take: String(shot.take + 1), pitch: `${shot.pitch >= 1 ? "+" : ""}${((shot.pitch - 1) * 100).toFixed(1)} %`, space: text.spaces[input.space ?? "outdoor"], distance: String(Math.round(input.distance ?? 0)), far: shot.closeMix < 1 ? ` (${Math.round((1 - shot.closeMix) * 100)} % far)` : "" }) + recorded,
|
|
65810
|
+
{ profile: shot.profile, take: shot.take, pitch: shot.pitch, space: input.space ?? "outdoor", distance: input.distance ?? 0, closeMix: shot.closeMix, delay: shot.delay, samples: shot.samples, played },
|
|
65811
|
+
"sound"
|
|
65812
|
+
);
|
|
65813
|
+
},
|
|
65814
|
+
onCasing: (sound3, played) => lent.log(fill(text.casingSound, { case: sound3.kind, surface: text.surfaces[sound3.surface] }) + (played === "sample" ? text.cueRecorded : ""), { case: sound3.kind, surface: sound3.surface, sample: sound3.sample, played }, "sound")
|
|
63961
65815
|
});
|
|
63962
65816
|
}
|
|
63963
65817
|
let simulatedMs = 0;
|
|
63964
65818
|
const offClock = lent.onFrame((dt) => simulatedMs += dt * 1e3);
|
|
63965
65819
|
const created = createWeaponFx({
|
|
63966
|
-
onSound: ({ weapon, cue: cue3, profile }) => lent.log(fill(text.soundCue, { weapon: arsenal.name(weapon), cue: text.soundCues[cue3] ?? cue3 }), { weapon, cue: cue3, weight: profile.weight, material: profile.material }, "sound"),
|
|
65820
|
+
onSound: ({ weapon, cue: cue3, profile, played }) => lent.log(fill(text.soundCue, { weapon: arsenal.name(weapon), cue: text.soundCues[cue3] ?? cue3 }) + (played === "sample" ? text.cueRecorded : played === "carried" ? text.cueCarried : ""), { weapon, cue: cue3, weight: profile.weight, material: profile.material, ...played ? { played } : {} }, "sound"),
|
|
63967
65821
|
THREE: lent.THREE,
|
|
63968
65822
|
scene: lent.scene,
|
|
63969
65823
|
camera: lent.camera,
|
|
@@ -64130,6 +65984,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64130
65984
|
push_outward: "Every body inside the reach moved away from the blast ({moved} of {n}, {least} m at the least)",
|
|
64131
65985
|
push_falloff: "{what}: the nearer one moved more than the farther one ({near} m at {nearDistance} m, {far} m at {farDistance} m)",
|
|
64132
65986
|
push_person: "{who} at {distance} m was pushed {moved} m away",
|
|
65987
|
+
push_sheltered: "{what} at {distance} m stood behind cover ({cover}% of the blast got through) and moved only {moved} m",
|
|
64133
65988
|
push_heavy: "{what} (too heavy to grab, not fixed) was moved {moved} m by the blast"
|
|
64134
65989
|
}
|
|
64135
65990
|
},
|
|
@@ -64215,6 +66070,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64215
66070
|
push_outward: "Todo corpo dentro do alcance se afastou da explos\xE3o ({moved} de {n}, no m\xEDnimo {least} m)",
|
|
64216
66071
|
push_falloff: "{what}: o mais perto andou mais que o mais longe ({near} m a {nearDistance} m, {far} m a {farDistance} m)",
|
|
64217
66072
|
push_person: "{who} a {distance} m foi empurrado {moved} m para longe",
|
|
66073
|
+
push_sheltered: "{what} a {distance} m estava atr\xE1s de cobertura ({cover}% da explos\xE3o passou) e andou s\xF3 {moved} m",
|
|
64218
66074
|
push_heavy: "{what} (pesado demais para pegar, mas solto) foi movido {moved} m pela explos\xE3o"
|
|
64219
66075
|
}
|
|
64220
66076
|
}
|
|
@@ -64760,6 +66616,10 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64760
66616
|
];
|
|
64761
66617
|
var PUSH_READ_AT = 0.8;
|
|
64762
66618
|
var MOVED = 0.15;
|
|
66619
|
+
var SHELTERED = 0.5;
|
|
66620
|
+
var SHELTERED_MOST = 1;
|
|
66621
|
+
var CHEST = 1.1;
|
|
66622
|
+
var MIDDLE = 0.3;
|
|
64763
66623
|
var HEAVY_ITEMS = ["camp_table"];
|
|
64764
66624
|
var flat = (a, b) => Math.hypot(a[0] - b[0], a[2] - b[2]);
|
|
64765
66625
|
var bearing = (centre, distance3, degrees) => [centre[0] + Math.sin(degrees * Math.PI / 180) * distance3, 0, centre[2] + Math.cos(degrees * Math.PI / 180) * distance3];
|
|
@@ -64776,9 +66636,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64776
66636
|
name: mode === "p13" ? text.push_p13 : text.push_grenade,
|
|
64777
66637
|
run: ({ room, step, expect }) => {
|
|
64778
66638
|
let centre;
|
|
66639
|
+
let source;
|
|
64779
66640
|
if (mode === "p13") {
|
|
64780
66641
|
room.openArea(EXPLOSIVES_AREA_ID);
|
|
64781
66642
|
const cylinder2 = room.spawned().find((spawned) => spawned.itemId === CYLINDER_ITEM);
|
|
66643
|
+
source = cylinder2?.objectId;
|
|
64782
66644
|
const at3 = cylinder2?.root?.position;
|
|
64783
66645
|
centre = [at3?.x ?? 0, 0, at3?.z ?? -10.66];
|
|
64784
66646
|
} else {
|
|
@@ -64829,6 +66691,14 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64829
66691
|
const blast = bench.lastBlast();
|
|
64830
66692
|
expect(!!blast, text.push_told, { waited });
|
|
64831
66693
|
if (!blast) return;
|
|
66694
|
+
const coverOf = new Map(
|
|
66695
|
+
placed.map((body) => {
|
|
66696
|
+
const from = origin.get(body.objectId) ?? body.from;
|
|
66697
|
+
const person = body.kind === "zombie" || body.kind === "survivor";
|
|
66698
|
+
const ignore = source ? [source, body.objectId] : [body.objectId];
|
|
66699
|
+
return [body.objectId, room.world.blastReach?.(blast.point, [from[0], from[1] + (person ? CHEST : MIDDLE), from[2]], { ignore }) ?? 1];
|
|
66700
|
+
})
|
|
66701
|
+
);
|
|
64832
66702
|
step(PUSH_READ_AT);
|
|
64833
66703
|
const rows = placed.map((body) => {
|
|
64834
66704
|
const from = origin.get(body.objectId) ?? body.from;
|
|
@@ -64836,10 +66706,15 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
64836
66706
|
const distance3 = flat(from, blast.point);
|
|
64837
66707
|
const away = Math.max(1e-6, distance3);
|
|
64838
66708
|
const outward = ((now[0] - from[0]) * (from[0] - blast.point[0]) + (now[2] - from[2]) * (from[2] - blast.point[2])) / away;
|
|
64839
|
-
return { ...body, distance: distance3, outward, moved: flat(now, from) };
|
|
66709
|
+
return { ...body, distance: distance3, outward, moved: flat(now, from), cover: coverOf.get(body.objectId) ?? 1 };
|
|
64840
66710
|
});
|
|
64841
66711
|
const torn = (row) => (PUSH_KINDS.some((entry2) => entry2.kind === row.kind) || HEAVY_ITEMS.includes(row.kind)) && partsOf(row.objectId) < (partsBefore.get(row.objectId) ?? 0);
|
|
64842
|
-
const
|
|
66712
|
+
const inReach = rows.filter((row) => row.distance < blast.radius * 0.85 && !torn(row));
|
|
66713
|
+
const sheltered = inReach.filter((row) => row.cover < SHELTERED);
|
|
66714
|
+
for (const row of sheltered) {
|
|
66715
|
+
expect(row.outward < SHELTERED_MOST, fillText2(text.push_sheltered, { what: things[row.kind] ?? row.kind, distance: row.distance.toFixed(1), cover: (row.cover * 100).toFixed(0), moved: Math.max(0, row.outward).toFixed(2) }), { row: { kind: row.kind, distance: row.distance, outward: row.outward, cover: row.cover } });
|
|
66716
|
+
}
|
|
66717
|
+
const reached = inReach.filter((row) => row.cover >= SHELTERED);
|
|
64843
66718
|
const movedAway = reached.filter((row) => row.outward >= MOVED);
|
|
64844
66719
|
const least = reached.length === 0 ? 0 : Math.min(...reached.map((row) => row.outward));
|
|
64845
66720
|
expect(reached.length > 0 && movedAway.length === reached.length, fillText2(text.push_outward, { moved: movedAway.length, n: reached.length, least: least.toFixed(2) }), { rows: reached.map((row) => ({ kind: row.kind, distance: row.distance, outward: row.outward })), torn: rows.filter(torn).map((row) => row.objectId) });
|
|
@@ -65013,12 +66888,12 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
65013
66888
|
// src/weapon-props.ts
|
|
65014
66889
|
function createWeaponProps(options = {}) {
|
|
65015
66890
|
const entryOf = ([id, model]) => ({ id, model: model ?? { item: "" } });
|
|
65016
|
-
const
|
|
66891
|
+
const entries2 = mergeById(SHIPPED_WEAPON_ITEM_MODELS.map(entryOf), (options.packs ?? []).flatMap((pack2) => Object.entries(pack2).map(entryOf)));
|
|
65017
66892
|
const patches = {};
|
|
65018
66893
|
for (const [id, model] of Object.entries(options.patch ?? {})) patches[id] = { model };
|
|
65019
|
-
applyPatches(
|
|
65020
|
-
removeIds(
|
|
65021
|
-
return weaponPropsOver(new Map([...
|
|
66894
|
+
applyPatches(entries2, patches);
|
|
66895
|
+
removeIds(entries2, options.remove);
|
|
66896
|
+
return weaponPropsOver(new Map([...entries2].map(([id, entry2]) => [id, entry2.model])));
|
|
65022
66897
|
}
|
|
65023
66898
|
return __toCommonJS(index_exports);
|
|
65024
66899
|
})();
|