@adatechnology/game-destruction-three 0.13.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.ts +151 -12
- package/dist/index.global.js +1738 -185
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +665 -98
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.global.js
CHANGED
|
@@ -23,33 +23,93 @@ var GameDestructionThree = (() => {
|
|
|
23
23
|
// src/index.ts
|
|
24
24
|
var index_exports = {};
|
|
25
25
|
__export(index_exports, {
|
|
26
|
+
BIG_BLAST_RADIUS: () => BIG_BLAST_RADIUS,
|
|
27
|
+
BLAST_FALLOFF: () => BLAST_FALLOFF,
|
|
28
|
+
BLAST_FAR_DISTANCE: () => BLAST_FAR_DISTANCE,
|
|
29
|
+
BLAST_FAR_FALLOFF: () => BLAST_FAR_FALLOFF,
|
|
30
|
+
BLAST_FIRE_SAMPLES: () => BLAST_FIRE_SAMPLES,
|
|
31
|
+
BLAST_KINDS: () => BLAST_KINDS,
|
|
32
|
+
BLAST_KIND_OF: () => BLAST_KIND_OF,
|
|
33
|
+
BLAST_SOUNDS: () => BLAST_SOUNDS,
|
|
34
|
+
BLAST_SOUND_OF: () => BLAST_SOUND_OF,
|
|
26
35
|
BURN_LOOP: () => BURN_LOOP,
|
|
36
|
+
DEFAULT_CRACKLES: () => DEFAULT_CRACKLES,
|
|
27
37
|
DEFAULT_FIRE: () => DEFAULT_FIRE,
|
|
38
|
+
DEFAULT_INDOOR_CONFINEMENT: () => DEFAULT_INDOOR_CONFINEMENT,
|
|
28
39
|
DESTRUCTION_SOUND_BANK: () => DESTRUCTION_SOUND_BANK,
|
|
29
40
|
DESTRUCTION_SOUND_KEYS: () => DESTRUCTION_SOUND_KEYS,
|
|
30
41
|
DRAG_SOUNDS: () => DRAG_SOUNDS,
|
|
31
42
|
EXPLOSION_BOOM: () => EXPLOSION_BOOM,
|
|
43
|
+
FIRE_FALLOFF: () => FIRE_FALLOFF,
|
|
44
|
+
FIRE_LOOP: () => FIRE_LOOP,
|
|
45
|
+
FIRE_SOUNDS: () => FIRE_SOUNDS,
|
|
46
|
+
IMPACT_FAMILY_TAGS: () => IMPACT_FAMILY_TAGS,
|
|
47
|
+
IMPACT_SOUNDS: () => IMPACT_SOUNDS,
|
|
48
|
+
IMPACT_SOUND_KEYS: () => IMPACT_SOUND_KEYS,
|
|
32
49
|
SCENE_SOUNDS: () => SCENE_SOUNDS,
|
|
50
|
+
blastFireSampleBank: () => blastFireSampleBank,
|
|
51
|
+
breakSoundKeys: () => breakSoundKeys,
|
|
33
52
|
createDestructionRenderer: () => createDestructionRenderer,
|
|
34
53
|
createDestructionSound: () => createDestructionSound,
|
|
35
54
|
dragSoundKey: () => dragSoundKey,
|
|
36
55
|
heatColor: () => heatColor,
|
|
56
|
+
impactFamily: () => impactFamily,
|
|
37
57
|
impactKey: () => impactKey,
|
|
58
|
+
impactSoundKeys: () => impactSoundKeys,
|
|
59
|
+
ricochetSoundKeys: () => ricochetSoundKeys,
|
|
60
|
+
shotKey: () => shotKey,
|
|
38
61
|
specFromObject3D: () => specFromObject3D
|
|
39
62
|
});
|
|
40
63
|
|
|
64
|
+
// src/audio/impact-keys.ts
|
|
65
|
+
var IMPACT_FAMILY_TAGS = [
|
|
66
|
+
["metal", "metal"],
|
|
67
|
+
["glass", "glass"],
|
|
68
|
+
["ceramic", "ceramic"],
|
|
69
|
+
["soil", "soil"],
|
|
70
|
+
["masonry", "masonry"],
|
|
71
|
+
["wood", "wood"],
|
|
72
|
+
["plant", "plant"],
|
|
73
|
+
["plastic", "plastic"],
|
|
74
|
+
["rubber", "rubber"],
|
|
75
|
+
["wax", "wax"],
|
|
76
|
+
["fabric", "soft"]
|
|
77
|
+
];
|
|
78
|
+
function impactFamily(def) {
|
|
79
|
+
const tags = def?.tags ?? [];
|
|
80
|
+
for (const [tag, family] of IMPACT_FAMILY_TAGS) if (tags.includes(tag)) return family;
|
|
81
|
+
return void 0;
|
|
82
|
+
}
|
|
83
|
+
var ordered = (prefix, material, family, blow3) => {
|
|
84
|
+
const keys = [];
|
|
85
|
+
if (material && blow3) keys.push(`${prefix}_${material}_${blow3}`);
|
|
86
|
+
if (material) keys.push(`${prefix}_${material}`);
|
|
87
|
+
if (family && blow3) keys.push(`${prefix}_${family}_${blow3}`);
|
|
88
|
+
if (family) keys.push(`${prefix}_${family}`);
|
|
89
|
+
return keys;
|
|
90
|
+
};
|
|
91
|
+
function impactSoundKeys(material, def, blow3) {
|
|
92
|
+
return { keys: ordered("impact", material, impactFamily(def), blow3) };
|
|
93
|
+
}
|
|
94
|
+
function breakSoundKeys(material, def, blow3) {
|
|
95
|
+
return { keys: ordered("break", material, impactFamily(def), blow3) };
|
|
96
|
+
}
|
|
97
|
+
function ricochetSoundKeys(material, def) {
|
|
98
|
+
return { keys: ordered("ricochet", material, impactFamily(def), void 0) };
|
|
99
|
+
}
|
|
100
|
+
|
|
41
101
|
// ../game-contracts/dist/index.js
|
|
42
102
|
var DEFAULT_BLAST_SHOVE = { coupling: 0.02, maxSpeed: 20, lift: 0.3, minSpeed: 0.3, falloffPower: 2 };
|
|
43
|
-
function blastShove(
|
|
103
|
+
function blastShove(blast3, target, options = {}) {
|
|
44
104
|
const o = { ...DEFAULT_BLAST_SHOVE, ...options };
|
|
45
|
-
const dx = target.position[0] -
|
|
46
|
-
const dy = target.position[1] -
|
|
47
|
-
const dz = target.position[2] -
|
|
105
|
+
const dx = target.position[0] - blast3.point[0];
|
|
106
|
+
const dy = target.position[1] - blast3.point[1];
|
|
107
|
+
const dz = target.position[2] - blast3.point[2];
|
|
48
108
|
const distance = Math.hypot(dx, dy, dz);
|
|
49
|
-
if (!(
|
|
50
|
-
const falloff = (1 - distance /
|
|
109
|
+
if (!(blast3.radius > 0) || distance > blast3.radius) return void 0;
|
|
110
|
+
const falloff = (1 - distance / blast3.radius) ** o.falloffPower;
|
|
51
111
|
const mass = Math.max(target.mass, 0.05);
|
|
52
|
-
const speed = Math.min(o.maxSpeed, Math.sqrt(2 *
|
|
112
|
+
const speed = Math.min(o.maxSpeed, Math.sqrt(2 * blast3.energy * (blast3.reach ?? 1) * o.coupling / mass)) * falloff;
|
|
53
113
|
if (!(speed >= o.minSpeed)) return void 0;
|
|
54
114
|
const direction = distance > 1e-4 ? [dx / distance, dy / distance + o.lift, dz / distance] : [0, 1, 0];
|
|
55
115
|
const length = Math.hypot(direction[0], direction[1], direction[2]);
|
|
@@ -1873,48 +1933,48 @@ var GameDestructionThree = (() => {
|
|
|
1873
1933
|
}));
|
|
1874
1934
|
}
|
|
1875
1935
|
function spawnFire(pool, random, init, handle) {
|
|
1876
|
-
const
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
return
|
|
1936
|
+
const fire2 = pool.acquire();
|
|
1937
|
+
fire2.x = init.x ?? 0;
|
|
1938
|
+
fire2.y = init.y ?? 0;
|
|
1939
|
+
fire2.z = init.z ?? 0;
|
|
1940
|
+
fire2.r = init.r ?? 0.6;
|
|
1941
|
+
fire2.r0 = init.startRadius ?? fire2.r;
|
|
1942
|
+
fire2.grow = init.grow ?? 0;
|
|
1943
|
+
fire2.life = init.life ?? 6;
|
|
1944
|
+
fire2.t = 0;
|
|
1945
|
+
fire2.rate = init.rate ?? 22;
|
|
1946
|
+
fire2.acc = 0;
|
|
1947
|
+
fire2.smoke = init.smoke ?? 0.6;
|
|
1948
|
+
fire2.smokeAcc = 0;
|
|
1949
|
+
fire2.fade = 1;
|
|
1950
|
+
fire2.follow = init.follow ?? null;
|
|
1951
|
+
fire2.fx = init.fx ?? 0;
|
|
1952
|
+
fire2.fy = init.fy ?? 0;
|
|
1953
|
+
fire2.fz = init.fz ?? 0;
|
|
1954
|
+
fire2.color = init.color ?? SMOKE_COLORS.black;
|
|
1955
|
+
fire2.rng = random;
|
|
1956
|
+
fire2.handle = handle;
|
|
1957
|
+
return fire2;
|
|
1898
1958
|
}
|
|
1899
1959
|
function addFire(core, random, init, handle) {
|
|
1900
|
-
const
|
|
1901
|
-
core.trace?.fire?.(
|
|
1902
|
-
return
|
|
1960
|
+
const fire2 = spawnFire(core.fires, random, init, handle);
|
|
1961
|
+
core.trace?.fire?.(fire2);
|
|
1962
|
+
return fire2;
|
|
1903
1963
|
}
|
|
1904
1964
|
function positionOf(follow) {
|
|
1905
1965
|
return "position" in follow ? follow.position : follow;
|
|
1906
1966
|
}
|
|
1907
|
-
function emitFlames(core,
|
|
1908
|
-
const random =
|
|
1909
|
-
|
|
1910
|
-
while (
|
|
1911
|
-
|
|
1967
|
+
function emitFlames(core, fire2, radius, dt) {
|
|
1968
|
+
const random = fire2.rng;
|
|
1969
|
+
fire2.acc += dt * fire2.rate * (0.5 + radius * 0.9) * fire2.fade * core.clock.lod;
|
|
1970
|
+
while (fire2.acc >= 1) {
|
|
1971
|
+
fire2.acc -= 1;
|
|
1912
1972
|
const angle = random.next() * Math.PI * 2;
|
|
1913
1973
|
const distance = Math.sqrt(random.next()) * radius;
|
|
1914
1974
|
addPuff(core, random, {
|
|
1915
|
-
x:
|
|
1916
|
-
y:
|
|
1917
|
-
z:
|
|
1975
|
+
x: fire2.x + Math.cos(angle) * distance,
|
|
1976
|
+
y: fire2.y + 0.05,
|
|
1977
|
+
z: fire2.z + Math.sin(angle) * distance,
|
|
1918
1978
|
vx: random.between(-0.2, 0.2),
|
|
1919
1979
|
vy: random.between(0.6, 1.4),
|
|
1920
1980
|
vz: random.between(-0.2, 0.2),
|
|
@@ -1926,21 +1986,21 @@ var GameDestructionThree = (() => {
|
|
|
1926
1986
|
hl: random.between(0.35, 0.6),
|
|
1927
1987
|
drag: 1.5,
|
|
1928
1988
|
buoy: 3.2,
|
|
1929
|
-
color:
|
|
1989
|
+
color: fire2.color,
|
|
1930
1990
|
kind: 0,
|
|
1931
1991
|
wind: 0.4
|
|
1932
1992
|
});
|
|
1933
1993
|
}
|
|
1934
1994
|
}
|
|
1935
|
-
function emitSmoke(core,
|
|
1936
|
-
const random =
|
|
1937
|
-
|
|
1938
|
-
while (
|
|
1939
|
-
|
|
1995
|
+
function emitSmoke(core, fire2, radius, dt) {
|
|
1996
|
+
const random = fire2.rng;
|
|
1997
|
+
fire2.smokeAcc += dt * fire2.smoke * (1 + radius * 0.8) * fire2.fade * core.clock.lod;
|
|
1998
|
+
while (fire2.smokeAcc >= 1 && core.layers.smoke) {
|
|
1999
|
+
fire2.smokeAcc -= 1;
|
|
1940
2000
|
addPuff(core, random, {
|
|
1941
|
-
x:
|
|
1942
|
-
y:
|
|
1943
|
-
z:
|
|
2001
|
+
x: fire2.x + random.between(-radius, radius) * 0.5,
|
|
2002
|
+
y: fire2.y + 0.6 + radius * 0.3,
|
|
2003
|
+
z: fire2.z + random.between(-radius, radius) * 0.5,
|
|
1944
2004
|
vy: random.between(0.8, 1.5),
|
|
1945
2005
|
s0: 0.25,
|
|
1946
2006
|
s1: 0.6 + Math.min(radius, 2) * 0.3,
|
|
@@ -1950,18 +2010,18 @@ var GameDestructionThree = (() => {
|
|
|
1950
2010
|
hl: 0.25,
|
|
1951
2011
|
drag: 0.6,
|
|
1952
2012
|
buoy: 0.55,
|
|
1953
|
-
color:
|
|
2013
|
+
color: fire2.color,
|
|
1954
2014
|
kind: 0
|
|
1955
2015
|
});
|
|
1956
2016
|
}
|
|
1957
2017
|
}
|
|
1958
|
-
function emitEmber(core,
|
|
1959
|
-
const random =
|
|
1960
|
-
if (!(random.next() < dt * 6 *
|
|
2018
|
+
function emitEmber(core, fire2, radius, dt) {
|
|
2019
|
+
const random = fire2.rng;
|
|
2020
|
+
if (!(random.next() < dt * 6 * fire2.fade && core.layers.shrapnel)) return;
|
|
1961
2021
|
addSpark(core, {
|
|
1962
|
-
x:
|
|
1963
|
-
y:
|
|
1964
|
-
z:
|
|
2022
|
+
x: fire2.x + random.between(-radius, radius) * 0.6,
|
|
2023
|
+
y: fire2.y + 0.4,
|
|
2024
|
+
z: fire2.z + random.between(-radius, radius) * 0.6,
|
|
1965
2025
|
vx: random.between(-0.4, 0.4),
|
|
1966
2026
|
vy: random.between(1.5, 3.2),
|
|
1967
2027
|
vz: random.between(-0.4, 0.4),
|
|
@@ -1976,24 +2036,24 @@ var GameDestructionThree = (() => {
|
|
|
1976
2036
|
function updateFires(core, dt) {
|
|
1977
2037
|
const pool = core.fires;
|
|
1978
2038
|
for (let index = pool.items.length - 1; index >= 0; index--) {
|
|
1979
|
-
const
|
|
1980
|
-
|
|
1981
|
-
if (
|
|
1982
|
-
const point = positionOf(
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
}
|
|
1987
|
-
const radius =
|
|
1988
|
-
|
|
1989
|
-
if (
|
|
2039
|
+
const fire2 = pool.items[index];
|
|
2040
|
+
fire2.t += dt;
|
|
2041
|
+
if (fire2.follow) {
|
|
2042
|
+
const point = positionOf(fire2.follow);
|
|
2043
|
+
fire2.x = point.x + fire2.fx;
|
|
2044
|
+
fire2.y = point.y + fire2.fy;
|
|
2045
|
+
fire2.z = point.z + fire2.fz;
|
|
2046
|
+
}
|
|
2047
|
+
const radius = fire2.grow ? lerp(fire2.r0, fire2.r, Math.min(1, fire2.t / fire2.grow)) : fire2.r;
|
|
2048
|
+
fire2.fade = fire2.t < fire2.life - 1.5 ? Math.min(1, fire2.t * 3) : Math.max(0, (fire2.life - fire2.t) / 1.5);
|
|
2049
|
+
if (fire2.t >= fire2.life) {
|
|
1990
2050
|
pool.removeAt(index);
|
|
1991
2051
|
continue;
|
|
1992
2052
|
}
|
|
1993
2053
|
if (!core.layers.fire) continue;
|
|
1994
|
-
emitFlames(core,
|
|
1995
|
-
emitSmoke(core,
|
|
1996
|
-
emitEmber(core,
|
|
2054
|
+
emitFlames(core, fire2, radius, dt);
|
|
2055
|
+
emitSmoke(core, fire2, radius, dt);
|
|
2056
|
+
emitEmber(core, fire2, radius, dt);
|
|
1997
2057
|
}
|
|
1998
2058
|
}
|
|
1999
2059
|
var call = (name) => (...args) => ({ $: name, a: args });
|
|
@@ -4458,35 +4518,35 @@ var GameDestructionThree = (() => {
|
|
|
4458
4518
|
var NOOP = () => {
|
|
4459
4519
|
};
|
|
4460
4520
|
function createSchedule() {
|
|
4461
|
-
const
|
|
4521
|
+
const entries2 = [];
|
|
4462
4522
|
const spare = [];
|
|
4463
4523
|
return {
|
|
4464
4524
|
at(time, action) {
|
|
4465
4525
|
const entry = spare.pop() ?? { time: 0, action: NOOP };
|
|
4466
4526
|
entry.time = time;
|
|
4467
4527
|
entry.action = action;
|
|
4468
|
-
|
|
4528
|
+
entries2.push(entry);
|
|
4469
4529
|
},
|
|
4470
4530
|
update(now) {
|
|
4471
|
-
for (let index =
|
|
4472
|
-
const entry =
|
|
4531
|
+
for (let index = entries2.length - 1; index >= 0; index--) {
|
|
4532
|
+
const entry = entries2[index];
|
|
4473
4533
|
if (!entry || entry.time > now) continue;
|
|
4474
4534
|
const action = entry.action;
|
|
4475
|
-
|
|
4535
|
+
entries2.splice(index, 1);
|
|
4476
4536
|
entry.action = NOOP;
|
|
4477
4537
|
spare.push(entry);
|
|
4478
4538
|
action();
|
|
4479
4539
|
}
|
|
4480
4540
|
},
|
|
4481
4541
|
clear() {
|
|
4482
|
-
for (const entry of
|
|
4542
|
+
for (const entry of entries2) {
|
|
4483
4543
|
entry.action = NOOP;
|
|
4484
4544
|
spare.push(entry);
|
|
4485
4545
|
}
|
|
4486
|
-
|
|
4546
|
+
entries2.length = 0;
|
|
4487
4547
|
},
|
|
4488
4548
|
get pending() {
|
|
4489
|
-
return
|
|
4549
|
+
return entries2.length;
|
|
4490
4550
|
}
|
|
4491
4551
|
};
|
|
4492
4552
|
}
|
|
@@ -5174,9 +5234,9 @@ var GameDestructionThree = (() => {
|
|
|
5174
5234
|
}
|
|
5175
5235
|
function largestFire(fires, skip) {
|
|
5176
5236
|
let best = null;
|
|
5177
|
-
for (const
|
|
5178
|
-
if (
|
|
5179
|
-
if (best === null ||
|
|
5237
|
+
for (const fire2 of fires) {
|
|
5238
|
+
if (fire2 === skip) continue;
|
|
5239
|
+
if (best === null || fire2.r > best.r) best = fire2;
|
|
5180
5240
|
}
|
|
5181
5241
|
return best;
|
|
5182
5242
|
}
|
|
@@ -5199,17 +5259,17 @@ var GameDestructionThree = (() => {
|
|
|
5199
5259
|
const second = largestFire(step.fires, first);
|
|
5200
5260
|
const largest = [first, second];
|
|
5201
5261
|
for (let index = 0; index < FIRE_LIGHTS; index++) {
|
|
5202
|
-
const
|
|
5262
|
+
const fire2 = largest[index];
|
|
5203
5263
|
const light = pool.fire[index];
|
|
5204
|
-
if (!
|
|
5264
|
+
if (!fire2) {
|
|
5205
5265
|
light.intensity = 0;
|
|
5206
5266
|
continue;
|
|
5207
5267
|
}
|
|
5208
|
-
light.x =
|
|
5209
|
-
light.y =
|
|
5210
|
-
light.z =
|
|
5211
|
-
light.intensity = (1.4 +
|
|
5212
|
-
light.distance = 10 +
|
|
5268
|
+
light.x = fire2.x;
|
|
5269
|
+
light.y = fire2.y + Math.max(0.8, fire2.r * 0.6);
|
|
5270
|
+
light.z = fire2.z;
|
|
5271
|
+
light.intensity = (1.4 + fire2.r * 0.6) * (0.75 + 0.25 * Math.sin(step.clock * 17 + index * 3) + 0.1 * Math.sin(step.clock * 41)) * fire2.fade;
|
|
5272
|
+
light.distance = 10 + fire2.r * 4;
|
|
5213
5273
|
}
|
|
5214
5274
|
if (brightest && brightness > 0.05) {
|
|
5215
5275
|
pool.glow.x = brightest.x;
|
|
@@ -5241,12 +5301,12 @@ var GameDestructionThree = (() => {
|
|
|
5241
5301
|
var SCORCH_VARIANTS = 3;
|
|
5242
5302
|
var RIM_COLORS = [2829359, 3815478];
|
|
5243
5303
|
function createMarkStore() {
|
|
5244
|
-
const
|
|
5304
|
+
const entries2 = [];
|
|
5245
5305
|
let version = 0;
|
|
5246
5306
|
let bloodCount = 0;
|
|
5247
5307
|
const listeners = /* @__PURE__ */ new Set();
|
|
5248
5308
|
return {
|
|
5249
|
-
entries,
|
|
5309
|
+
entries: entries2,
|
|
5250
5310
|
get version() {
|
|
5251
5311
|
return version;
|
|
5252
5312
|
},
|
|
@@ -5255,13 +5315,13 @@ var GameDestructionThree = (() => {
|
|
|
5255
5315
|
},
|
|
5256
5316
|
lift: 0,
|
|
5257
5317
|
add(mark) {
|
|
5258
|
-
|
|
5318
|
+
entries2.push(mark);
|
|
5259
5319
|
if (mark.kind === "blood") bloodCount++;
|
|
5260
5320
|
version++;
|
|
5261
5321
|
for (const listener of listeners) listener({ type: "add", mark });
|
|
5262
5322
|
},
|
|
5263
5323
|
clear() {
|
|
5264
|
-
|
|
5324
|
+
entries2.length = 0;
|
|
5265
5325
|
bloodCount = 0;
|
|
5266
5326
|
this.lift = 0;
|
|
5267
5327
|
version++;
|
|
@@ -5715,18 +5775,18 @@ var GameDestructionThree = (() => {
|
|
|
5715
5775
|
}
|
|
5716
5776
|
if (def.mushroom && core.layers.fire) composeMushroom(context, def.mushroom);
|
|
5717
5777
|
if (def.residualFires && core.layers.fire) {
|
|
5718
|
-
for (const
|
|
5778
|
+
for (const fire2 of def.residualFires) {
|
|
5719
5779
|
addFire(core, random, {
|
|
5720
|
-
x: x + (
|
|
5780
|
+
x: x + (fire2.dx ?? 0),
|
|
5721
5781
|
y: 0,
|
|
5722
|
-
z: z + (
|
|
5723
|
-
r:
|
|
5724
|
-
life:
|
|
5725
|
-
rate:
|
|
5726
|
-
smoke:
|
|
5727
|
-
startRadius:
|
|
5728
|
-
grow:
|
|
5729
|
-
color:
|
|
5782
|
+
z: z + (fire2.dz ?? 0),
|
|
5783
|
+
r: fire2.radius,
|
|
5784
|
+
life: fire2.life,
|
|
5785
|
+
rate: fire2.rate,
|
|
5786
|
+
smoke: fire2.smoke,
|
|
5787
|
+
startRadius: fire2.startRadius,
|
|
5788
|
+
grow: fire2.grow,
|
|
5789
|
+
color: fire2.smokeColor !== void 0 ? hexToLinearRgb(fire2.smokeColor) : void 0
|
|
5730
5790
|
}, context.call.handle);
|
|
5731
5791
|
}
|
|
5732
5792
|
}
|
|
@@ -7398,7 +7458,7 @@ var GameDestructionThree = (() => {
|
|
|
7398
7458
|
function scaleDefinition(def, factor) {
|
|
7399
7459
|
if (factor === 1) return def;
|
|
7400
7460
|
const mushroom = def.mushroom && { ...def.mushroom, height: def.mushroom.height * factor, radius: def.mushroom.radius * factor };
|
|
7401
|
-
const residual = def.residualFires?.map((
|
|
7461
|
+
const residual = def.residualFires?.map((fire2) => ({ ...fire2, radius: fire2.radius * factor, dx: (fire2.dx ?? 0) * factor, dz: (fire2.dz ?? 0) * factor }));
|
|
7402
7462
|
return {
|
|
7403
7463
|
...def,
|
|
7404
7464
|
lethal: def.lethal * factor,
|
|
@@ -7968,13 +8028,13 @@ void main(){
|
|
|
7968
8028
|
function createLightLayer(THREE, pool, scale, budget) {
|
|
7969
8029
|
const group = new THREE.Group();
|
|
7970
8030
|
if (budget) return createBudgetedLightLayer(group, pool, scale, budget);
|
|
7971
|
-
const
|
|
8031
|
+
const blast3 = pool.blast.map(() => {
|
|
7972
8032
|
const light = new THREE.PointLight(16752720, 0, 30, 2);
|
|
7973
8033
|
light.position.set(0, -50, 0);
|
|
7974
8034
|
group.add(light);
|
|
7975
8035
|
return light;
|
|
7976
8036
|
});
|
|
7977
|
-
const
|
|
8037
|
+
const fire2 = pool.fire.map(() => {
|
|
7978
8038
|
const light = new THREE.PointLight(16742954, 0, 16, 2);
|
|
7979
8039
|
light.position.set(0, -50, 0);
|
|
7980
8040
|
group.add(light);
|
|
@@ -7985,7 +8045,7 @@ void main(){
|
|
|
7985
8045
|
sync() {
|
|
7986
8046
|
let lit = 0;
|
|
7987
8047
|
pool.blast.forEach((entry, index) => {
|
|
7988
|
-
const light =
|
|
8048
|
+
const light = blast3[index];
|
|
7989
8049
|
light.position.set(entry.x, entry.y, entry.z);
|
|
7990
8050
|
light.distance = entry.distance;
|
|
7991
8051
|
light.color.setRGB(entry.color[0], entry.color[1], entry.color[2], THREE.LinearSRGBColorSpace);
|
|
@@ -7993,7 +8053,7 @@ void main(){
|
|
|
7993
8053
|
if (entry.intensity > 0.05) lit++;
|
|
7994
8054
|
});
|
|
7995
8055
|
pool.fire.forEach((entry, index) => {
|
|
7996
|
-
const light =
|
|
8056
|
+
const light = fire2[index];
|
|
7997
8057
|
light.position.set(entry.x, entry.y, entry.z);
|
|
7998
8058
|
light.distance = entry.distance;
|
|
7999
8059
|
light.intensity = entry.intensity * scale;
|
|
@@ -8002,31 +8062,31 @@ void main(){
|
|
|
8002
8062
|
return lit;
|
|
8003
8063
|
},
|
|
8004
8064
|
dispose() {
|
|
8005
|
-
for (const light of [...
|
|
8065
|
+
for (const light of [...blast3, ...fire2]) light.dispose();
|
|
8006
8066
|
}
|
|
8007
8067
|
};
|
|
8008
8068
|
}
|
|
8009
8069
|
function createBudgetedLightLayer(group, pool, scale, budget) {
|
|
8010
|
-
const
|
|
8011
|
-
const
|
|
8070
|
+
const blast3 = pool.blast.map(() => null);
|
|
8071
|
+
const fire2 = pool.fire.map(() => null);
|
|
8012
8072
|
return {
|
|
8013
8073
|
group,
|
|
8014
8074
|
sync() {
|
|
8015
8075
|
let lit = 0;
|
|
8016
8076
|
pool.blast.forEach((entry, index) => {
|
|
8017
8077
|
const request = { owner: "vfx.blast", priority: LIGHT_PRIORITY.blast, urgent: true, color: entry.color, intensity: entry.intensity * scale, distance: entry.distance, decay: BLAST_DECAY, position: [entry.x, entry.y, entry.z] };
|
|
8018
|
-
followEntry(budget,
|
|
8078
|
+
followEntry(budget, blast3, index, entry, request);
|
|
8019
8079
|
if (entry.intensity > LIGHT_ON_THRESHOLD) lit++;
|
|
8020
8080
|
});
|
|
8021
8081
|
pool.fire.forEach((entry, index) => {
|
|
8022
8082
|
const request = { owner: "vfx.fire", priority: LIGHT_PRIORITY.fire, color: FIRE_COLOR, intensity: entry.intensity * scale, distance: entry.distance, decay: FIRE_DECAY, position: [entry.x, entry.y, entry.z] };
|
|
8023
|
-
followEntry(budget,
|
|
8083
|
+
followEntry(budget, fire2, index, entry, request);
|
|
8024
8084
|
if (entry.intensity > LIGHT_ON_THRESHOLD) lit++;
|
|
8025
8085
|
});
|
|
8026
8086
|
return lit;
|
|
8027
8087
|
},
|
|
8028
8088
|
dispose() {
|
|
8029
|
-
for (const handle of [...
|
|
8089
|
+
for (const handle of [...blast3, ...fire2]) handle?.release({ fadeMs: 0 });
|
|
8030
8090
|
}
|
|
8031
8091
|
};
|
|
8032
8092
|
}
|
|
@@ -8924,7 +8984,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8924
8984
|
}
|
|
8925
8985
|
function budgetedLights(engine, lightScale, budget) {
|
|
8926
8986
|
const flash2 = engine.lights.lights.map(() => null);
|
|
8927
|
-
const
|
|
8987
|
+
const fire2 = engine.lights.fire.map(() => null);
|
|
8928
8988
|
return {
|
|
8929
8989
|
sync() {
|
|
8930
8990
|
engine.lights.lights.forEach((source, index) => {
|
|
@@ -8933,11 +8993,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8933
8993
|
});
|
|
8934
8994
|
engine.lights.fire.forEach((source, index) => {
|
|
8935
8995
|
const request = { owner: "vfx.workshop", priority: LIGHT_PRIORITY.fire, color: FIRE_LIGHT_COLOR, intensity: source.intensity * lightScale, distance: FIRE_LIGHT_DISTANCE, position: [source.x, source.y, source.z] };
|
|
8936
|
-
followEntry(budget,
|
|
8996
|
+
followEntry(budget, fire2, index, source, request);
|
|
8937
8997
|
});
|
|
8938
8998
|
},
|
|
8939
8999
|
dispose() {
|
|
8940
|
-
for (const handle of [...flash2, ...
|
|
9000
|
+
for (const handle of [...flash2, ...fire2]) handle?.release({ fadeMs: 0 });
|
|
8941
9001
|
}
|
|
8942
9002
|
};
|
|
8943
9003
|
}
|
|
@@ -9301,10 +9361,10 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
9301
9361
|
*/
|
|
9302
9362
|
warmMeshes() {
|
|
9303
9363
|
const opaque = this.materialFor("warm", 8421504, false);
|
|
9304
|
-
const
|
|
9364
|
+
const glass2 = this.materialFor("warm", 8421504, true);
|
|
9305
9365
|
const geometries = [this.box, ...Array.from({ length: SHARD_SHAPES }, (_, index) => this.shardGeometry(index))];
|
|
9306
9366
|
const { geometry, material } = this.markParts();
|
|
9307
|
-
return [...geometries.flatMap((shared) => [new this.THREE.Mesh(shared, opaque), new this.THREE.Mesh(shared,
|
|
9367
|
+
return [...geometries.flatMap((shared) => [new this.THREE.Mesh(shared, opaque), new this.THREE.Mesh(shared, glass2)]), new this.THREE.Mesh(geometry, material)];
|
|
9308
9368
|
}
|
|
9309
9369
|
/**
|
|
9310
9370
|
* Bullet holes that stay on a fragment (`Fragment.marks`): dark discs that are children of its mesh, so they fall, spin and settle with it. The mesh is
|
|
@@ -9655,6 +9715,9 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
9655
9715
|
};
|
|
9656
9716
|
|
|
9657
9717
|
// src/pieces.ts
|
|
9718
|
+
var SLAM_MIN_SPEED = 2;
|
|
9719
|
+
var SLAM_BOUNCE = 0.2;
|
|
9720
|
+
var SLAM_FLOOR_NORMAL = 0.7;
|
|
9658
9721
|
var SUB_DT = 1 / 120;
|
|
9659
9722
|
var MU = 0.7;
|
|
9660
9723
|
var SLEEP_AFTER = 0.5;
|
|
@@ -9889,9 +9952,34 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
9889
9952
|
const fixed = this.o.staticTopAt?.(x, z, y, step) ?? -Infinity;
|
|
9890
9953
|
return Math.max(top, fixed);
|
|
9891
9954
|
}
|
|
9955
|
+
/** Stops a piece that ran into something on its way from `start` to `pos` (`sweep`): moves it back to where it met it and takes the speed into it. */
|
|
9956
|
+
sweepOn(b, start, pos) {
|
|
9957
|
+
const travel = Math.hypot(pos[0] - start[0], pos[1] - start[1], pos[2] - start[2]);
|
|
9958
|
+
if (travel < 1e-3) return;
|
|
9959
|
+
const hit = this.o.sweep?.(b, start, pos);
|
|
9960
|
+
if (!hit || hit.normal[1] > SLAM_FLOOR_NORMAL) return;
|
|
9961
|
+
const v = b.velocity;
|
|
9962
|
+
const n = hit.normal;
|
|
9963
|
+
const into = -(v[0] * n[0] + v[1] * n[1] + v[2] * n[2]);
|
|
9964
|
+
if (into <= 0) return;
|
|
9965
|
+
const k = Math.min(1, hit.distance / travel);
|
|
9966
|
+
for (let i = 0; i < 3; i++) {
|
|
9967
|
+
pos[i] = start[i] + (pos[i] - start[i]) * k;
|
|
9968
|
+
v[i] += (1 + SLAM_BOUNCE) * into * n[i];
|
|
9969
|
+
}
|
|
9970
|
+
const w = b.angularVelocity;
|
|
9971
|
+
w[0] *= 0.5;
|
|
9972
|
+
w[1] *= 0.5;
|
|
9973
|
+
w[2] *= 0.5;
|
|
9974
|
+
if (into >= SLAM_MIN_SPEED && this.time - b.lastHit > 0.15) {
|
|
9975
|
+
b.lastHit = this.time;
|
|
9976
|
+
this.o.onSlam?.(b, hit, into);
|
|
9977
|
+
}
|
|
9978
|
+
}
|
|
9892
9979
|
integrate(b, dt) {
|
|
9893
9980
|
const c = this.centerOf(b, this.p);
|
|
9894
9981
|
const pos = [c.x, c.y, c.z];
|
|
9982
|
+
const start = [c.x, c.y, c.z];
|
|
9895
9983
|
const q = this.q.copy(b.root.quaternion);
|
|
9896
9984
|
const v = b.velocity;
|
|
9897
9985
|
const w = b.angularVelocity;
|
|
@@ -10001,11 +10089,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
10001
10089
|
if (contactedLast) touched = true;
|
|
10002
10090
|
if (!contactedLast) continue;
|
|
10003
10091
|
pos[1] += Math.max(0, maxPen - SLOP * 0.5);
|
|
10004
|
-
let
|
|
10005
|
-
for (const r of rs)
|
|
10006
|
-
const restitution =
|
|
10007
|
-
if (
|
|
10008
|
-
landing2 =
|
|
10092
|
+
let impact3 = 0;
|
|
10093
|
+
for (const r of rs) impact3 = Math.max(impact3, -(v[1] + w[2] * r[0] - w[0] * r[2]));
|
|
10094
|
+
const restitution = impact3 > 2 ? 0.25 : 0;
|
|
10095
|
+
if (impact3 > landing2) {
|
|
10096
|
+
landing2 = impact3;
|
|
10009
10097
|
let sx = 0;
|
|
10010
10098
|
let sz = 0;
|
|
10011
10099
|
for (const r of rs) {
|
|
@@ -10136,6 +10224,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
10136
10224
|
v[0] *= fd;
|
|
10137
10225
|
v[2] *= fd;
|
|
10138
10226
|
}
|
|
10227
|
+
if (this.o.sweep && !b.held) this.sweepOn(b, start, pos);
|
|
10139
10228
|
b.root.quaternion.copy(q);
|
|
10140
10229
|
const off = this.ax.copy(b.centerV).applyQuaternion(q);
|
|
10141
10230
|
b.root.position.set(pos[0] - off.x, pos[1] - off.y, pos[2] - off.z);
|
|
@@ -11724,7 +11813,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
11724
11813
|
const fallback2 = options.fallback ?? "plastic";
|
|
11725
11814
|
const minSize = options.minSize ?? 0.015;
|
|
11726
11815
|
const inv = specFrameInverse(THREE, root);
|
|
11727
|
-
const
|
|
11816
|
+
const entries2 = [];
|
|
11728
11817
|
const byKey = /* @__PURE__ */ new Map();
|
|
11729
11818
|
const visit = (o) => {
|
|
11730
11819
|
if (!o.visible || o.userData?.destructionIgnore) return;
|
|
@@ -11761,8 +11850,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
11761
11850
|
if (powder) existing.powder = powder;
|
|
11762
11851
|
if (thickness !== void 0) existing.thickness = Math.min(existing.thickness ?? thickness, thickness);
|
|
11763
11852
|
} else {
|
|
11764
|
-
const e = { key: explicit ?? `m${
|
|
11765
|
-
|
|
11853
|
+
const e = { key: explicit ?? `m${entries2.length}`, meshes: [o], box, material, explicitId: explicit, fill, hollow, skin, tags, fixedId: !!explicit, ...contains ? { contains } : {}, ...powder ? { powder } : {}, ...thickness !== void 0 ? { thickness } : {}, name: o.name, parent: hint?.parent, jointKind: hint?.kind };
|
|
11854
|
+
entries2.push(e);
|
|
11766
11855
|
if (explicit) byKey.set(explicit, e);
|
|
11767
11856
|
}
|
|
11768
11857
|
}
|
|
@@ -11780,7 +11869,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
11780
11869
|
const largest = (e) => Math.max(...sizeOf(e.box));
|
|
11781
11870
|
const kept = [];
|
|
11782
11871
|
const tiny = [];
|
|
11783
|
-
for (const e of
|
|
11872
|
+
for (const e of entries2) (e.skin || !e.fixedId && largest(e) < minSize ? tiny : kept).push(e);
|
|
11784
11873
|
for (const t of tiny) {
|
|
11785
11874
|
let best = null;
|
|
11786
11875
|
let bestV = 0;
|
|
@@ -12939,12 +13028,14 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
12939
13028
|
var QUEUE_CAP = 4e3;
|
|
12940
13029
|
var MIN_FRAGMENTS_PER_SLICE = 8;
|
|
12941
13030
|
var STATIC_REFRESH = 0.5;
|
|
13031
|
+
var STATIC_REFRESH_SLICE_MS = 1;
|
|
12942
13032
|
var STATIC_SPAN = 3;
|
|
12943
13033
|
var FEET_BAND = 0.03;
|
|
12944
13034
|
var TIP_MIN_HEIGHT = 0.3;
|
|
12945
13035
|
var TIP_NARROW = 0.3;
|
|
12946
13036
|
var FIRE_CEILING_SECONDS = 3600;
|
|
12947
13037
|
var GENERIC_REFERENCE_RADIUS = 15;
|
|
13038
|
+
var SWEEP_CORE = 0.15;
|
|
12948
13039
|
var PRIMED_FIRE_RADIUS = 0.2;
|
|
12949
13040
|
var FLUID_COLORS = {
|
|
12950
13041
|
water: 9226495,
|
|
@@ -12987,6 +13078,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
12987
13078
|
if (def.fracture === "tear") return "impact_soft";
|
|
12988
13079
|
return def.fracture === "none" ? "impact_metal" : "impact_wood";
|
|
12989
13080
|
}
|
|
13081
|
+
var shotKey = (def) => impactKey(def).replace("impact_", "shot_");
|
|
12990
13082
|
var dragSoundKey = (def) => impactKey(def).replace("impact_", "drag_");
|
|
12991
13083
|
function fractureKey(def, style) {
|
|
12992
13084
|
switch (style) {
|
|
@@ -13036,6 +13128,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13036
13128
|
/** Objects to measure again; `staticAll` measures every one. */
|
|
13037
13129
|
__publicField(this, "staticDirty", /* @__PURE__ */ new Set());
|
|
13038
13130
|
__publicField(this, "staticAll", true);
|
|
13131
|
+
/** The periodic refresh: the objects still to measure again in this round, a slice per call. */
|
|
13132
|
+
__publicField(this, "staticRound", []);
|
|
13039
13133
|
/** Boxes of the pieces' meshes (as `staticBoxes`), with the time they were measured. */
|
|
13040
13134
|
__publicField(this, "pieceBoxes", /* @__PURE__ */ new WeakMap());
|
|
13041
13135
|
__publicField(this, "staticAt", 0);
|
|
@@ -13127,7 +13221,9 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13127
13221
|
staticTopAt: (x, z, y, step) => this.staticTopAt(x, z, y, step),
|
|
13128
13222
|
gravity: this.gravity,
|
|
13129
13223
|
scene: o.scene,
|
|
13130
|
-
onHardLanding: (p, point, speed) => this.hardLanding(p, point, speed)
|
|
13224
|
+
onHardLanding: (p, point, speed) => this.hardLanding(p, point, speed),
|
|
13225
|
+
sweep: (p, from, to) => this.sweepPiece(p, from, to),
|
|
13226
|
+
onSlam: (p, hit, speed) => this.slam(p, hit, speed)
|
|
13131
13227
|
});
|
|
13132
13228
|
this.unsubscribe = this.world.on("*", (ev) => {
|
|
13133
13229
|
if (this.queue.length < QUEUE_CAP) this.queue.push(ev);
|
|
@@ -13317,26 +13413,58 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13317
13413
|
const p = this.pieceSys.get(objectId);
|
|
13318
13414
|
if (p) this.pieceSys.impulse(p, impulse, point);
|
|
13319
13415
|
}
|
|
13416
|
+
/**
|
|
13417
|
+
* What a piece moving from `from` to `to` runs into: the core of its box (its thinnest half each way, at most `SWEEP_CORE`) swept through the world, the piece itself left out,
|
|
13418
|
+
* so a crate thrown by a blast stops at the wall instead of passing through it. Null for a world that cannot sweep.
|
|
13419
|
+
*/
|
|
13420
|
+
sweepPiece(p, from, to) {
|
|
13421
|
+
if (typeof this.world.sweepBox !== "function") return null;
|
|
13422
|
+
const d = [to[0] - from[0], to[1] - from[1], to[2] - from[2]];
|
|
13423
|
+
const travel = Math.hypot(d[0], d[1], d[2]);
|
|
13424
|
+
if (travel < 1e-4) return null;
|
|
13425
|
+
const core = Math.min(SWEEP_CORE, ...p.halfExtents);
|
|
13426
|
+
const box = { min: [from[0] - core, from[1] - core, from[2] - core], max: [from[0] + core, from[1] + core, from[2] + core] };
|
|
13427
|
+
const hit = this.world.sweepBox(box, d, travel, { ignore: p.objectId, spacing: Math.max(0.05, core) });
|
|
13428
|
+
if (!hit) return null;
|
|
13429
|
+
return { object: hit.object, part: hit.part, distance: hit.distance, point: hit.point, normal: hit.normal };
|
|
13430
|
+
}
|
|
13431
|
+
/** A piece thrown into a wall: the wall takes the blow of its weight where it met it, the piece takes it too, and each sounds as its material does. */
|
|
13432
|
+
slam(p, hit, speed) {
|
|
13433
|
+
const energy = 0.5 * p.mass * speed * speed;
|
|
13434
|
+
const direction = [-hit.normal[0], -hit.normal[1], -hit.normal[2]];
|
|
13435
|
+
this.landingSound(hit.object, hit.point, clamp6(speed / 10, 0.2, 1));
|
|
13436
|
+
this.syncBound(p.objectId);
|
|
13437
|
+
try {
|
|
13438
|
+
this.world.hitPart(hit.object, hit.part, { type: "blunt", point: hit.point, energy, radius: 0.1, direction, normal: hit.normal, source: p.objectId });
|
|
13439
|
+
this.world.hit(p.objectId, { type: "blunt", point: hit.point, energy, radius: 0.08, direction: hit.normal, source: "slam" });
|
|
13440
|
+
} catch {
|
|
13441
|
+
}
|
|
13442
|
+
}
|
|
13320
13443
|
hardLanding(p, point, speed) {
|
|
13321
|
-
|
|
13322
|
-
this.sound(key, point, clamp6(speed / 10, 0.2, 1));
|
|
13444
|
+
this.landingSound(p.objectId, point, clamp6(speed / 10, 0.2, 1));
|
|
13323
13445
|
this.syncBound(p.objectId);
|
|
13324
13446
|
try {
|
|
13325
13447
|
this.world.hit(p.objectId, { type: "blunt", point, energy: 0.5 * p.mass * speed * speed, radius: 0.08, direction: [0, -1, 0], source: "fall" });
|
|
13326
13448
|
} catch {
|
|
13327
13449
|
}
|
|
13328
13450
|
}
|
|
13329
|
-
|
|
13451
|
+
/** The impact of the heaviest part of an object (a piece landing): its material and the blunt blow of the fall. */
|
|
13452
|
+
landingSound(objectId, point, volume) {
|
|
13330
13453
|
const st = this.world.state(objectId);
|
|
13331
|
-
let best;
|
|
13454
|
+
let best = "";
|
|
13332
13455
|
let mass = -1;
|
|
13333
13456
|
for (const p of st?.parts ?? []) {
|
|
13334
13457
|
if (p.mass > mass) {
|
|
13335
13458
|
mass = p.mass;
|
|
13336
|
-
best =
|
|
13459
|
+
best = p.material;
|
|
13337
13460
|
}
|
|
13338
13461
|
}
|
|
13339
|
-
|
|
13462
|
+
this.impactSound(best, point, volume, "blunt");
|
|
13463
|
+
}
|
|
13464
|
+
/** The impact on a material by a blow: the legacy family key (`impactKey`) with the more specific keys to try first (`impactSoundKeys`). */
|
|
13465
|
+
impactSound(material, point, volume, blow3) {
|
|
13466
|
+
const def = this.world.materials.get(material);
|
|
13467
|
+
this.sound(impactKey(def), point, volume, impactSoundKeys(material, def, blow3));
|
|
13340
13468
|
}
|
|
13341
13469
|
// ----------------------------------------------------------------------------------------------------------------------------------
|
|
13342
13470
|
// Update
|
|
@@ -13468,9 +13596,9 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13468
13596
|
staticNow() {
|
|
13469
13597
|
if (this.time - this.staticAt > STATIC_REFRESH) {
|
|
13470
13598
|
this.staticAt = this.time;
|
|
13471
|
-
this.
|
|
13599
|
+
if (this.staticRound.length === 0) this.staticRound = [...this.bounds.keys()].reverse();
|
|
13472
13600
|
}
|
|
13473
|
-
if (!this.staticAll && this.staticDirty.size === 0) return this.staticBoxes;
|
|
13601
|
+
if (!this.staticAll && this.staticDirty.size === 0 && this.staticRound.length === 0) return this.staticBoxes;
|
|
13474
13602
|
const box = new this.THREE.Box3();
|
|
13475
13603
|
const measure = (b) => {
|
|
13476
13604
|
if (b.piece || this.pieceSys.get(b.id)) {
|
|
@@ -13490,14 +13618,21 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13490
13618
|
}
|
|
13491
13619
|
this.staticBoxes.set(b.id, out.length > 6 ? out : []);
|
|
13492
13620
|
};
|
|
13621
|
+
const measureId = (id) => {
|
|
13622
|
+
const b = this.bounds.get(id);
|
|
13623
|
+
if (b) measure(b);
|
|
13624
|
+
else this.staticBoxes.delete(id);
|
|
13625
|
+
};
|
|
13493
13626
|
if (this.staticAll) {
|
|
13494
13627
|
this.staticBoxes.clear();
|
|
13495
13628
|
for (const b of this.bounds.values()) measure(b);
|
|
13629
|
+
this.staticRound = [];
|
|
13496
13630
|
} else {
|
|
13497
|
-
for (const id of this.staticDirty)
|
|
13498
|
-
|
|
13499
|
-
|
|
13500
|
-
|
|
13631
|
+
for (const id of this.staticDirty) measureId(id);
|
|
13632
|
+
const until = performance.now() + STATIC_REFRESH_SLICE_MS;
|
|
13633
|
+
while (this.staticRound.length > 0) {
|
|
13634
|
+
measureId(this.staticRound.pop());
|
|
13635
|
+
if (performance.now() >= until) break;
|
|
13501
13636
|
}
|
|
13502
13637
|
}
|
|
13503
13638
|
this.staticAll = false;
|
|
@@ -13557,7 +13692,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13557
13692
|
case "ricochet": {
|
|
13558
13693
|
const d = ev.direction;
|
|
13559
13694
|
this.vfx.burst("sparks", ev.point, d, 4 + Math.min(10, ev.energy / 150), 4);
|
|
13560
|
-
this.
|
|
13695
|
+
const glanced = this.partVis(ev.object, ev.part)?.material ?? "";
|
|
13696
|
+
this.sound("ricochet", ev.point, 0.7, ricochetSoundKeys(glanced, this.world.materials.get(glanced)));
|
|
13561
13697
|
break;
|
|
13562
13698
|
}
|
|
13563
13699
|
case "debris":
|
|
@@ -13599,7 +13735,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13599
13735
|
this.vfx.fire({ point: ev.point, radius: PRIMED_FIRE_RADIUS, life: ev.delay });
|
|
13600
13736
|
this.primedBurning.add(`${ev.object}|${ev.part}`);
|
|
13601
13737
|
this.activate(ev.object, ev.part);
|
|
13602
|
-
this.sound("
|
|
13738
|
+
this.sound("primed", ev.point, 0.7, { seconds: ev.delay });
|
|
13603
13739
|
this.sound("burn_loop", ev.point, 0.5);
|
|
13604
13740
|
}
|
|
13605
13741
|
break;
|
|
@@ -13713,8 +13849,9 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13713
13849
|
const b = this.bounds.get(objectId);
|
|
13714
13850
|
return b ? [b.root.position.x, b.root.position.y, b.root.position.z] : [0, 0, 0];
|
|
13715
13851
|
}
|
|
13716
|
-
sound(key, point, volume) {
|
|
13717
|
-
this.o.onSound?.(key, point, volume);
|
|
13852
|
+
sound(key, point, volume, detail) {
|
|
13853
|
+
if (detail) this.o.onSound?.(key, point, volume, detail);
|
|
13854
|
+
else this.o.onSound?.(key, point, volume);
|
|
13718
13855
|
}
|
|
13719
13856
|
partVis(objectId, partId) {
|
|
13720
13857
|
return this.bounds.get(objectId)?.parts.get(partId) ?? null;
|
|
@@ -13779,7 +13916,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13779
13916
|
const reach = shown.reduce((widest, mv) => Math.max(widest, this.visuals.dentReach(mv, wp, ev.dent)), ev.dent.radius);
|
|
13780
13917
|
this.visuals.applyPartDent(shown, wp, wn, ev.dent, reach);
|
|
13781
13918
|
if (def?.tags?.includes("metal")) this.vfx.burst("sparks", ev.worldPoint, [wn.x, wn.y, wn.z], 4 + Math.min(8, ev.dent.depth * 150), 3.2);
|
|
13782
|
-
this.
|
|
13919
|
+
this.impactSound(pv.material, ev.worldPoint, clamp6(0.3 + ev.dent.depth * 12, 0.3, 1), ev.blow);
|
|
13783
13920
|
}
|
|
13784
13921
|
onHole(ev) {
|
|
13785
13922
|
const b = this.bounds.get(ev.object);
|
|
@@ -13808,7 +13945,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13808
13945
|
this.vfx.burst("dust", ev.worldPoint, [n.x, n.y, n.z], this.low ? 5 : 10, 0.7, puff3);
|
|
13809
13946
|
if (ev.hole.through && ev.exitPoint) this.vfx.burst("dust", ev.exitPoint, [-n.x, -n.y, -n.z], this.low ? 10 : 20, 1.3, puff3);
|
|
13810
13947
|
}
|
|
13811
|
-
this.sound(
|
|
13948
|
+
this.sound(shotKey(def), ev.worldPoint, 0.6, impactSoundKeys(pv.material, def, ev.blow));
|
|
13812
13949
|
}
|
|
13813
13950
|
onCrack(ev) {
|
|
13814
13951
|
const b = this.bounds.get(ev.object);
|
|
@@ -13818,13 +13955,13 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13818
13955
|
const wp = new this.THREE.Vector3(ev.worldPoint[0], ev.worldPoint[1], ev.worldPoint[2]);
|
|
13819
13956
|
const mv = this.nearestMesh(pv, wp);
|
|
13820
13957
|
if (mv) {
|
|
13821
|
-
const
|
|
13958
|
+
const glass2 = !!def?.visual?.transparent;
|
|
13822
13959
|
const own = this.partColor(pv, def) ?? fallbackColor(pv.material, def);
|
|
13823
|
-
const color =
|
|
13824
|
-
const length =
|
|
13960
|
+
const color = glass2 ? 15267071 : new this.THREE.Color(own).multiplyScalar(0.45).getHex();
|
|
13961
|
+
const length = glass2 ? ev.crack.length : Math.min(ev.crack.length, OPAQUE_CRACK);
|
|
13825
13962
|
this.visuals.addCrack(mv, wp, this.worldDir(b, ev.crack.normal), ev.crack.rays, length, color, hashNumbers(ev.time, ev.worldPoint[0], ev.worldPoint[1], ev.worldPoint[2]));
|
|
13826
13963
|
}
|
|
13827
|
-
this.
|
|
13964
|
+
this.impactSound(pv.material, ev.worldPoint, 0.5, ev.blow);
|
|
13828
13965
|
}
|
|
13829
13966
|
/** Outward normal of the face of `mv` nearest to a world point: the thin axis of its world box (right for a wall; a sloped face is left to the vertex-range binding). */
|
|
13830
13967
|
faceNormal(mv, point) {
|
|
@@ -13881,7 +14018,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13881
14018
|
this.fragments.spawn(fr, this.fragments.materialFor(fr.material, fdef === def || !fdef ? color : fallbackColor(fr.material, fdef), false), ev.object, maxAlive);
|
|
13882
14019
|
}
|
|
13883
14020
|
if (!played) this.vfx.burst("dust", ev.opening.center, [0, 1, 0], 14, 1.2, { color });
|
|
13884
|
-
this.
|
|
14021
|
+
this.impactSound(pv?.material ?? "", ev.opening.center, 0.8, ev.blow);
|
|
13885
14022
|
}
|
|
13886
14023
|
/**
|
|
13887
14024
|
* A unit came out of a wall of units: the unit flies as a fragment with a puff of its dust, and the marks drawn on it (bullet holes, spalls, the impact
|
|
@@ -13899,7 +14036,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13899
14036
|
this.fragments.spawn(fr, this.fragments.materialFor(fr.material, tone, false), ev.object, maxAlive);
|
|
13900
14037
|
}
|
|
13901
14038
|
if (ev.torn) {
|
|
13902
|
-
this.
|
|
14039
|
+
this.impactSound(pv?.material ?? "", ev.center, 0.5, ev.blow);
|
|
13903
14040
|
return;
|
|
13904
14041
|
}
|
|
13905
14042
|
const T = this.THREE;
|
|
@@ -13909,7 +14046,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13909
14046
|
for (const part of this.bounds.get(ev.object)?.parts.values() ?? []) for (const mv of part.meshes) this.visuals.clearDecals(mv, center, half, rotation2);
|
|
13910
14047
|
this.vfx.peekWorkshop()?.decals.clearInside(ev.center, [half.x, half.y, half.z], ev.rotation);
|
|
13911
14048
|
this.vfx.burst("dust", ev.center, [0, 1, 0], 8, 0.8, { color });
|
|
13912
|
-
this.
|
|
14049
|
+
this.impactSound(pv?.material ?? "", ev.center, 0.7, ev.blow);
|
|
13913
14050
|
}
|
|
13914
14051
|
onFracture(ev) {
|
|
13915
14052
|
const b = this.bounds.get(ev.object);
|
|
@@ -13950,7 +14087,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
13950
14087
|
default:
|
|
13951
14088
|
this.vfx.burst("sparks", ev.point, up, 10, 4);
|
|
13952
14089
|
}
|
|
13953
|
-
this.sound(fractureKey(def, ev.style), ev.point, clamp6(0.4 + ev.fragments.length * 0.03, 0.4, 1));
|
|
14090
|
+
this.sound(fractureKey(def, ev.style), ev.point, clamp6(0.4 + ev.fragments.length * 0.03, 0.4, 1), breakSoundKeys(matId, def, ev.blow));
|
|
13954
14091
|
}
|
|
13955
14092
|
/** Spawns the fragments of a fracture from index `from`; what does not fit in this frame's budget is spawned by the next frames. */
|
|
13956
14093
|
spawnFragments(ev, from, look) {
|
|
@@ -14087,10 +14224,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14087
14224
|
const report = options.report;
|
|
14088
14225
|
const confinement = report?.find((r) => r.blast !== void 0)?.blast?.confinement ?? 1;
|
|
14089
14226
|
const energy = ev.energy * confinement;
|
|
14090
|
-
const reachOf = (objectId) => report?.find((r) => r.object === objectId)?.blast?.shelter ?? 1;
|
|
14227
|
+
const reachOf = (objectId, at3) => report?.find((r) => r.object === objectId)?.blast?.shelter ?? this.world.blastReach?.(p, at3, { ignore: ev.object ? [ev.object, objectId] : [objectId] }) ?? 1;
|
|
14091
14228
|
const shove = (pc) => {
|
|
14092
14229
|
this.pieceSys.centerOf(pc, c);
|
|
14093
|
-
|
|
14230
|
+
if (c.distanceTo(this.v2.set(p[0], p[1], p[2])) > ev.radius) return;
|
|
14231
|
+
const hit = blastShove({ point: p, energy, radius: ev.radius, reach: reachOf(pc.objectId, [c.x, c.y, c.z]) }, { position: [c.x, c.y, c.z], mass: pc.mass }, this.o.blastShove);
|
|
14094
14232
|
if (!hit) return;
|
|
14095
14233
|
const spread = pc.halfExtents[0];
|
|
14096
14234
|
const momentum = hit.speed * pc.mass;
|
|
@@ -14099,7 +14237,12 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14099
14237
|
for (const pc of [...this.pieceSys.list]) shove(pc);
|
|
14100
14238
|
if (this.o.shoveable) this.loosen(p, ev.radius, energy, reachOf);
|
|
14101
14239
|
this.fragments.blast(p, ev.radius, Math.min(20, Math.sqrt(energy) * 0.08));
|
|
14102
|
-
this.sound("explode", p, clamp6(0.5 + ev.radius / 10, 0.5, 1)
|
|
14240
|
+
this.sound("explode", p, clamp6(0.5 + ev.radius / 10, 0.5, 1), {
|
|
14241
|
+
radius: ev.radius,
|
|
14242
|
+
...ev.effect !== void 0 ? { effect: ev.effect } : {},
|
|
14243
|
+
...options.effect !== void 0 ? { effect: options.effect } : {},
|
|
14244
|
+
...report ? { confinement } : {}
|
|
14245
|
+
});
|
|
14103
14246
|
}
|
|
14104
14247
|
/** The bound objects without a piece that the host lets a blast move (`shoveable`): the ones it reaches with enough speed become pieces and get the shove. */
|
|
14105
14248
|
loosen(point, radius, energy, reachOf) {
|
|
@@ -14110,7 +14253,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14110
14253
|
const { half, center } = this.measure(b.root, this.meshesOf(b));
|
|
14111
14254
|
const world = center.clone().applyQuaternion(b.root.quaternion).add(b.root.position);
|
|
14112
14255
|
const mass = this.massOf(b.id);
|
|
14113
|
-
|
|
14256
|
+
if (world.distanceTo(this.v2.set(point[0], point[1], point[2])) > radius) continue;
|
|
14257
|
+
const hit = blastShove({ point, energy, radius, reach: reachOf(b.id, [world.x, world.y, world.z]) }, { position: [world.x, world.y, world.z], mass }, this.o.blastShove);
|
|
14114
14258
|
if (!hit) continue;
|
|
14115
14259
|
const piece = this.makePiece(b.id, { mass });
|
|
14116
14260
|
const body = this.pieceSys.get(b.id);
|
|
@@ -14134,9 +14278,9 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14134
14278
|
this.fires.set(key, { object: ev.object, part: ev.part, point: ev.point, follow: { x: ev.point[0], y: ev.point[1], z: ev.point[2] } });
|
|
14135
14279
|
}
|
|
14136
14280
|
stopFire(key) {
|
|
14137
|
-
const
|
|
14138
|
-
if (!
|
|
14139
|
-
if (
|
|
14281
|
+
const fire2 = this.fires.get(key);
|
|
14282
|
+
if (!fire2) return;
|
|
14283
|
+
if (fire2.handle !== void 0) this.vfx.stop(fire2.handle);
|
|
14140
14284
|
this.fires.delete(key);
|
|
14141
14285
|
}
|
|
14142
14286
|
// ----------------------------------------------------------------------------------------------------------------------------------
|
|
@@ -14173,9 +14317,9 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14173
14317
|
if (ps.status === "melted") this.onGone(a.object, pv, "melted", def);
|
|
14174
14318
|
else if (ps.status === "ashes") this.onGone(a.object, pv, "ashes", def);
|
|
14175
14319
|
}
|
|
14176
|
-
const
|
|
14177
|
-
if (
|
|
14178
|
-
if (ps.burning && ps.status !== "broken" && ps.status !== "ashes" && ps.status !== "melted") this.emitFire(
|
|
14320
|
+
const fire2 = this.fires.get(key);
|
|
14321
|
+
if (fire2) {
|
|
14322
|
+
if (ps.burning && ps.status !== "broken" && ps.status !== "ashes" && ps.status !== "melted") this.emitFire(fire2, pv, def);
|
|
14179
14323
|
else this.stopFire(key);
|
|
14180
14324
|
}
|
|
14181
14325
|
const hot = def?.visual?.glows === true && ps.temperature > GLOW_FROM_C;
|
|
@@ -14305,10 +14449,12 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14305
14449
|
this.scene.remove(b.root);
|
|
14306
14450
|
this.pieceSys.remove(b.id);
|
|
14307
14451
|
this.bounds.delete(b.id);
|
|
14452
|
+
this.staticDirty.add(b.id);
|
|
14308
14453
|
}
|
|
14309
14454
|
}
|
|
14310
14455
|
}
|
|
14311
14456
|
clear() {
|
|
14457
|
+
this.staticAll = true;
|
|
14312
14458
|
this.queue.length = 0;
|
|
14313
14459
|
this.slices.length = 0;
|
|
14314
14460
|
this.active.clear();
|
|
@@ -14335,6 +14481,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14335
14481
|
this.rng = createRng(RNG_SEED);
|
|
14336
14482
|
this.time = 0;
|
|
14337
14483
|
this.staticAt = 0;
|
|
14484
|
+
this.staticRound = [];
|
|
14485
|
+
this.staticAll = true;
|
|
14338
14486
|
this.throttles.clear();
|
|
14339
14487
|
this.fragments.reset();
|
|
14340
14488
|
this.pieceSys.reset();
|
|
@@ -14391,7 +14539,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14391
14539
|
}
|
|
14392
14540
|
};
|
|
14393
14541
|
|
|
14394
|
-
// ../game-audio/dist/chunk-
|
|
14542
|
+
// ../game-audio/dist/chunk-7TLFY7VO.js
|
|
14395
14543
|
var DISTANCE_CURVES = {
|
|
14396
14544
|
/** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
|
|
14397
14545
|
game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
|
|
@@ -14454,15 +14602,31 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14454
14602
|
{
|
|
14455
14603
|
id: "game",
|
|
14456
14604
|
master: 0.5,
|
|
14457
|
-
noise: {
|
|
14458
|
-
|
|
14605
|
+
noise: {
|
|
14606
|
+
seconds: 1.5,
|
|
14607
|
+
create: "lazy"
|
|
14608
|
+
},
|
|
14609
|
+
sources: [
|
|
14610
|
+
"jogo:L62077-62081 master 0.5 to the output",
|
|
14611
|
+
"jogo:L62082-62088 noise 1.5 s made by the first sound that needs it"
|
|
14612
|
+
]
|
|
14459
14613
|
},
|
|
14460
14614
|
{
|
|
14461
14615
|
id: "art_scene",
|
|
14462
14616
|
master: 0.85,
|
|
14463
|
-
compressor: {
|
|
14464
|
-
|
|
14465
|
-
|
|
14617
|
+
compressor: {
|
|
14618
|
+
threshold: -12,
|
|
14619
|
+
ratio: 5
|
|
14620
|
+
},
|
|
14621
|
+
reverb: {
|
|
14622
|
+
seconds: 2.2,
|
|
14623
|
+
decay: 3.4,
|
|
14624
|
+
wet: 0.4
|
|
14625
|
+
},
|
|
14626
|
+
noise: {
|
|
14627
|
+
seconds: 2,
|
|
14628
|
+
create: "eager"
|
|
14629
|
+
},
|
|
14466
14630
|
sources: [
|
|
14467
14631
|
"cena:L1308 compressor -12 dB, ratio 5",
|
|
14468
14632
|
"cena:L1309 master 0.85",
|
|
@@ -14470,6 +14634,30 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14470
14634
|
"cena:L1311 wet 0.4",
|
|
14471
14635
|
"cena:L1312 noise 2 s made with the chain"
|
|
14472
14636
|
]
|
|
14637
|
+
},
|
|
14638
|
+
{
|
|
14639
|
+
id: "kit",
|
|
14640
|
+
master: 0.85,
|
|
14641
|
+
compressor: {
|
|
14642
|
+
threshold: -12,
|
|
14643
|
+
ratio: 5
|
|
14644
|
+
},
|
|
14645
|
+
reverb: {
|
|
14646
|
+
seconds: 2.2,
|
|
14647
|
+
decay: 3.4,
|
|
14648
|
+
wet: 0.4
|
|
14649
|
+
},
|
|
14650
|
+
noise: {
|
|
14651
|
+
seconds: 2,
|
|
14652
|
+
create: "eager"
|
|
14653
|
+
},
|
|
14654
|
+
sources: [
|
|
14655
|
+
"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"
|
|
14656
|
+
],
|
|
14657
|
+
limiter: {
|
|
14658
|
+
ceiling: -1,
|
|
14659
|
+
knee: -6
|
|
14660
|
+
}
|
|
14473
14661
|
}
|
|
14474
14662
|
];
|
|
14475
14663
|
var MIX_PROFILES = Object.fromEntries(
|
|
@@ -14520,8 +14708,395 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14520
14708
|
}
|
|
14521
14709
|
]
|
|
14522
14710
|
};
|
|
14711
|
+
var entries = (category, list) => list.map(([id, priority, current]) => ({ id, category, priority, ...current ? { current } : {} }));
|
|
14712
|
+
var SFX_CATALOG = [
|
|
14713
|
+
...entries("armas", [
|
|
14714
|
+
["pistol_22lr", 2, "sfx_pistol"],
|
|
14715
|
+
["pistol_9mm", 1, "sfx_pistol"],
|
|
14716
|
+
["pistol_45", 1, "sfx_pistol"],
|
|
14717
|
+
["revolver_38_357", 2, "sfx_pistol"],
|
|
14718
|
+
["revolver_44_50ae", 3, "sfx_pistol"],
|
|
14719
|
+
["smg_9mm_auto", 1, "sfx_pistol"],
|
|
14720
|
+
["shotgun_12", 1, "sfx_shotgun"],
|
|
14721
|
+
["rifle_5_56", 1, "sfx_rifle"],
|
|
14722
|
+
["rifle_7_62x39", 1, "sfx_rifle"],
|
|
14723
|
+
["rifle_auto_burst", 1, "sfx_rifle"],
|
|
14724
|
+
["rifle_308_3006", 2, "sfx_rifle"],
|
|
14725
|
+
["sniper_338_300wm", 2, "sfx_rifle"],
|
|
14726
|
+
["antimateriel_50bmg", 3, "sfx_rifle"],
|
|
14727
|
+
["suppressed_pistol", 2],
|
|
14728
|
+
["suppressed_rifle", 2],
|
|
14729
|
+
["gunshot_far_pistol", 1],
|
|
14730
|
+
["gunshot_far_rifle", 1],
|
|
14731
|
+
["gunshot_far_shotgun", 1],
|
|
14732
|
+
["gunshot_far_heavy", 2],
|
|
14733
|
+
["gunshot_tail_indoor", 1],
|
|
14734
|
+
["gunshot_tail_outdoor", 1],
|
|
14735
|
+
["bullet_crack_by", 2],
|
|
14736
|
+
["bullet_whiz", 2],
|
|
14737
|
+
["ricochet_metal", 2, "ping"],
|
|
14738
|
+
["dry_fire", 1],
|
|
14739
|
+
["mag_out", 1],
|
|
14740
|
+
["mag_in", 1],
|
|
14741
|
+
["slide_pull_release", 1],
|
|
14742
|
+
["pump_cycle", 1],
|
|
14743
|
+
["casing_drop_concreto_pistol", 1],
|
|
14744
|
+
["casing_drop_concreto_rifle", 1],
|
|
14745
|
+
["casing_drop_concreto_shell", 1],
|
|
14746
|
+
["casing_drop_madeira_pistol", 1],
|
|
14747
|
+
["casing_drop_madeira_rifle", 1],
|
|
14748
|
+
["casing_drop_madeira_shell", 1],
|
|
14749
|
+
["casing_drop_metal_pistol", 1],
|
|
14750
|
+
["casing_drop_metal_rifle", 1],
|
|
14751
|
+
["casing_drop_metal_shell", 1],
|
|
14752
|
+
["casing_drop_terra_pistol", 1],
|
|
14753
|
+
["casing_drop_terra_rifle", 1],
|
|
14754
|
+
["casing_drop_terra_shell", 1],
|
|
14755
|
+
["rocket_fire", 2]
|
|
14756
|
+
]),
|
|
14757
|
+
...entries("explosoes-fogo", [
|
|
14758
|
+
["explosion_grenade", 1, "boom"],
|
|
14759
|
+
["explosion_big", 1, "boom_big"],
|
|
14760
|
+
["explosion_car", 2, "boom_big"],
|
|
14761
|
+
["explosion_far", 1],
|
|
14762
|
+
["debris_rain_stone", 1],
|
|
14763
|
+
["molotov_break_ignite", 1, "glass_shatter"],
|
|
14764
|
+
["fire_ignite", 1, "hiss"],
|
|
14765
|
+
["fire_loop_small", 1],
|
|
14766
|
+
["fire_loop_large", 1],
|
|
14767
|
+
["fire_extinguish", 2, "hiss"],
|
|
14768
|
+
["gas_leak_hiss", 2],
|
|
14769
|
+
["structure_collapse", 2, "crumble"]
|
|
14770
|
+
]),
|
|
14771
|
+
...entries("personagem", [
|
|
14772
|
+
["footstep_concrete_walk", 1, "sfx_step"],
|
|
14773
|
+
["footstep_wood_walk", 1, "sfx_step"],
|
|
14774
|
+
["footstep_dirt_walk", 1, "sfx_step"],
|
|
14775
|
+
["footstep_grass_walk", 1, "sfx_step"],
|
|
14776
|
+
["footstep_gravel_walk", 1, "sfx_step"],
|
|
14777
|
+
["land_concrete", 1, "sfx_step"],
|
|
14778
|
+
["punch_swing", 1],
|
|
14779
|
+
["punch_hit_body", 1, "sfx_flesh"],
|
|
14780
|
+
["kick_hit", 1, "sfx_flesh"],
|
|
14781
|
+
["knife_stab", 1],
|
|
14782
|
+
["blunt_hit", 1],
|
|
14783
|
+
["bite", 1, "sfx_flesh"],
|
|
14784
|
+
["body_fall", 1],
|
|
14785
|
+
["player_hurt", 2]
|
|
14786
|
+
]),
|
|
14787
|
+
...entries("veiculos", [
|
|
14788
|
+
["engine_loop_car", 1],
|
|
14789
|
+
["engine_start", 1],
|
|
14790
|
+
["crash_light", 1, "crash"],
|
|
14791
|
+
["crash_heavy", 1, "crash"],
|
|
14792
|
+
["car_door_open", 1, "latch"],
|
|
14793
|
+
["car_door_close", 1, "shut_metal"],
|
|
14794
|
+
["horn_car", 2, "horn"],
|
|
14795
|
+
["tire_skid_asphalt", 2]
|
|
14796
|
+
]),
|
|
14797
|
+
...entries("itens-portas", [
|
|
14798
|
+
["item_pickup_metal", 1],
|
|
14799
|
+
["can_open", 1],
|
|
14800
|
+
["can_crush", 1],
|
|
14801
|
+
["door_wood_open", 1, "latch"],
|
|
14802
|
+
["door_wood_close", 1, "shut_wood"],
|
|
14803
|
+
["door_creak", 1, "creak_wood"],
|
|
14804
|
+
["door_locked_rattle", 1, "rattle"],
|
|
14805
|
+
["drawer_open", 2, "slide"],
|
|
14806
|
+
["fridge_close", 2, "shut_metal"]
|
|
14807
|
+
]),
|
|
14808
|
+
...entries("ambiente", [
|
|
14809
|
+
["rain_loop", 2],
|
|
14810
|
+
["wind_loop", 2],
|
|
14811
|
+
["thunder_near", 2],
|
|
14812
|
+
["thunder_far", 2],
|
|
14813
|
+
["water_splash", 2]
|
|
14814
|
+
])
|
|
14815
|
+
];
|
|
14816
|
+
var SFX_MATERIALS = [
|
|
14817
|
+
["steel", "metal"],
|
|
14818
|
+
["aluminium", "metal"],
|
|
14819
|
+
["wood", "wood"],
|
|
14820
|
+
["plywood", "wood"],
|
|
14821
|
+
["mdf", "wood"],
|
|
14822
|
+
["glass", "glass"],
|
|
14823
|
+
["tempered_glass", "glass"],
|
|
14824
|
+
["ceramic", "glass"],
|
|
14825
|
+
["concrete", "masonry"],
|
|
14826
|
+
["brick", "masonry"],
|
|
14827
|
+
["plaster", "masonry"],
|
|
14828
|
+
["plastic", "soft"],
|
|
14829
|
+
["fabric", "soft"],
|
|
14830
|
+
["paper", "soft"],
|
|
14831
|
+
["foliage", "soft"],
|
|
14832
|
+
["soil", "soft"],
|
|
14833
|
+
["flesh", "soft"]
|
|
14834
|
+
];
|
|
14835
|
+
var SFX_BLOWS = ["bullet", "blunt", "blade", "break", "drag"];
|
|
14836
|
+
var CURRENT_BY_GROUP = {
|
|
14837
|
+
metal: { bullet: "clang", blunt: "clang", blade: "clang", break: "clang", drag: "drag_metal" },
|
|
14838
|
+
wood: { bullet: "wood_hit", blunt: "wood_hit", blade: "wood_hit", break: "crack", drag: "drag_wood" },
|
|
14839
|
+
glass: { bullet: "ping", blunt: "ping", break: "glass_shatter", drag: "drag_glass" },
|
|
14840
|
+
masonry: { bullet: "chip", blunt: "chip", blade: "chip", break: "crumble", drag: "drag_masonry" },
|
|
14841
|
+
soft: { bullet: "thud", blunt: "thud", blade: "thud", break: "thud", drag: "drag_soft" }
|
|
14842
|
+
};
|
|
14843
|
+
var impactSoundId = (material, blow3) => `impact_${material}_${blow3}`;
|
|
14844
|
+
var SFX_IMPACTS = SFX_MATERIALS.flatMap(
|
|
14845
|
+
([material, group]) => SFX_BLOWS.map((blow3) => {
|
|
14846
|
+
const current = CURRENT_BY_GROUP[group]?.[blow3];
|
|
14847
|
+
return { id: impactSoundId(material, blow3), category: "impactos", priority: ["steel", "wood", "glass", "concrete", "brick", "soil", "flesh"].includes(material) && blow3 === "bullet" ? 1 : 2, ...current ? { current } : {} };
|
|
14848
|
+
})
|
|
14849
|
+
);
|
|
14850
|
+
var CALIBRATION_ID = "calibration_shot";
|
|
14851
|
+
var PREFIX = "calibration/";
|
|
14852
|
+
var url = (name) => `${PREFIX}${name}`;
|
|
14853
|
+
var CALIBRATION_SOUND = {
|
|
14854
|
+
id: CALIBRATION_ID,
|
|
14855
|
+
bus: "weapons",
|
|
14856
|
+
close: ["close_1.wav", "close_2.wav", "close_3.wav", "close_4.wav"].map((name) => ({ url: url(name) })),
|
|
14857
|
+
far: ["far_1.wav", "far_2.wav"].map((name) => ({ url: url(name) })),
|
|
14858
|
+
tiers: [
|
|
14859
|
+
{ name: "light", from: 0, close: ["light_1.wav", "light_2.wav"].map((name) => ({ url: url(name) })) },
|
|
14860
|
+
{ name: "medium", from: 0.34, close: ["close_1.wav", "close_2.wav", "close_3.wav", "close_4.wav"].map((name) => ({ url: url(name) })) },
|
|
14861
|
+
{ name: "heavy", from: 0.67, close: ["heavy_1.wav", "heavy_2.wav"].map((name) => ({ url: url(name) })) }
|
|
14862
|
+
],
|
|
14863
|
+
tail: { indoor: [{ url: url("tail_in.wav") }], outdoor: [{ url: url("tail_out.wav") }] },
|
|
14864
|
+
pitch: 0.04,
|
|
14865
|
+
choke: { voices: 2 },
|
|
14866
|
+
fallback: "sfx_pistol",
|
|
14867
|
+
sources: ["sdk: calibration takes synthesized by the harness (measure/calibration.ts), no file, no licence"]
|
|
14868
|
+
};
|
|
14869
|
+
var CALIBRATION_LOOP_ID = "calibration_loop";
|
|
14870
|
+
var CALIBRATION_LOOP_SOUND = {
|
|
14871
|
+
id: CALIBRATION_LOOP_ID,
|
|
14872
|
+
bus: "ambience",
|
|
14873
|
+
close: ["loop_1.wav", "loop_2.wav", "loop_3.wav"].map((name) => ({ url: url(name) })),
|
|
14874
|
+
loop: { crossfade: 0.15 },
|
|
14875
|
+
sources: ["sdk: calibration takes synthesized by the harness (measure/calibration.ts), no file, no licence"]
|
|
14876
|
+
};
|
|
14877
|
+
var CRITERIA_TARGETS = {
|
|
14878
|
+
/** C1: event to the first sample, and onset to the peak (one 60 fps frame). */
|
|
14879
|
+
syncMs: 20,
|
|
14880
|
+
peakAfterOnsetMs: 1e3 / 60,
|
|
14881
|
+
/** C3: distances measured, metres. */
|
|
14882
|
+
distances: [1, 10, 50, 200],
|
|
14883
|
+
/** C5: plays, distinct takes and the pitch range (fraction). */
|
|
14884
|
+
plays: 10,
|
|
14885
|
+
minTakes: 4,
|
|
14886
|
+
pitch: [0.03, 0.05],
|
|
14887
|
+
/** C6: the highest peak, dBFS. */
|
|
14888
|
+
peakDb: -1,
|
|
14889
|
+
/** C8: the end of each file against its peak, dB. */
|
|
14890
|
+
endDropDb: -40,
|
|
14891
|
+
/** C9: a burst of rapid fire. */
|
|
14892
|
+
burst: 20,
|
|
14893
|
+
burstSpacing: 0.06
|
|
14894
|
+
};
|
|
14895
|
+
var PT = {
|
|
14896
|
+
group: "Som",
|
|
14897
|
+
name: "Painel de som (arquivos e C1\u2013C10)",
|
|
14898
|
+
controls: {
|
|
14899
|
+
category: "1 \xB7 Categoria",
|
|
14900
|
+
sound: "1 \xB7 Som",
|
|
14901
|
+
play: "1 \xB7 \u25B6 Tocar",
|
|
14902
|
+
material: "2 \xB7 Material",
|
|
14903
|
+
blow: "2 \xB7 Golpe",
|
|
14904
|
+
strike: "2 \xB7 \u25B6 Tocar golpe",
|
|
14905
|
+
distance: "3 \xB7 Dist\xE2ncia",
|
|
14906
|
+
bearing: "3 \xB7 Dire\xE7\xE3o",
|
|
14907
|
+
environment: "3 \xB7 Lugar",
|
|
14908
|
+
strength: "3 \xB7 For\xE7a",
|
|
14909
|
+
wall: "3 \xB7 Atr\xE1s da parede",
|
|
14910
|
+
burst: "3 \xB7 Rajada 20\xD7",
|
|
14911
|
+
play_a: "4 \xB7 \u25B6 A (atual)",
|
|
14912
|
+
play_b: "4 \xB7 \u25B6 B (novo)",
|
|
14913
|
+
ab_cycle: "4 \xB7 Alternar A/B",
|
|
14914
|
+
blind: "4 \xB7 \xC0s cegas (X)",
|
|
14915
|
+
reveal: "4 \xB7 Revelar X",
|
|
14916
|
+
prefer_a: "4 \xB7 Prefiro A",
|
|
14917
|
+
prefer_b: "4 \xB7 Prefiro B",
|
|
14918
|
+
measure: "5 \xB7 Medir C1\u2013C10",
|
|
14919
|
+
record: "5 \xB7 Gravar 3 s",
|
|
14920
|
+
approve: "5 \xB7 Aprovo (C10)"
|
|
14921
|
+
},
|
|
14922
|
+
hints: {
|
|
14923
|
+
sound: "A = arquivo, S = sintetizado, F = faltando. O que tem arquivo toca o arquivo; o resto toca o som atual.",
|
|
14924
|
+
strike: "Toca impact_<material>_<golpe>: o arquivo se existir, sen\xE3o o som atual daquele material.",
|
|
14925
|
+
wall: "P\xF5e a parede de casa entre voc\xEA e a fonte: o som fica abafado (C4).",
|
|
14926
|
+
burst: "Vinte vezes a cada 60 ms, como uma rajada (C9).",
|
|
14927
|
+
ab_cycle: "A, B, A, B, um por segundo.",
|
|
14928
|
+
blind: "Toca A ou B sem dizer qual; depois revele.",
|
|
14929
|
+
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.",
|
|
14930
|
+
record: "Grava 3 s da sa\xEDda com o som tocando e baixa o arquivo (C10).",
|
|
14931
|
+
approve: "Marca o C10 do som escolhido como aprovado pelo seu ouvido."
|
|
14932
|
+
},
|
|
14933
|
+
categories: {
|
|
14934
|
+
armas: "Armas",
|
|
14935
|
+
impactos: "Impactos",
|
|
14936
|
+
"explosoes-fogo": "Explos\xF5es e fogo",
|
|
14937
|
+
personagem: "Personagem",
|
|
14938
|
+
veiculos: "Ve\xEDculos",
|
|
14939
|
+
"itens-portas": "Itens e portas",
|
|
14940
|
+
ambiente: "Ambiente",
|
|
14941
|
+
calibracao: "Calibra\xE7\xE3o (SDK)"
|
|
14942
|
+
},
|
|
14943
|
+
blows: { bullet: "tiro", blunt: "soco/chute", blade: "faca", break: "quebra", drag: "arrasto/queda" },
|
|
14944
|
+
materials: {
|
|
14945
|
+
steel: "a\xE7o",
|
|
14946
|
+
aluminium: "alum\xEDnio",
|
|
14947
|
+
wood: "madeira",
|
|
14948
|
+
plywood: "compensado",
|
|
14949
|
+
mdf: "MDF",
|
|
14950
|
+
glass: "vidro",
|
|
14951
|
+
tempered_glass: "vidro temperado",
|
|
14952
|
+
ceramic: "cer\xE2mica",
|
|
14953
|
+
concrete: "concreto",
|
|
14954
|
+
brick: "tijolo",
|
|
14955
|
+
plaster: "gesso",
|
|
14956
|
+
plastic: "pl\xE1stico",
|
|
14957
|
+
fabric: "tecido",
|
|
14958
|
+
paper: "papel\xE3o",
|
|
14959
|
+
foliage: "folhagem",
|
|
14960
|
+
soil: "terra",
|
|
14961
|
+
flesh: "carne"
|
|
14962
|
+
},
|
|
14963
|
+
environments: { indoor: "interior", outdoor: "exterior" },
|
|
14964
|
+
strengths: { light: "leve", medium: "m\xE9dio", heavy: "forte" },
|
|
14965
|
+
states: { file: "A", synth: "S", missing: "F" },
|
|
14966
|
+
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" },
|
|
14967
|
+
metrics: { 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" },
|
|
14968
|
+
run: { idle: "parada", measuring: "medindo\u2026", done: "pronta", failed: "falhou", recording: "gravando\u2026", recorded: "grava\xE7\xE3o baixada" },
|
|
14969
|
+
words: { none: "\u2014", hidden: "? (revele)", prefers: "prefere", approved: "aprovado pelo dono" },
|
|
14970
|
+
probe: "Fonte do som",
|
|
14971
|
+
wall: "Parede (oclus\xE3o)",
|
|
14972
|
+
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" }
|
|
14973
|
+
};
|
|
14974
|
+
var EN2 = {
|
|
14975
|
+
...PT,
|
|
14976
|
+
group: "Sound",
|
|
14977
|
+
name: "Sound panel (files and C1\u2013C10)",
|
|
14978
|
+
controls: {
|
|
14979
|
+
category: "1 \xB7 Category",
|
|
14980
|
+
sound: "1 \xB7 Sound",
|
|
14981
|
+
play: "1 \xB7 \u25B6 Play",
|
|
14982
|
+
material: "2 \xB7 Material",
|
|
14983
|
+
blow: "2 \xB7 Blow",
|
|
14984
|
+
strike: "2 \xB7 \u25B6 Play blow",
|
|
14985
|
+
distance: "3 \xB7 Distance",
|
|
14986
|
+
bearing: "3 \xB7 Bearing",
|
|
14987
|
+
environment: "3 \xB7 Place",
|
|
14988
|
+
strength: "3 \xB7 Strength",
|
|
14989
|
+
wall: "3 \xB7 Behind the wall",
|
|
14990
|
+
burst: "3 \xB7 Burst 20\xD7",
|
|
14991
|
+
play_a: "4 \xB7 \u25B6 A (current)",
|
|
14992
|
+
play_b: "4 \xB7 \u25B6 B (new)",
|
|
14993
|
+
ab_cycle: "4 \xB7 Alternate A/B",
|
|
14994
|
+
blind: "4 \xB7 Blind (X)",
|
|
14995
|
+
reveal: "4 \xB7 Reveal X",
|
|
14996
|
+
prefer_a: "4 \xB7 Prefer A",
|
|
14997
|
+
prefer_b: "4 \xB7 Prefer B",
|
|
14998
|
+
measure: "5 \xB7 Measure C1\u2013C10",
|
|
14999
|
+
record: "5 \xB7 Record 3 s",
|
|
15000
|
+
approve: "5 \xB7 Approve (C10)"
|
|
15001
|
+
},
|
|
15002
|
+
hints: {
|
|
15003
|
+
sound: "A = file, S = synthesized, F = missing. A file plays the file; the rest plays the current sound.",
|
|
15004
|
+
strike: "Plays impact_<material>_<blow>: the file if there is one, else the current sound of that material.",
|
|
15005
|
+
wall: "Puts the house wall between you and the source: the sound is muffled (C4).",
|
|
15006
|
+
burst: "Twenty times every 60 ms, like a burst (C9).",
|
|
15007
|
+
ab_cycle: "A, B, A, B, one a second.",
|
|
15008
|
+
blind: "Plays A or B without saying which; reveal it after.",
|
|
15009
|
+
measure: "Measures the chosen sound through the real engine (offline context): sync, right sound, distance, side, variation, level, strength, tail and burst.",
|
|
15010
|
+
record: "Records 3 s of the output with the sound playing and downloads it (C10).",
|
|
15011
|
+
approve: "Marks C10 of the chosen sound as approved by your ear."
|
|
15012
|
+
},
|
|
15013
|
+
categories: { armas: "Weapons", impactos: "Impacts", "explosoes-fogo": "Explosions and fire", personagem: "Character", veiculos: "Vehicles", "itens-portas": "Items and doors", ambiente: "Ambience", calibracao: "Calibration (SDK)" },
|
|
15014
|
+
blows: { bullet: "bullet", blunt: "punch/kick", blade: "knife", break: "break", drag: "drag/fall" },
|
|
15015
|
+
materials: {
|
|
15016
|
+
steel: "steel",
|
|
15017
|
+
aluminium: "aluminium",
|
|
15018
|
+
wood: "wood",
|
|
15019
|
+
plywood: "plywood",
|
|
15020
|
+
mdf: "MDF",
|
|
15021
|
+
glass: "glass",
|
|
15022
|
+
tempered_glass: "tempered glass",
|
|
15023
|
+
ceramic: "ceramic",
|
|
15024
|
+
concrete: "concrete",
|
|
15025
|
+
brick: "brick",
|
|
15026
|
+
plaster: "plaster",
|
|
15027
|
+
plastic: "plastic",
|
|
15028
|
+
fabric: "fabric",
|
|
15029
|
+
paper: "cardboard",
|
|
15030
|
+
foliage: "foliage",
|
|
15031
|
+
soil: "soil",
|
|
15032
|
+
flesh: "flesh"
|
|
15033
|
+
},
|
|
15034
|
+
environments: { indoor: "indoor", outdoor: "outdoor" },
|
|
15035
|
+
strengths: { light: "light", medium: "medium", heavy: "heavy" },
|
|
15036
|
+
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" },
|
|
15037
|
+
metrics: { 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" },
|
|
15038
|
+
run: { idle: "idle", measuring: "measuring\u2026", done: "done", failed: "failed", recording: "recording\u2026", recorded: "recording downloaded" },
|
|
15039
|
+
words: { none: "\u2014", hidden: "? (reveal)", prefers: "prefers", approved: "approved by the owner" },
|
|
15040
|
+
probe: "Sound source",
|
|
15041
|
+
wall: "Wall (occlusion)",
|
|
15042
|
+
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" }
|
|
15043
|
+
};
|
|
14523
15044
|
|
|
14524
15045
|
// ../game-audio/dist/index.js
|
|
15046
|
+
var SFX_TIERS = { light: 0, medium: 0.34, heavy: 0.67 };
|
|
15047
|
+
function splitTier(id) {
|
|
15048
|
+
const match = /^(.*)_(light|medium|heavy)$/.exec(id);
|
|
15049
|
+
return match ? { base: match[1], tier: match[2] } : { base: id };
|
|
15050
|
+
}
|
|
15051
|
+
var refsOf = (entries2, baseUrl) => (entries2 ?? []).map((entry) => ({ url: `${baseUrl}${entry.file}` }));
|
|
15052
|
+
function sampleBankFromManifest(manifest, options) {
|
|
15053
|
+
const baseUrl = options.baseUrl ?? "";
|
|
15054
|
+
const samples = [];
|
|
15055
|
+
const tiersOf = /* @__PURE__ */ new Map();
|
|
15056
|
+
for (const sound of manifest.sounds) {
|
|
15057
|
+
const { base, tier } = splitTier(sound.id);
|
|
15058
|
+
if (tier) tiersOf.set(base, [...tiersOf.get(base) ?? [], sound]);
|
|
15059
|
+
}
|
|
15060
|
+
const bases = /* @__PURE__ */ new Map();
|
|
15061
|
+
for (const sound of manifest.sounds) {
|
|
15062
|
+
if (!splitTier(sound.id).tier) bases.set(sound.id, sound);
|
|
15063
|
+
}
|
|
15064
|
+
for (const [base, tiers] of tiersOf) {
|
|
15065
|
+
if (!bases.has(base)) bases.set(base, { id: base, category: tiers[0]?.category ?? "", layers: { close: tiers[0]?.layers.close ?? [] } });
|
|
15066
|
+
}
|
|
15067
|
+
for (const sound of bases.values()) {
|
|
15068
|
+
const numbers = options.sounds?.[sound.id] ?? options.defaults?.(sound);
|
|
15069
|
+
const close = refsOf(sound.layers.close, baseUrl);
|
|
15070
|
+
if (!numbers || close.length === 0) continue;
|
|
15071
|
+
const tiers = (tiersOf.get(sound.id) ?? []).map((tier) => {
|
|
15072
|
+
const name = splitTier(tier.id).tier;
|
|
15073
|
+
const tierFar = refsOf(tier.layers.far, baseUrl);
|
|
15074
|
+
return { name, from: SFX_TIERS[name] ?? 0, close: refsOf(tier.layers.close, baseUrl), ...tierFar.length > 0 ? { far: tierFar } : {} };
|
|
15075
|
+
}).sort((a, b) => a.from - b.from);
|
|
15076
|
+
const far = refsOf(sound.layers.far, baseUrl);
|
|
15077
|
+
const indoor = refsOf(sound.layers.tail_in, baseUrl);
|
|
15078
|
+
const outdoor = refsOf(sound.layers.tail_out, baseUrl);
|
|
15079
|
+
const files = [sound, ...tiersOf.get(sound.id) ?? []].flatMap((entry) => Object.values(entry.layers).flatMap((entries2) => entries2 ?? []));
|
|
15080
|
+
samples.push({
|
|
15081
|
+
id: sound.id,
|
|
15082
|
+
bus: numbers.bus,
|
|
15083
|
+
close,
|
|
15084
|
+
...far.length > 0 ? { far } : {},
|
|
15085
|
+
...tiers.length > 0 ? { tiers } : {},
|
|
15086
|
+
...numbers.crossover ? { crossover: numbers.crossover } : {},
|
|
15087
|
+
...indoor.length > 0 || outdoor.length > 0 ? { tail: { ...indoor.length > 0 ? { indoor } : {}, ...outdoor.length > 0 ? { outdoor } : {}, ...numbers.tailGain === void 0 ? {} : { gain: numbers.tailGain } } } : {},
|
|
15088
|
+
...numbers.pitch === void 0 ? {} : { pitch: numbers.pitch },
|
|
15089
|
+
...numbers.gain === void 0 ? {} : { gain: numbers.gain },
|
|
15090
|
+
...numbers.falloff ? { falloff: numbers.falloff } : {},
|
|
15091
|
+
...numbers.cutoffK === void 0 ? {} : { cutoffK: numbers.cutoffK },
|
|
15092
|
+
...numbers.group ? { group: numbers.group } : {},
|
|
15093
|
+
...numbers.priority === void 0 ? {} : { priority: numbers.priority },
|
|
15094
|
+
...numbers.fallback ? { fallback: numbers.fallback } : {},
|
|
15095
|
+
sources: files.map((file) => `${file.file}: ${file.source} ${file.author} ${file.license}`)
|
|
15096
|
+
});
|
|
15097
|
+
}
|
|
15098
|
+
return { id: options.id, samples };
|
|
15099
|
+
}
|
|
14525
15100
|
var ATTACK = 2e-3;
|
|
14526
15101
|
function lengthOf(d, attack) {
|
|
14527
15102
|
if (typeof d === "number") return attack + d;
|
|
@@ -14597,6 +15172,569 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14597
15172
|
sources: [`cena:${line}`]
|
|
14598
15173
|
};
|
|
14599
15174
|
}
|
|
15175
|
+
var FOLEY_FALLOFF = {
|
|
15176
|
+
model: "inverse_square",
|
|
15177
|
+
k: 0.02,
|
|
15178
|
+
cutoffK: 0.04,
|
|
15179
|
+
minGain: 4e-3
|
|
15180
|
+
};
|
|
15181
|
+
var vary = (f, pct = 0.04) => [Math.round(f * (1 - pct)), Math.round(f * (1 + pct))];
|
|
15182
|
+
var foley = (id, layers, note) => ({
|
|
15183
|
+
id,
|
|
15184
|
+
bus: "world",
|
|
15185
|
+
pan: true,
|
|
15186
|
+
layers,
|
|
15187
|
+
falloff: FOLEY_FALLOFF,
|
|
15188
|
+
sources: [`sdk: ${note}`]
|
|
15189
|
+
});
|
|
15190
|
+
var click = (f, vol, delay = 0) => [
|
|
15191
|
+
sceneNoise({
|
|
15192
|
+
type: "bandpass",
|
|
15193
|
+
f: vary(f, 0.08),
|
|
15194
|
+
q: 4,
|
|
15195
|
+
d: [0.018, 0.03],
|
|
15196
|
+
vol: [vol * 0.85, vol * 1.1],
|
|
15197
|
+
delay
|
|
15198
|
+
}),
|
|
15199
|
+
sceneTone({
|
|
15200
|
+
f: vary(f * 0.8, 0.06),
|
|
15201
|
+
f2: Math.round(f * 0.62),
|
|
15202
|
+
d: [0.015, 0.025],
|
|
15203
|
+
vol: vol * 0.18,
|
|
15204
|
+
delay
|
|
15205
|
+
})
|
|
15206
|
+
];
|
|
15207
|
+
var meet = (body, panel, vol, latch) => [
|
|
15208
|
+
sceneTone({
|
|
15209
|
+
f: vary(body),
|
|
15210
|
+
f2: Math.round(body * 0.5),
|
|
15211
|
+
d: [0.12, 0.16],
|
|
15212
|
+
vol: [vol * 0.9, vol * 1.1]
|
|
15213
|
+
}),
|
|
15214
|
+
sceneNoise({
|
|
15215
|
+
type: "bandpass",
|
|
15216
|
+
f: vary(panel, 0.06),
|
|
15217
|
+
q: 1.2,
|
|
15218
|
+
d: [0.08, 0.12],
|
|
15219
|
+
vol: [vol * 0.9, vol * 1.1],
|
|
15220
|
+
wet: 0.25
|
|
15221
|
+
}),
|
|
15222
|
+
...click(latch, vol * 0.45, [0.012, 0.028])
|
|
15223
|
+
];
|
|
15224
|
+
var LEAF_FOLEY = [
|
|
15225
|
+
// a wooden house door or wardrobe door: latch, a short creak, the leaf on the frame (the hard slam adds the frame rattling)
|
|
15226
|
+
foley("door_wood_open", click(2400, 0.4), "the latch of a wooden door giving"),
|
|
15227
|
+
foley(
|
|
15228
|
+
"door_creak",
|
|
15229
|
+
[
|
|
15230
|
+
sceneTone({ f: [190, 240], f2: 310, d: [0.4, 0.55], vol: [0.04, 0.06] }),
|
|
15231
|
+
sceneNoise({
|
|
15232
|
+
type: "bandpass",
|
|
15233
|
+
f: [480, 560],
|
|
15234
|
+
q: 6,
|
|
15235
|
+
a: 0.05,
|
|
15236
|
+
d: [0.35, 0.5],
|
|
15237
|
+
vol: [0.1, 0.14]
|
|
15238
|
+
})
|
|
15239
|
+
],
|
|
15240
|
+
"a wooden hinge turning"
|
|
15241
|
+
),
|
|
15242
|
+
foley("door_wood_close", meet(120, 600, 0.55, 2400), "a wooden leaf meeting its frame"),
|
|
15243
|
+
foley(
|
|
15244
|
+
"door_wood_slam",
|
|
15245
|
+
[
|
|
15246
|
+
...meet(110, 560, 0.85, 2300),
|
|
15247
|
+
...sceneMany(
|
|
15248
|
+
3,
|
|
15249
|
+
() => sceneNoise({
|
|
15250
|
+
type: "bandpass",
|
|
15251
|
+
f: [900, 1500],
|
|
15252
|
+
q: 3,
|
|
15253
|
+
d: 0.03,
|
|
15254
|
+
vol: [0.08, 0.14],
|
|
15255
|
+
delay: [0.05, 0.18]
|
|
15256
|
+
})
|
|
15257
|
+
)
|
|
15258
|
+
],
|
|
15259
|
+
"a wooden door slammed: the frame and the hinges rattle after the hit"
|
|
15260
|
+
),
|
|
15261
|
+
// a metal door or gate: a hollow panel that rings a little
|
|
15262
|
+
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"),
|
|
15263
|
+
foley(
|
|
15264
|
+
"door_creak_metal",
|
|
15265
|
+
[
|
|
15266
|
+
sceneTone({ f: [620, 760], f2: 900, d: [0.3, 0.4], vol: [0.03, 0.045] }),
|
|
15267
|
+
sceneNoise({
|
|
15268
|
+
type: "bandpass",
|
|
15269
|
+
f: [1300, 1500],
|
|
15270
|
+
q: 8,
|
|
15271
|
+
a: 0.04,
|
|
15272
|
+
d: [0.25, 0.35],
|
|
15273
|
+
vol: [0.07, 0.09]
|
|
15274
|
+
})
|
|
15275
|
+
],
|
|
15276
|
+
"a metal hinge turning"
|
|
15277
|
+
),
|
|
15278
|
+
// the handle of a locked door shaken: the latch knocking in its keeper, five to seven times in half a second
|
|
15279
|
+
foley(
|
|
15280
|
+
"door_locked_rattle",
|
|
15281
|
+
[
|
|
15282
|
+
...sceneMany(
|
|
15283
|
+
6,
|
|
15284
|
+
() => sceneNoise({
|
|
15285
|
+
type: "bandpass",
|
|
15286
|
+
f: [1600, 2600],
|
|
15287
|
+
q: 3,
|
|
15288
|
+
d: [0.025, 0.04],
|
|
15289
|
+
vol: [0.22, 0.34],
|
|
15290
|
+
delay: [0, 0.45]
|
|
15291
|
+
})
|
|
15292
|
+
),
|
|
15293
|
+
...sceneMany(
|
|
15294
|
+
3,
|
|
15295
|
+
() => sceneTone({
|
|
15296
|
+
f: [170, 210],
|
|
15297
|
+
f2: 120,
|
|
15298
|
+
d: 0.05,
|
|
15299
|
+
vol: [0.12, 0.18],
|
|
15300
|
+
delay: [0.02, 0.4]
|
|
15301
|
+
})
|
|
15302
|
+
)
|
|
15303
|
+
],
|
|
15304
|
+
"the handle of a locked door shaken: latch knocks and the leaf thumping in its frame"
|
|
15305
|
+
),
|
|
15306
|
+
// 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
|
|
15307
|
+
foley(
|
|
15308
|
+
"fridge_open",
|
|
15309
|
+
[
|
|
15310
|
+
sceneNoise({
|
|
15311
|
+
type: "lowpass",
|
|
15312
|
+
f: [320, 380],
|
|
15313
|
+
a: 0.03,
|
|
15314
|
+
d: [0.14, 0.2],
|
|
15315
|
+
vol: [0.32, 0.4]
|
|
15316
|
+
}),
|
|
15317
|
+
sceneNoise({
|
|
15318
|
+
type: "bandpass",
|
|
15319
|
+
f: [800, 950],
|
|
15320
|
+
f2: 1400,
|
|
15321
|
+
q: 2,
|
|
15322
|
+
a: 0.02,
|
|
15323
|
+
d: 0.12,
|
|
15324
|
+
vol: [0.08, 0.12]
|
|
15325
|
+
}),
|
|
15326
|
+
...sceneMany(
|
|
15327
|
+
2,
|
|
15328
|
+
() => sceneTone({
|
|
15329
|
+
f: [2600, 4200],
|
|
15330
|
+
d: [0.04, 0.08],
|
|
15331
|
+
vol: [0.015, 0.03],
|
|
15332
|
+
delay: [0.08, 0.22]
|
|
15333
|
+
})
|
|
15334
|
+
)
|
|
15335
|
+
],
|
|
15336
|
+
"a fridge door: the seal letting go and the bottles in the door"
|
|
15337
|
+
),
|
|
15338
|
+
foley(
|
|
15339
|
+
"fridge_close",
|
|
15340
|
+
[
|
|
15341
|
+
sceneTone({ f: vary(85), f2: 45, d: [0.1, 0.13], vol: [0.38, 0.46] }),
|
|
15342
|
+
sceneNoise({
|
|
15343
|
+
type: "lowpass",
|
|
15344
|
+
f: [520, 620],
|
|
15345
|
+
d: [0.08, 0.12],
|
|
15346
|
+
vol: [0.3, 0.36]
|
|
15347
|
+
}),
|
|
15348
|
+
sceneNoise({
|
|
15349
|
+
type: "lowpass",
|
|
15350
|
+
f: [260, 320],
|
|
15351
|
+
a: 0.02,
|
|
15352
|
+
d: 0.1,
|
|
15353
|
+
vol: [0.12, 0.18],
|
|
15354
|
+
delay: [0.04, 0.07]
|
|
15355
|
+
}),
|
|
15356
|
+
...sceneMany(
|
|
15357
|
+
2,
|
|
15358
|
+
() => sceneTone({
|
|
15359
|
+
f: [2600, 4200],
|
|
15360
|
+
d: [0.04, 0.07],
|
|
15361
|
+
vol: [0.015, 0.03],
|
|
15362
|
+
delay: [0.03, 0.12]
|
|
15363
|
+
})
|
|
15364
|
+
)
|
|
15365
|
+
],
|
|
15366
|
+
"a fridge door shut: a soft thump, the seal pulling and the bottles"
|
|
15367
|
+
),
|
|
15368
|
+
// a microwave: the spring catch of the door, plastic on plastic
|
|
15369
|
+
foley(
|
|
15370
|
+
"microwave_open",
|
|
15371
|
+
[
|
|
15372
|
+
...click(1800, 0.34),
|
|
15373
|
+
sceneTone({
|
|
15374
|
+
f: [3e3, 3400],
|
|
15375
|
+
f2: 2800,
|
|
15376
|
+
d: 0.05,
|
|
15377
|
+
vol: 0.025,
|
|
15378
|
+
delay: [0.01, 0.02]
|
|
15379
|
+
})
|
|
15380
|
+
],
|
|
15381
|
+
"the spring catch of a microwave door"
|
|
15382
|
+
),
|
|
15383
|
+
foley(
|
|
15384
|
+
"microwave_close",
|
|
15385
|
+
[
|
|
15386
|
+
sceneNoise({
|
|
15387
|
+
type: "bandpass",
|
|
15388
|
+
f: [1200, 1450],
|
|
15389
|
+
q: 2.5,
|
|
15390
|
+
d: [0.04, 0.06],
|
|
15391
|
+
vol: [0.36, 0.44]
|
|
15392
|
+
}),
|
|
15393
|
+
sceneTone({ f: vary(180), f2: 120, d: 0.05, vol: [0.16, 0.22] }),
|
|
15394
|
+
...click(2200, 0.2, [8e-3, 0.016])
|
|
15395
|
+
],
|
|
15396
|
+
"a microwave door clacking shut"
|
|
15397
|
+
),
|
|
15398
|
+
foley("microwave_beep", [sceneTone({ wave: "square", f: 2e3, d: 0.12, vol: 0.05 })], "the beep of a microwave"),
|
|
15399
|
+
// drawers and sliding leaves: the runners, then the stop
|
|
15400
|
+
foley(
|
|
15401
|
+
"drawer_open",
|
|
15402
|
+
[
|
|
15403
|
+
sceneNoise({
|
|
15404
|
+
type: "bandpass",
|
|
15405
|
+
f: [620, 780],
|
|
15406
|
+
q: 2,
|
|
15407
|
+
a: 0.04,
|
|
15408
|
+
d: [0.28, 0.36],
|
|
15409
|
+
vol: [0.18, 0.24]
|
|
15410
|
+
}),
|
|
15411
|
+
sceneNoise({ type: "bandpass", f: [2e3, 2400], q: 5, d: 0.28, vol: 0.04 }),
|
|
15412
|
+
...click(1400, 0.16, [0.28, 0.34])
|
|
15413
|
+
],
|
|
15414
|
+
"a drawer on its runners and its stop"
|
|
15415
|
+
),
|
|
15416
|
+
foley(
|
|
15417
|
+
"drawer_close",
|
|
15418
|
+
[
|
|
15419
|
+
sceneNoise({
|
|
15420
|
+
type: "bandpass",
|
|
15421
|
+
f: [620, 780],
|
|
15422
|
+
q: 2,
|
|
15423
|
+
a: 0.03,
|
|
15424
|
+
d: [0.2, 0.28],
|
|
15425
|
+
vol: [0.18, 0.24]
|
|
15426
|
+
}),
|
|
15427
|
+
sceneTone({
|
|
15428
|
+
f: vary(150),
|
|
15429
|
+
f2: 90,
|
|
15430
|
+
d: 0.08,
|
|
15431
|
+
vol: [0.22, 0.3],
|
|
15432
|
+
delay: [0.2, 0.26]
|
|
15433
|
+
})
|
|
15434
|
+
],
|
|
15435
|
+
"a drawer pushed home"
|
|
15436
|
+
)
|
|
15437
|
+
];
|
|
15438
|
+
var ITEM_FOLEY = [
|
|
15439
|
+
// the hand closing on the item: a touch of skin and cloth, then the item's own small sound
|
|
15440
|
+
foley(
|
|
15441
|
+
"item_pickup_metal",
|
|
15442
|
+
[
|
|
15443
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
|
|
15444
|
+
sceneTone({
|
|
15445
|
+
f: [1900, 2600],
|
|
15446
|
+
f2: 1700,
|
|
15447
|
+
d: [0.05, 0.08],
|
|
15448
|
+
vol: [0.06, 0.09],
|
|
15449
|
+
delay: [0.01, 0.03]
|
|
15450
|
+
})
|
|
15451
|
+
],
|
|
15452
|
+
"picking up a metal thing"
|
|
15453
|
+
),
|
|
15454
|
+
foley(
|
|
15455
|
+
"item_pickup_plastic",
|
|
15456
|
+
[
|
|
15457
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
|
|
15458
|
+
sceneNoise({
|
|
15459
|
+
type: "bandpass",
|
|
15460
|
+
f: [1500, 1900],
|
|
15461
|
+
q: 3,
|
|
15462
|
+
d: 0.03,
|
|
15463
|
+
vol: [0.15, 0.21],
|
|
15464
|
+
delay: [0.01, 0.03]
|
|
15465
|
+
})
|
|
15466
|
+
],
|
|
15467
|
+
"picking up a plastic thing"
|
|
15468
|
+
),
|
|
15469
|
+
foley(
|
|
15470
|
+
"item_pickup_glass",
|
|
15471
|
+
[
|
|
15472
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.15 }),
|
|
15473
|
+
sceneTone({
|
|
15474
|
+
f: [3200, 4200],
|
|
15475
|
+
d: [0.05, 0.08],
|
|
15476
|
+
vol: [0.038, 0.06],
|
|
15477
|
+
delay: [0.01, 0.03]
|
|
15478
|
+
})
|
|
15479
|
+
],
|
|
15480
|
+
"picking up a glass thing"
|
|
15481
|
+
),
|
|
15482
|
+
foley(
|
|
15483
|
+
"item_pickup_paper",
|
|
15484
|
+
[
|
|
15485
|
+
sceneNoise({
|
|
15486
|
+
type: "highpass",
|
|
15487
|
+
f: [2600, 3400],
|
|
15488
|
+
a: 0.01,
|
|
15489
|
+
d: [0.1, 0.14],
|
|
15490
|
+
vol: [0.12, 0.18]
|
|
15491
|
+
}),
|
|
15492
|
+
sceneNoise({ type: "bandpass", f: [800, 1e3], q: 1, d: 0.05, vol: 0.12 })
|
|
15493
|
+
],
|
|
15494
|
+
"picking up paper or cardboard"
|
|
15495
|
+
),
|
|
15496
|
+
foley(
|
|
15497
|
+
"item_pickup_fabric",
|
|
15498
|
+
[
|
|
15499
|
+
sceneNoise({
|
|
15500
|
+
type: "bandpass",
|
|
15501
|
+
f: [900, 1300],
|
|
15502
|
+
q: 0.8,
|
|
15503
|
+
a: 0.02,
|
|
15504
|
+
d: [0.12, 0.16],
|
|
15505
|
+
vol: [0.15, 0.21]
|
|
15506
|
+
})
|
|
15507
|
+
],
|
|
15508
|
+
"picking up cloth"
|
|
15509
|
+
),
|
|
15510
|
+
foley(
|
|
15511
|
+
"item_pickup_wood",
|
|
15512
|
+
[
|
|
15513
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
|
|
15514
|
+
sceneNoise({
|
|
15515
|
+
type: "bandpass",
|
|
15516
|
+
f: [900, 1100],
|
|
15517
|
+
q: 2,
|
|
15518
|
+
d: 0.04,
|
|
15519
|
+
vol: [0.15, 0.21],
|
|
15520
|
+
delay: [0.01, 0.03]
|
|
15521
|
+
})
|
|
15522
|
+
],
|
|
15523
|
+
"picking up a wooden thing"
|
|
15524
|
+
),
|
|
15525
|
+
foley(
|
|
15526
|
+
"item_pickup_food",
|
|
15527
|
+
[
|
|
15528
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
|
|
15529
|
+
sceneNoise({
|
|
15530
|
+
type: "lowpass",
|
|
15531
|
+
f: [500, 650],
|
|
15532
|
+
d: 0.05,
|
|
15533
|
+
vol: 0.12,
|
|
15534
|
+
delay: [0.01, 0.03]
|
|
15535
|
+
})
|
|
15536
|
+
],
|
|
15537
|
+
"picking up food"
|
|
15538
|
+
),
|
|
15539
|
+
foley(
|
|
15540
|
+
"item_throw",
|
|
15541
|
+
[
|
|
15542
|
+
sceneNoise({
|
|
15543
|
+
type: "bandpass",
|
|
15544
|
+
f: [450, 650],
|
|
15545
|
+
f2: 1400,
|
|
15546
|
+
q: 1.5,
|
|
15547
|
+
a: 0.05,
|
|
15548
|
+
d: 0.18,
|
|
15549
|
+
vol: [0.1, 0.14]
|
|
15550
|
+
})
|
|
15551
|
+
],
|
|
15552
|
+
"the arm throwing something: air"
|
|
15553
|
+
),
|
|
15554
|
+
// a can: the tab cracks, the gas hisses out; drinking is gulps; crushing it crumples the sheet
|
|
15555
|
+
foley(
|
|
15556
|
+
"can_open",
|
|
15557
|
+
[
|
|
15558
|
+
...click(3200, 0.36),
|
|
15559
|
+
sceneNoise({
|
|
15560
|
+
type: "highpass",
|
|
15561
|
+
f: [3600, 4400],
|
|
15562
|
+
a: 5e-3,
|
|
15563
|
+
d: [0.22, 0.3],
|
|
15564
|
+
vol: [0.16, 0.22],
|
|
15565
|
+
delay: [0.012, 0.02]
|
|
15566
|
+
}),
|
|
15567
|
+
...sceneMany(5, () => sceneTone({ f: [4e3, 7e3], d: 0.02, vol: 0.01, delay: [0.05, 0.4] }))
|
|
15568
|
+
],
|
|
15569
|
+
"the tab of a can and the gas hissing out"
|
|
15570
|
+
),
|
|
15571
|
+
foley(
|
|
15572
|
+
"can_crush",
|
|
15573
|
+
[
|
|
15574
|
+
sceneNoise({
|
|
15575
|
+
type: "bandpass",
|
|
15576
|
+
f: [1600, 2200],
|
|
15577
|
+
q: 1.2,
|
|
15578
|
+
d: [0.18, 0.25],
|
|
15579
|
+
vol: [0.3, 0.38]
|
|
15580
|
+
}),
|
|
15581
|
+
...sceneMany(
|
|
15582
|
+
6,
|
|
15583
|
+
() => sceneTone({
|
|
15584
|
+
f: [1200, 3400],
|
|
15585
|
+
f2: 900,
|
|
15586
|
+
d: 0.03,
|
|
15587
|
+
vol: [0.03, 0.06],
|
|
15588
|
+
delay: [0, 0.2]
|
|
15589
|
+
})
|
|
15590
|
+
)
|
|
15591
|
+
],
|
|
15592
|
+
"a can crushed in the hand"
|
|
15593
|
+
),
|
|
15594
|
+
foley(
|
|
15595
|
+
"can_puncture_spray",
|
|
15596
|
+
[
|
|
15597
|
+
sceneNoise({
|
|
15598
|
+
type: "highpass",
|
|
15599
|
+
f: [2400, 3e3],
|
|
15600
|
+
a: 5e-3,
|
|
15601
|
+
d: [0.5, 0.7],
|
|
15602
|
+
vol: [0.2, 0.26]
|
|
15603
|
+
}),
|
|
15604
|
+
sceneNoise({ type: "bandpass", f: [600, 800], q: 2, d: 0.4, vol: 0.06 })
|
|
15605
|
+
],
|
|
15606
|
+
"a can holed: the jet hissing out"
|
|
15607
|
+
),
|
|
15608
|
+
foley(
|
|
15609
|
+
"bottle_open",
|
|
15610
|
+
[
|
|
15611
|
+
...sceneMany(
|
|
15612
|
+
5,
|
|
15613
|
+
() => sceneNoise({
|
|
15614
|
+
type: "bandpass",
|
|
15615
|
+
f: [2200, 3e3],
|
|
15616
|
+
q: 4,
|
|
15617
|
+
d: 8e-3,
|
|
15618
|
+
vol: [0.1, 0.16],
|
|
15619
|
+
delay: [0, 0.18]
|
|
15620
|
+
})
|
|
15621
|
+
),
|
|
15622
|
+
sceneNoise({
|
|
15623
|
+
type: "highpass",
|
|
15624
|
+
f: 3800,
|
|
15625
|
+
a: 5e-3,
|
|
15626
|
+
d: 0.12,
|
|
15627
|
+
vol: [0.06, 0.1],
|
|
15628
|
+
delay: [0.18, 0.22]
|
|
15629
|
+
})
|
|
15630
|
+
],
|
|
15631
|
+
"the screw cap of a bottle turning off"
|
|
15632
|
+
),
|
|
15633
|
+
foley(
|
|
15634
|
+
"drink_gulp",
|
|
15635
|
+
[
|
|
15636
|
+
sceneNoise({
|
|
15637
|
+
type: "lowpass",
|
|
15638
|
+
f: [280, 360],
|
|
15639
|
+
a: 0.02,
|
|
15640
|
+
d: [0.1, 0.14],
|
|
15641
|
+
vol: [0.24, 0.3]
|
|
15642
|
+
}),
|
|
15643
|
+
sceneTone({ f: [140, 170], f2: 85, d: [0.08, 0.11], vol: [0.12, 0.16] })
|
|
15644
|
+
],
|
|
15645
|
+
"a gulp"
|
|
15646
|
+
),
|
|
15647
|
+
foley(
|
|
15648
|
+
"eat_crunch",
|
|
15649
|
+
[
|
|
15650
|
+
...sceneMany(
|
|
15651
|
+
4,
|
|
15652
|
+
() => sceneNoise({
|
|
15653
|
+
type: "bandpass",
|
|
15654
|
+
f: [1800, 3200],
|
|
15655
|
+
q: 1.5,
|
|
15656
|
+
d: [0.02, 0.04],
|
|
15657
|
+
vol: [0.12, 0.2],
|
|
15658
|
+
delay: [0, 0.12]
|
|
15659
|
+
})
|
|
15660
|
+
)
|
|
15661
|
+
],
|
|
15662
|
+
"a bite of something crunchy"
|
|
15663
|
+
),
|
|
15664
|
+
foley(
|
|
15665
|
+
"eat_chew",
|
|
15666
|
+
[
|
|
15667
|
+
sceneNoise({
|
|
15668
|
+
type: "lowpass",
|
|
15669
|
+
f: [450, 600],
|
|
15670
|
+
a: 0.03,
|
|
15671
|
+
d: [0.1, 0.14],
|
|
15672
|
+
vol: [0.12, 0.16]
|
|
15673
|
+
}),
|
|
15674
|
+
sceneNoise({
|
|
15675
|
+
type: "bandpass",
|
|
15676
|
+
f: [1100, 1400],
|
|
15677
|
+
q: 2,
|
|
15678
|
+
d: 0.04,
|
|
15679
|
+
vol: 0.04,
|
|
15680
|
+
delay: [0.03, 0.06]
|
|
15681
|
+
})
|
|
15682
|
+
],
|
|
15683
|
+
"chewing"
|
|
15684
|
+
),
|
|
15685
|
+
foley(
|
|
15686
|
+
"bandage_wrap",
|
|
15687
|
+
[
|
|
15688
|
+
sceneNoise({
|
|
15689
|
+
type: "bandpass",
|
|
15690
|
+
f: [1400, 1800],
|
|
15691
|
+
f2: 2400,
|
|
15692
|
+
q: 1,
|
|
15693
|
+
a: 0.04,
|
|
15694
|
+
d: [0.3, 0.4],
|
|
15695
|
+
vol: [0.12, 0.16]
|
|
15696
|
+
})
|
|
15697
|
+
],
|
|
15698
|
+
"a bandage unrolled round a limb"
|
|
15699
|
+
),
|
|
15700
|
+
foley(
|
|
15701
|
+
"pills_shake",
|
|
15702
|
+
[
|
|
15703
|
+
...sceneMany(
|
|
15704
|
+
8,
|
|
15705
|
+
() => sceneTone({
|
|
15706
|
+
f: [2400, 3600],
|
|
15707
|
+
d: 0.015,
|
|
15708
|
+
vol: [0.03, 0.05],
|
|
15709
|
+
delay: [0, 0.25]
|
|
15710
|
+
})
|
|
15711
|
+
),
|
|
15712
|
+
sceneNoise({ type: "bandpass", f: [1500, 1900], q: 2, d: 0.25, vol: 0.05 })
|
|
15713
|
+
],
|
|
15714
|
+
"pills shaken in their bottle"
|
|
15715
|
+
),
|
|
15716
|
+
foley(
|
|
15717
|
+
"medkit_use",
|
|
15718
|
+
[
|
|
15719
|
+
...click(1700, 0.24),
|
|
15720
|
+
sceneNoise({
|
|
15721
|
+
type: "bandpass",
|
|
15722
|
+
f: [1e3, 1400],
|
|
15723
|
+
q: 1,
|
|
15724
|
+
a: 0.03,
|
|
15725
|
+
d: [0.25, 0.32],
|
|
15726
|
+
vol: [0.08, 0.12],
|
|
15727
|
+
delay: [0.05, 0.08]
|
|
15728
|
+
})
|
|
15729
|
+
],
|
|
15730
|
+
"a first aid kit opened and rummaged"
|
|
15731
|
+
),
|
|
15732
|
+
foley("flashlight_click", click(2600, 0.3), "the switch of a flashlight")
|
|
15733
|
+
];
|
|
15734
|
+
var FOLEY_BANK = {
|
|
15735
|
+
id: "foley",
|
|
15736
|
+
sounds: [...LEAF_FOLEY, ...ITEM_FOLEY]
|
|
15737
|
+
};
|
|
14600
15738
|
var TAKES = [
|
|
14601
15739
|
{ f: 1, t: 1, v: 1 },
|
|
14602
15740
|
{ f: 1.08, t: 0.9, v: 0.92 },
|
|
@@ -14764,6 +15902,202 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14764
15902
|
};
|
|
14765
15903
|
var BODY_FOLEY_SET_IDS = [...FOOTSTEP_SOUND_IDS, ...LAND_SOUND_IDS, ...BODY_SOUND_IDS];
|
|
14766
15904
|
|
|
15905
|
+
// src/audio/blast-fire.ts
|
|
15906
|
+
var BLAST_FALLOFF = { model: "inverse_square", k: 12e-4, cutoffK: 6e-3, minGain: 2e-3 };
|
|
15907
|
+
var BLAST_FAR_FALLOFF = { model: "inverse_square", k: 8e-5, scale: 0.3, minGain: 1e-3 };
|
|
15908
|
+
var FIRE_FALLOFF = { model: "inverse_square", k: 0.01, cutoffK: 0.01, minGain: 5e-3 };
|
|
15909
|
+
var BLAST_FAR_DISTANCE = 60;
|
|
15910
|
+
var BLAST_KINDS = ["grenade", "big", "fuel", "car", "pipe_bomb", "rocket", "flashbang", "molotov"];
|
|
15911
|
+
var BLAST_KIND_OF = {
|
|
15912
|
+
m67: "grenade",
|
|
15913
|
+
vog_25: "grenade",
|
|
15914
|
+
m79_40mm: "grenade",
|
|
15915
|
+
claymore: "grenade",
|
|
15916
|
+
generic: "grenade",
|
|
15917
|
+
c4: "big",
|
|
15918
|
+
dynamite: "big",
|
|
15919
|
+
fuel_station_tank: "big",
|
|
15920
|
+
propane_p13: "fuel",
|
|
15921
|
+
fuel_barrel: "fuel",
|
|
15922
|
+
fuel_pump: "fuel",
|
|
15923
|
+
car_fuel_tank: "car",
|
|
15924
|
+
pipe_bomb: "pipe_bomb",
|
|
15925
|
+
m72_66mm: "rocket",
|
|
15926
|
+
at4_84mm: "rocket",
|
|
15927
|
+
carl_gustaf_84mm: "rocket",
|
|
15928
|
+
pg7v: "rocket",
|
|
15929
|
+
flashbang: "flashbang",
|
|
15930
|
+
molotov: "molotov"
|
|
15931
|
+
};
|
|
15932
|
+
var BIG_BLAST_RADIUS = 8;
|
|
15933
|
+
var blast = (id, layers, sources, falloff = BLAST_FALLOFF) => ({
|
|
15934
|
+
...sceneRecipe(id, layers, ""),
|
|
15935
|
+
falloff,
|
|
15936
|
+
sources
|
|
15937
|
+
});
|
|
15938
|
+
var crack = (f, d, vol) => sceneNoise({ type: "highpass", f, a: 1e-3, d, vol });
|
|
15939
|
+
var debris2 = (count, from, to, vol) => [
|
|
15940
|
+
...sceneMany(count, () => sceneNoise({ type: "bandpass", f: [300, 1400], q: 2.5, d: [0.03, 0.09], vol, delay: [from, to] })),
|
|
15941
|
+
...sceneMany(Math.ceil(count / 3), () => sceneNoise({ type: "bandpass", f: [1800, 3600], q: 5, d: [0.02, 0.04], vol: [vol[0] * 0.6, vol[1] * 0.6], delay: [from + 0.1, to] }))
|
|
15942
|
+
];
|
|
15943
|
+
var shrapnel = (count, to) => sceneMany(count, () => sceneNoise({ type: "bandpass", f: [2500, 6e3], q: 6, d: [0.015, 0.045], vol: [0.08, 0.16], delay: [0.02, to] }));
|
|
15944
|
+
var glass = (count, from) => [
|
|
15945
|
+
sceneNoise({ type: "highpass", f: [2600, 3e3], d: 0.4, vol: 0.7, wet: 0.5, delay: from }),
|
|
15946
|
+
...sceneMany(count, () => sceneTone({ f: [3e3, 7500], d: [0.05, 0.13], vol: 0.12, delay: [from, from + 0.7] }))
|
|
15947
|
+
];
|
|
15948
|
+
var BLAST_SOUNDS = [
|
|
15949
|
+
blast(
|
|
15950
|
+
"explosion_grenade",
|
|
15951
|
+
[
|
|
15952
|
+
crack([2300, 2700], 0.06, 2.4),
|
|
15953
|
+
sceneNoise({ f: [2500, 3e3], f2: 160, d: 0.7, vol: 2, wet: 0.35 }),
|
|
15954
|
+
sceneTone({ f: [80, 92], f2: 32, d: 0.5, vol: 1.6 }),
|
|
15955
|
+
sceneNoise({ type: "bandpass", f: [620, 760], q: 0.8, d: 0.18, vol: 1.1 }),
|
|
15956
|
+
...shrapnel(14, 0.7),
|
|
15957
|
+
...debris2(10, 0.35, 1.8, [0.1, 0.2])
|
|
15958
|
+
],
|
|
15959
|
+
["sdk: frag grenade (M67, VOG-25, 40 mm): sharp crack, short body, fragments striking, a little debris"]
|
|
15960
|
+
),
|
|
15961
|
+
blast(
|
|
15962
|
+
"explosion_big",
|
|
15963
|
+
[
|
|
15964
|
+
crack([1900, 2300], 0.08, 2.4),
|
|
15965
|
+
sceneNoise({ f: [2200, 2600], f2: 90, d: 1.6, vol: 2.2, wet: 0.45 }),
|
|
15966
|
+
sceneTone({ f: [52, 60], f2: 22, d: 1.6, vol: 1.9 }),
|
|
15967
|
+
sceneNoise({ f: [280, 330], f2: 60, a: 0.25, d: 2.8, vol: 0.8, wet: 0.6, delay: 0.05 }),
|
|
15968
|
+
...debris2(24, 0.5, 3.6, [0.12, 0.25])
|
|
15969
|
+
],
|
|
15970
|
+
["sdk: big charge (C4, dynamite, a fuel station tank): crack, long deep roar, debris falling for 2 to 4 s"]
|
|
15971
|
+
),
|
|
15972
|
+
blast(
|
|
15973
|
+
"explosion_fuel",
|
|
15974
|
+
[
|
|
15975
|
+
sceneNoise({ type: "highpass", f: [1700, 2e3], a: 1e-3, d: 0.05, vol: 1 }),
|
|
15976
|
+
sceneTone({ f: [380, 450], f2: 300, d: 0.4, vol: 0.3 }),
|
|
15977
|
+
sceneNoise({ f: [1700, 2e3], f2: 150, a: 0.03, d: 1.4, vol: 2.1, wet: 0.4 }),
|
|
15978
|
+
sceneTone({ f: [48, 56], f2: 25, d: 1.2, vol: 1.7 }),
|
|
15979
|
+
sceneNoise({ type: "bandpass", f: [450, 560], q: 0.6, a: 0.15, d: 2.2, vol: 0.85, wet: 0.5, delay: 0.1 }),
|
|
15980
|
+
...debris2(10, 0.5, 2.6, [0.08, 0.16])
|
|
15981
|
+
],
|
|
15982
|
+
['sdk: a fuel vessel bursting (propane P13, fuel barrel, pump): the shell tearing, a fireball "whoomp" and its roar']
|
|
15983
|
+
),
|
|
15984
|
+
blast(
|
|
15985
|
+
"explosion_car",
|
|
15986
|
+
[
|
|
15987
|
+
sceneNoise({ type: "highpass", f: [1700, 2e3], a: 1e-3, d: 0.06, vol: 1.1 }),
|
|
15988
|
+
sceneNoise({ f: [1600, 1900], f2: 140, a: 0.03, d: 1.6, vol: 2.1, wet: 0.4 }),
|
|
15989
|
+
sceneTone({ f: [44, 52], f2: 24, d: 1.4, vol: 1.8 }),
|
|
15990
|
+
sceneNoise({ type: "bandpass", f: [420, 520], q: 0.6, a: 0.15, d: 2.6, vol: 0.9, wet: 0.5, delay: 0.1 }),
|
|
15991
|
+
...glass(10, 0.04),
|
|
15992
|
+
sceneTone({ f: [130, 150], f2: 85, d: 1.1, vol: 0.18, delay: [0.3, 0.5] }),
|
|
15993
|
+
...debris2(16, 0.6, 3.2, [0.1, 0.2])
|
|
15994
|
+
],
|
|
15995
|
+
["sdk: a car going up: the fuel tank fireball, every window breaking, the body groaning, parts falling"]
|
|
15996
|
+
),
|
|
15997
|
+
blast(
|
|
15998
|
+
"explosion_pipe_bomb",
|
|
15999
|
+
[
|
|
16000
|
+
crack([2e3, 2400], 0.07, 2.2),
|
|
16001
|
+
sceneNoise({ f: [2e3, 2400], f2: 150, d: 0.8, vol: 1.9, wet: 0.35 }),
|
|
16002
|
+
sceneTone({ f: [70, 82], f2: 30, d: 0.6, vol: 1.5 }),
|
|
16003
|
+
...sceneMany(6, () => sceneTone({ f: [1800, 3200], f2: 1200, d: [0.06, 0.12], vol: 0.06, delay: [0.05, 0.6] })),
|
|
16004
|
+
...shrapnel(18, 0.9),
|
|
16005
|
+
...debris2(8, 0.4, 1.8, [0.08, 0.16])
|
|
16006
|
+
],
|
|
16007
|
+
["sdk: pipe bomb: crack, body, the steel pipe flying apart in ringing pieces"]
|
|
16008
|
+
),
|
|
16009
|
+
blast(
|
|
16010
|
+
"explosion_rocket",
|
|
16011
|
+
[
|
|
16012
|
+
crack([2100, 2500], 0.08, 2.4),
|
|
16013
|
+
sceneNoise({ f: [2400, 2800], f2: 120, d: 1.1, vol: 2.1, wet: 0.4 }),
|
|
16014
|
+
sceneTone({ f: [60, 70], f2: 26, d: 0.9, vol: 1.8 }),
|
|
16015
|
+
sceneNoise({ f: [350, 420], f2: 80, a: 0.08, d: 1.8, vol: 0.9, wet: 0.6, delay: 0.05 }),
|
|
16016
|
+
...shrapnel(10, 0.8),
|
|
16017
|
+
...debris2(16, 0.4, 2.6, [0.1, 0.2])
|
|
16018
|
+
],
|
|
16019
|
+
["sdk: rocket or anti-tank warhead (M72, AT4, RPG): hard crack, heavy body, debris"]
|
|
16020
|
+
),
|
|
16021
|
+
blast(
|
|
16022
|
+
"explosion_flashbang",
|
|
16023
|
+
[crack([1400, 1700], 0.12, 2.8), sceneNoise({ f: [1900, 2200], f2: 300, d: 0.35, vol: 1.3, wet: 0.3 }), sceneTone({ f: [110, 130], f2: 60, d: 0.2, vol: 0.8 })],
|
|
16024
|
+
["sdk: flashbang: a deafening crack with almost no body and no fragments"]
|
|
16025
|
+
),
|
|
16026
|
+
blast(
|
|
16027
|
+
"molotov_break_ignite",
|
|
16028
|
+
[
|
|
16029
|
+
...glass(8, 0),
|
|
16030
|
+
sceneNoise({ f: [280, 340], f2: 2200, a: 0.12, d: 0.9, vol: 1.5, wet: 0.6, delay: 0.05 }),
|
|
16031
|
+
sceneTone({ f: [85, 95], f2: 55, d: 0.4, vol: 0.5, delay: 0.08 })
|
|
16032
|
+
],
|
|
16033
|
+
['sdk: molotov: the bottle breaking and the fuel catching with a "fuuush"'],
|
|
16034
|
+
FIRE_FALLOFF
|
|
16035
|
+
),
|
|
16036
|
+
blast(
|
|
16037
|
+
"explosion_far",
|
|
16038
|
+
[
|
|
16039
|
+
sceneNoise({ f: [550, 650], f2: 80, a: 0.03, d: 2.5, vol: 2, wet: 1.4 }),
|
|
16040
|
+
sceneTone({ f: [42, 48], f2: 25, d: 1.8, vol: 1.2 }),
|
|
16041
|
+
sceneNoise({ f: [350, 420], f2: 70, a: 0.1, d: 1.6, vol: 0.6, wet: 1.5, delay: [0.6, 1] })
|
|
16042
|
+
],
|
|
16043
|
+
["sdk: any blast far away: no crack left, a dull thud and the echo rolling back"],
|
|
16044
|
+
BLAST_FAR_FALLOFF
|
|
16045
|
+
),
|
|
16046
|
+
blast(
|
|
16047
|
+
"explosion_indoor_tail",
|
|
16048
|
+
[
|
|
16049
|
+
...sceneMany(3, () => sceneNoise({ f: [650, 800], d: 0.12, vol: 0.5, delay: [0.04, 0.2] })),
|
|
16050
|
+
sceneNoise({ f: [850, 950], f2: 120, a: 0.05, d: 2.6, vol: 0.9, wet: 1.6, delay: 0.08 })
|
|
16051
|
+
],
|
|
16052
|
+
["sdk: the room answering a blast inside it: slaps off the walls and a boomy tail"]
|
|
16053
|
+
)
|
|
16054
|
+
];
|
|
16055
|
+
var FIRE_SOUNDS = [
|
|
16056
|
+
{
|
|
16057
|
+
...blast(
|
|
16058
|
+
"fire_ignite",
|
|
16059
|
+
[sceneNoise({ f: [230, 270], f2: 1500, a: 0.07, d: 0.5, vol: 1.6 }), sceneTone({ f: [80, 90], f2: 55, d: 0.3, vol: 0.45 }), sceneNoise({ type: "highpass", f: 3e3, d: 0.3, vol: 0.1, delay: 0.1 })],
|
|
16060
|
+
['sdk: fire catching, a soft "fuuump"'],
|
|
16061
|
+
FIRE_FALLOFF
|
|
16062
|
+
),
|
|
16063
|
+
group: "fire_ignite"
|
|
16064
|
+
},
|
|
16065
|
+
{
|
|
16066
|
+
...blast("gas_leak", [sceneNoise({ type: "bandpass", f: [3200, 3800], q: 0.7, a: 0.08, d: { param: "seconds" }, vol: 0.3 })], ["sdk: gas jetting from a punctured vessel"], FIRE_FALLOFF),
|
|
16067
|
+
vars: { seconds: 2 }
|
|
16068
|
+
},
|
|
16069
|
+
{
|
|
16070
|
+
...blast(
|
|
16071
|
+
"fire_extinguish",
|
|
16072
|
+
[sceneNoise({ type: "highpass", f: [2300, 2700], a: 0.03, d: { param: "seconds" }, vol: 0.3 }), sceneNoise({ type: "bandpass", f: [800, 1e3], q: 0.5, d: 0.5, vol: 0.25 })],
|
|
16073
|
+
["sdk: water or foam on a fire: a steam puff and a sizzle"],
|
|
16074
|
+
FIRE_FALLOFF
|
|
16075
|
+
),
|
|
16076
|
+
vars: { seconds: 1.2 }
|
|
16077
|
+
},
|
|
16078
|
+
{ ...blast("fire_crackle", [sceneNoise({ type: "highpass", f: [1500, 3e3], d: [0.01, 0.025], vol: [1.2, 2.2] })], ["sdk: a crackle of the fire"], FIRE_FALLOFF), group: "fire_crackle" },
|
|
16079
|
+
{ ...blast("fire_pop", [sceneNoise({ type: "bandpass", f: [500, 1100], q: 1, d: [0.03, 0.06], vol: [3, 4.5] })], ["sdk: a log or a resin pocket popping"], FIRE_FALLOFF), group: "fire_crackle" }
|
|
16080
|
+
];
|
|
16081
|
+
var FIRE_LOOP = {
|
|
16082
|
+
id: "fire_loop",
|
|
16083
|
+
bus: "world",
|
|
16084
|
+
order: "chain_loop",
|
|
16085
|
+
source: { kind: "noise", loop: true },
|
|
16086
|
+
filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: 950 }, q: 0.5 }] },
|
|
16087
|
+
volume: 0,
|
|
16088
|
+
sources: ["sdk: the roar under the crackles of a fire"]
|
|
16089
|
+
};
|
|
16090
|
+
var BLAST_SOUND_OF = {
|
|
16091
|
+
grenade: "explosion_grenade",
|
|
16092
|
+
big: "explosion_big",
|
|
16093
|
+
fuel: "explosion_fuel",
|
|
16094
|
+
car: "explosion_car",
|
|
16095
|
+
pipe_bomb: "explosion_pipe_bomb",
|
|
16096
|
+
rocket: "explosion_rocket",
|
|
16097
|
+
flashbang: "explosion_flashbang",
|
|
16098
|
+
molotov: "molotov_break_ignite"
|
|
16099
|
+
};
|
|
16100
|
+
|
|
14767
16101
|
// src/audio/recipes.ts
|
|
14768
16102
|
var scene = (id, layers, line, vars) => sceneRecipe(id, layers, line, vars ? { vars } : {});
|
|
14769
16103
|
var boomLayers = (big) => [
|
|
@@ -14846,11 +16180,111 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14846
16180
|
leaf("shut_metal", [sceneTone({ f: 160, f2: 85, d: 0.18, vol: 0.55 }), sceneNoise({ type: "bandpass", f: 900, q: 1.6, d: 0.12, vol: 0.45, wet: 0.3 }), sceneTone({ f: 1250, f2: 1150, d: 0.12, vol: 0.06 })]),
|
|
14847
16181
|
leaf("shut_soft", [sceneTone({ f: 95, f2: 55, d: 0.12, vol: 0.35 }), sceneNoise({ type: "lowpass", f: 500, d: 0.1, vol: 0.3 })]),
|
|
14848
16182
|
leaf("rattle", sceneMany(5, () => sceneNoise({ type: "bandpass", f: [1600, 2600], q: 3, d: 0.035, vol: 0.32, delay: [0, 0.45] }))),
|
|
14849
|
-
leaf("slide", [sceneNoise({ type: "bandpass", f: 700, q: 2, a: 0.04, d: 0.35, vol: 0.22 }), sceneNoise({ type: "bandpass", f: 2200, q: 5, d: 0.3, vol: 0.05 })])
|
|
16183
|
+
leaf("slide", [sceneNoise({ type: "bandpass", f: 700, q: 2, a: 0.04, d: 0.35, vol: 0.22 }), sceneNoise({ type: "bandpass", f: 2200, q: 5, d: 0.3, vol: 0.05 })]),
|
|
16184
|
+
// an item taken in the hand: the fingers on a hard surface and the sleeve moving, or a soft thing gathered up (the kit's recordings answer these ids)
|
|
16185
|
+
leaf("grab_hard", [sceneNoise({ type: "bandpass", f: 1800, q: 3, d: 0.03, vol: 0.18 }), sceneNoise({ type: "bandpass", f: 900, q: 1.2, a: 0.02, d: 0.14, vol: 0.08 })]),
|
|
16186
|
+
leaf("grab_soft", [sceneNoise({ type: "lowpass", f: 1400, a: 0.02, d: 0.16, vol: 0.14 })])
|
|
16187
|
+
];
|
|
16188
|
+
var impact2 = (id, layers) => ({ ...sceneRecipe(id, layers, ""), sources: ["sdk: a blow on a material, by material and kind of blow (synthesised until the recorded samples arrive)"] });
|
|
16189
|
+
var IMPACT_SOUNDS = [
|
|
16190
|
+
// metal
|
|
16191
|
+
impact2("metal_bullet", [sceneNoise({ type: "highpass", f: 3e3, d: 0.03, vol: 0.8 }), sceneTone({ f: [2600, 3400], f2: 1800, d: 0.14, vol: 0.28, wet: 0.35 }), sceneTone({ f: [520, 720], f2: 480, d: 0.35, vol: 0.22, wet: 0.35 })]),
|
|
16192
|
+
impact2("metal_blunt", [sceneNoise({ type: "bandpass", f: 800, q: 1, d: 0.05, vol: 0.5 }), sceneTone({ f: [150, 210], f2: 120, d: 0.6, vol: 0.5, wet: 0.4 }), sceneTone({ f: [420, 520], f2: 400, d: 0.4, vol: 0.12 })]),
|
|
16193
|
+
impact2("metal_blade", [sceneNoise({ type: "bandpass", f: [3500, 4500], q: 6, a: 0.01, d: 0.18, vol: 0.45 }), sceneTone({ f: [2200, 2800], f2: 3e3, d: 0.15, vol: 0.06 })]),
|
|
16194
|
+
impact2("metal_thin", [sceneNoise({ type: "highpass", f: 2500, d: 0.04, vol: 0.6 }), sceneTone({ f: [900, 1300], f2: 700, d: 0.25, vol: 0.22, wet: 0.3 }), sceneNoise({ type: "bandpass", f: 1200, q: 2, d: 0.08, vol: 0.3 })]),
|
|
16195
|
+
// wood (the bullet keeps the art scene's `wood_hit`)
|
|
16196
|
+
impact2("wood_blunt", [sceneTone({ f: [110, 150], f2: 70, d: 0.14, vol: 0.6 }), sceneNoise({ type: "bandpass", f: 500, q: 1.2, d: 0.12, vol: 0.55, wet: 0.2 })]),
|
|
16197
|
+
impact2("wood_blade", [sceneNoise({ type: "bandpass", f: [1800, 2400], q: 2, a: 0.01, d: 0.12, vol: 0.5 }), ...sceneMany(3, () => sceneNoise({ type: "bandpass", f: [2500, 4e3], q: 3, d: 0.02, vol: 0.22, delay: [0.02, 0.1] }))]),
|
|
16198
|
+
impact2("mdf_puff", [sceneNoise({ type: "lowpass", f: 900, d: 0.08, vol: 1 }), sceneTone({ f: [180, 230], f2: 110, d: 0.06, vol: 0.3 }), sceneNoise({ type: "highpass", f: 3e3, a: 0.01, d: 0.2, vol: 0.1 })]),
|
|
16199
|
+
// glass and ceramic
|
|
16200
|
+
impact2("glass_bullet", [sceneNoise({ type: "highpass", f: 4e3, d: 0.05, vol: 0.7 }), sceneTone({ f: [3200, 4200], f2: 2600, d: 0.2, vol: 0.14, wet: 0.3 }), ...sceneMany(4, () => sceneTone({ f: [4e3, 7e3], d: 0.05, vol: 0.07, delay: [0.02, 0.2] }))]),
|
|
16201
|
+
impact2("glass_blunt", [sceneNoise({ type: "bandpass", f: 2200, q: 3, d: 0.05, vol: 0.8 }), sceneTone({ f: [1400, 1800], f2: 1300, d: 0.2, vol: 0.16, wet: 0.3 })]),
|
|
16202
|
+
impact2("glass_blade", [sceneNoise({ type: "bandpass", f: 5e3, q: 8, a: 0.02, d: 0.25, vol: 0.3 })]),
|
|
16203
|
+
impact2("ceramic_hit", [sceneNoise({ type: "bandpass", f: 3e3, q: 2, d: 0.03, vol: 0.6 }), sceneTone({ f: [1800, 2400], f2: 1600, d: 0.1, vol: 0.2 })]),
|
|
16204
|
+
impact2("ceramic_bullet", [sceneNoise({ type: "highpass", f: 2500, d: 0.06, vol: 0.85 }), ...sceneMany(5, () => sceneTone({ f: [2500, 5e3], d: 0.04, vol: 0.09, delay: [0, 0.15] }))]),
|
|
16205
|
+
// masonry and the ground
|
|
16206
|
+
impact2("masonry_bullet", [sceneNoise({ type: "bandpass", f: [1600, 2e3], q: 1, d: 0.05, vol: 1.8 }), sceneNoise({ type: "lowpass", f: 600, d: 0.12, vol: 0.9, wet: 0.2 }), ...sceneMany(4, () => sceneNoise({ type: "bandpass", f: [2e3, 4e3], q: 3, d: 0.02, vol: 0.28, delay: [0.03, 0.3] }))]),
|
|
16207
|
+
impact2("masonry_blunt", [sceneTone({ f: [70, 95], f2: 45, d: 0.12, vol: 0.55 }), sceneNoise({ type: "lowpass", f: 400, d: 0.1, vol: 0.5 })]),
|
|
16208
|
+
impact2("masonry_blade", [sceneNoise({ type: "bandpass", f: [2500, 3500], q: 4, a: 0.01, d: 0.15, vol: 0.4 })]),
|
|
16209
|
+
impact2("plaster_puff", [sceneNoise({ type: "lowpass", f: 900, d: 0.09, vol: 0.7 }), sceneNoise({ type: "highpass", f: 3e3, a: 0.01, d: 0.2, vol: 0.14 })]),
|
|
16210
|
+
impact2("soil_bullet", [sceneNoise({ type: "lowpass", f: 700, d: 0.08, vol: 2.2 }), ...sceneMany(3, () => sceneNoise({ type: "bandpass", f: [1200, 2200], q: 2, d: 0.03, vol: 0.18, delay: [0.02, 0.2] }))]),
|
|
16211
|
+
impact2("soil_blunt", [sceneTone({ f: [55, 70], f2: 40, d: 0.1, vol: 0.45 }), sceneNoise({ type: "lowpass", f: 300, d: 0.08, vol: 0.4 })]),
|
|
16212
|
+
impact2("sand_hit", [sceneNoise({ type: "bandpass", f: 3500, q: 0.8, a: 5e-3, d: 0.15, vol: 0.45 }), sceneNoise({ type: "lowpass", f: 500, d: 0.06, vol: 0.45 })]),
|
|
16213
|
+
impact2("gravel_hit", [sceneNoise({ type: "lowpass", f: 500, d: 0.06, vol: 0.45 }), ...sceneMany(6, () => sceneNoise({ type: "bandpass", f: [1500, 3500], q: 3, d: 0.025, vol: 0.28, delay: [0, 0.18] }))]),
|
|
16214
|
+
// plastic, rubber, wax
|
|
16215
|
+
impact2("plastic_hit", [sceneNoise({ type: "bandpass", f: 1600, q: 3, d: 0.04, vol: 0.5 }), sceneTone({ f: [380, 520], f2: 300, d: 0.08, vol: 0.32 })]),
|
|
16216
|
+
impact2("plastic_bullet", [sceneNoise({ type: "bandpass", f: 2500, q: 2, d: 0.03, vol: 1.3 }), sceneTone({ f: [600, 800], f2: 450, d: 0.06, vol: 0.4 })]),
|
|
16217
|
+
impact2("rubber_hit", [sceneTone({ f: [90, 130], f2: 60, d: 0.1, vol: 0.45 }), sceneNoise({ type: "lowpass", f: 350, d: 0.06, vol: 0.28 })]),
|
|
16218
|
+
impact2("wax_hit", [sceneNoise({ type: "lowpass", f: 800, d: 0.05, vol: 0.45 }), sceneTone({ f: [240, 280], f2: 180, d: 0.05, vol: 0.22 })]),
|
|
16219
|
+
// soft things, paper, plants
|
|
16220
|
+
impact2("soft_bullet", [sceneNoise({ type: "lowpass", f: 450, a: 3e-3, d: 0.1, vol: 1.8 }), sceneNoise({ type: "bandpass", f: 900, q: 1, d: 0.05, vol: 0.5 })]),
|
|
16221
|
+
impact2("fabric_rip", [sceneNoise({ type: "bandpass", f: [2e3, 2800], q: 1.5, a: 0.02, d: 0.25, vol: 0.4 }), ...sceneMany(4, () => sceneNoise({ type: "bandpass", f: [3e3, 5e3], q: 4, d: 0.02, vol: 0.14, delay: [0, 0.22] }))]),
|
|
16222
|
+
impact2("paper_hit", [sceneNoise({ type: "bandpass", f: 2200, q: 1, d: 0.05, vol: 0.45 })]),
|
|
16223
|
+
impact2("paper_tear", [sceneNoise({ type: "highpass", f: 2500, a: 0.02, d: 0.3, vol: 0.15 })]),
|
|
16224
|
+
impact2("leaf_rustle", sceneMany(6, () => sceneNoise({ type: "bandpass", f: [2500, 6e3], q: 2, d: 0.05, vol: 0.16, delay: [0, 0.3] }))),
|
|
16225
|
+
impact2("branch_cut", [sceneNoise({ type: "bandpass", f: 1500, q: 2, d: 0.04, vol: 0.55 }), sceneTone({ f: [260, 340], f2: 150, d: 0.05, vol: 0.22 })]),
|
|
16226
|
+
impact2("fruit_splat", [sceneNoise({ type: "lowpass", f: 1200, d: 0.12, vol: 0.55 }), sceneNoise({ type: "bandpass", f: 600, q: 0.7, d: 0.2, vol: 0.32 })]),
|
|
16227
|
+
// a round glancing off: steel whines down in pitch ("piiuu"), stone and concrete give a short crack with grit
|
|
16228
|
+
impact2("ricochet_metal", [sceneNoise({ type: "highpass", f: 3e3, d: 0.02, vol: 0.6 }), sceneTone({ f: [2800, 3600], f2: 900, d: 0.38, vol: 0.2, wet: 0.4 }), sceneTone({ f: [5200, 6400], f2: 2e3, d: 0.2, vol: 0.05 })]),
|
|
16229
|
+
impact2("ricochet_stone", [sceneNoise({ type: "bandpass", f: [2200, 2800], q: 2, d: 0.04, vol: 0.8 }), sceneTone({ f: [1800, 2400], f2: 1200, d: 0.08, vol: 0.1 }), ...sceneMany(3, () => sceneNoise({ type: "bandpass", f: [2500, 4500], q: 3, d: 0.015, vol: 0.2, delay: [0.02, 0.12] }))]),
|
|
16230
|
+
// breaks a material has of its own (the rest keep the art scene's shatter, crumble and splinter)
|
|
16231
|
+
impact2("ceramic_break", [sceneNoise({ type: "highpass", f: 1800, d: 0.3, vol: 0.85, wet: 0.4 }), ...sceneMany(8, () => sceneTone({ f: [1800, 4500], d: [0.04, 0.1], vol: 0.15, delay: [0, 0.4] }))]),
|
|
16232
|
+
impact2("tempered_burst", [sceneNoise({ type: "highpass", f: 3500, d: 0.6, vol: 0.9, wet: 0.4 }), ...sceneMany(16, () => sceneTone({ f: [4e3, 8e3], d: 0.04, vol: 0.08, delay: [0, 0.8] }))]),
|
|
16233
|
+
impact2("plastic_crack", [sceneNoise({ type: "bandpass", f: 1800, q: 2, d: 0.06, vol: 0.75 }), sceneTone({ f: [450, 550], f2: 250, d: 0.05, vol: 0.22 })]),
|
|
16234
|
+
impact2("mdf_crumble", [sceneNoise({ type: "lowpass", f: 700, d: 0.25, vol: 0.75, wet: 0.2 }), ...sceneMany(4, () => sceneNoise({ type: "lowpass", f: 500, d: 0.05, vol: 0.32, delay: [0.05, 0.3] }))])
|
|
14850
16235
|
];
|
|
14851
|
-
var DESTRUCTION_SOUND_BANK = { id: "destruction_three", sounds: [...SCENE_SOUNDS, ...DRAG_SOUNDS, ...LEAF_SOUNDS, EXPLOSION_BOOM], loops: [BURN_LOOP] };
|
|
16236
|
+
var DESTRUCTION_SOUND_BANK = { id: "destruction_three", sounds: [...SCENE_SOUNDS, ...DRAG_SOUNDS, ...LEAF_SOUNDS, ...IMPACT_SOUNDS, EXPLOSION_BOOM, ...BLAST_SOUNDS, ...FIRE_SOUNDS], loops: [BURN_LOOP, FIRE_LOOP] };
|
|
14852
16237
|
|
|
14853
16238
|
// src/audio/sound.ts
|
|
16239
|
+
var IMPACT_SOUND_KEYS = {
|
|
16240
|
+
impact_metal_ballistic: { sound: "metal_bullet" },
|
|
16241
|
+
impact_metal_blunt: { sound: "metal_blunt" },
|
|
16242
|
+
impact_metal_slash: { sound: "metal_blade" },
|
|
16243
|
+
impact_aluminium_ballistic: { sound: "metal_thin" },
|
|
16244
|
+
impact_aluminium_blunt: { sound: "metal_thin" },
|
|
16245
|
+
impact_copper_ballistic: { sound: "metal_thin" },
|
|
16246
|
+
impact_copper_blunt: { sound: "metal_thin" },
|
|
16247
|
+
impact_wood_ballistic: { sound: "wood_hit" },
|
|
16248
|
+
impact_wood_blunt: { sound: "wood_blunt" },
|
|
16249
|
+
impact_wood_slash: { sound: "wood_blade" },
|
|
16250
|
+
impact_mdf_ballistic: { sound: "mdf_puff" },
|
|
16251
|
+
impact_mdf_blunt: { sound: "mdf_puff", volumeScale: 0.8 },
|
|
16252
|
+
impact_glass_ballistic: { sound: "glass_bullet" },
|
|
16253
|
+
impact_glass_blunt: { sound: "glass_blunt" },
|
|
16254
|
+
impact_glass_slash: { sound: "glass_blade" },
|
|
16255
|
+
impact_ceramic: { sound: "ceramic_hit" },
|
|
16256
|
+
impact_ceramic_ballistic: { sound: "ceramic_bullet" },
|
|
16257
|
+
impact_masonry_ballistic: { sound: "masonry_bullet" },
|
|
16258
|
+
impact_masonry_blunt: { sound: "masonry_blunt" },
|
|
16259
|
+
impact_masonry_slash: { sound: "masonry_blade" },
|
|
16260
|
+
impact_plaster: { sound: "plaster_puff" },
|
|
16261
|
+
impact_soil: { sound: "soil_blunt" },
|
|
16262
|
+
impact_soil_ballistic: { sound: "soil_bullet" },
|
|
16263
|
+
impact_sand: { sound: "sand_hit" },
|
|
16264
|
+
impact_gravel: { sound: "gravel_hit" },
|
|
16265
|
+
impact_plastic: { sound: "plastic_hit" },
|
|
16266
|
+
impact_plastic_ballistic: { sound: "plastic_bullet" },
|
|
16267
|
+
impact_rubber: { sound: "rubber_hit" },
|
|
16268
|
+
impact_wax: { sound: "wax_hit" },
|
|
16269
|
+
impact_soft_ballistic: { sound: "soft_bullet" },
|
|
16270
|
+
impact_soft_slash: { sound: "fabric_rip" },
|
|
16271
|
+
impact_paper: { sound: "paper_hit" },
|
|
16272
|
+
impact_paper_slash: { sound: "paper_tear" },
|
|
16273
|
+
impact_plant: { sound: "leaf_rustle" },
|
|
16274
|
+
impact_plant_slash: { sound: "branch_cut" },
|
|
16275
|
+
impact_flesh_fruit: { sound: "fruit_splat" },
|
|
16276
|
+
ricochet_metal: { sound: "ricochet_metal" },
|
|
16277
|
+
ricochet_masonry: { sound: "ricochet_stone" },
|
|
16278
|
+
ricochet_soil: { sound: "ricochet_stone" },
|
|
16279
|
+
ricochet_ceramic: { sound: "ricochet_stone" },
|
|
16280
|
+
break_ceramic: { sound: "ceramic_break" },
|
|
16281
|
+
break_tempered_glass: { sound: "tempered_burst" },
|
|
16282
|
+
break_plastic: { sound: "plastic_crack" },
|
|
16283
|
+
break_mdf: { sound: "mdf_crumble" },
|
|
16284
|
+
break_soft: { sound: "fabric_rip" },
|
|
16285
|
+
break_paper: { sound: "paper_tear" },
|
|
16286
|
+
break_plant: { sound: "branch_cut" }
|
|
16287
|
+
};
|
|
14854
16288
|
var DESTRUCTION_SOUND_KEYS = {
|
|
14855
16289
|
art_scene: {
|
|
14856
16290
|
impact_metal: { sound: "clang" },
|
|
@@ -14858,6 +16292,12 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14858
16292
|
impact_glass: { sound: "ping" },
|
|
14859
16293
|
impact_masonry: { sound: "chip" },
|
|
14860
16294
|
impact_soft: { sound: "thud" },
|
|
16295
|
+
// a round strikes: the steel rings high, glass cracks, wood and masonry chip, a soft part takes a dull thunk
|
|
16296
|
+
shot_metal: { sound: "ping" },
|
|
16297
|
+
shot_wood: { sound: "chip" },
|
|
16298
|
+
shot_glass: { sound: "crack" },
|
|
16299
|
+
shot_masonry: { sound: "chip" },
|
|
16300
|
+
shot_soft: { sound: "thunk" },
|
|
14861
16301
|
drag_wood: { sound: "drag_wood" },
|
|
14862
16302
|
drag_metal: { sound: "drag_metal" },
|
|
14863
16303
|
drag_glass: { sound: "drag_glass" },
|
|
@@ -14883,22 +16323,38 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14883
16323
|
hood_shut: { sound: "shut_metal" },
|
|
14884
16324
|
trunk_shut: { sound: "shut_metal" },
|
|
14885
16325
|
door_close: { sound: "shut_wood", volumeScale: 0.7 },
|
|
16326
|
+
// a vehicle's leaves (the vehicle bank of game-vehicles-three): a car door shuts with a padded thump and a latch, not like a fridge
|
|
16327
|
+
vehicle_door_open: { sound: "car_door_open", fallback: "latch" },
|
|
16328
|
+
vehicle_door_shut: { sound: "car_door_close", fallback: "shut_metal" },
|
|
16329
|
+
vehicle_trunk_open: { sound: "car_door_open", fallback: "latch" },
|
|
16330
|
+
vehicle_trunk_shut: { sound: "car_trunk_close", fallback: "shut_metal" },
|
|
16331
|
+
vehicle_hood_open: { sound: "car_door_open", fallback: "latch" },
|
|
16332
|
+
vehicle_hood_shut: { sound: "car_hood_close", fallback: "shut_metal" },
|
|
14886
16333
|
drawer_open: { sound: "slide" },
|
|
14887
16334
|
drawer_close: { sound: "slide" },
|
|
14888
16335
|
lid_open: { sound: "latch" },
|
|
14889
16336
|
lid_close: { sound: "shut_soft" },
|
|
14890
16337
|
flap_open: { sound: "latch" },
|
|
14891
16338
|
flap_close: { sound: "shut_soft" },
|
|
16339
|
+
// an item taken in the hand, by what it is made of (game-audio's KIT_SAMPLE_ALIASES puts recordings on these ids)
|
|
16340
|
+
grab_metal: { sound: "grab_hard" },
|
|
16341
|
+
grab_wood: { sound: "grab_hard" },
|
|
16342
|
+
grab_glass: { sound: "grab_hard", volumeScale: 0.7 },
|
|
16343
|
+
grab_masonry: { sound: "grab_hard" },
|
|
16344
|
+
grab_soft: { sound: "grab_soft" },
|
|
14892
16345
|
shatter_glass: { sound: "glass_shatter" },
|
|
14893
16346
|
crumble: { sound: "crumble" },
|
|
14894
16347
|
splinter: { sound: "crack" },
|
|
14895
16348
|
ricochet: { sound: "ping" },
|
|
14896
16349
|
unscrew: { sound: "chip" },
|
|
14897
16350
|
detach: { sound: "thunk" },
|
|
14898
|
-
ignite: { sound: "
|
|
14899
|
-
|
|
16351
|
+
ignite: { sound: "fire_ignite" },
|
|
16352
|
+
primed: { sound: "gas_leak" },
|
|
16353
|
+
extinguish: { sound: "fire_extinguish" },
|
|
14900
16354
|
melt_sizzle: { sound: "hiss", params: { seconds: 0.6 } },
|
|
14901
|
-
|
|
16355
|
+
// the blast family comes from the explosion's effect (`BLAST_KIND_OF`); this rule answers only an explosion the kit cannot place
|
|
16356
|
+
explode: { sound: "explosion_grenade", above: { volume: 0.9, sound: "explosion_big" } },
|
|
16357
|
+
...IMPACT_SOUND_KEYS
|
|
14902
16358
|
},
|
|
14903
16359
|
game: {
|
|
14904
16360
|
impact_metal: { sound: "sfx_impact" },
|
|
@@ -14912,14 +16368,26 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14912
16368
|
explode: { sound: "explosion_boom" }
|
|
14913
16369
|
}
|
|
14914
16370
|
};
|
|
14915
|
-
var DEFAULT_FIRE = { perFire: 0.
|
|
16371
|
+
var DEFAULT_FIRE = { perFire: 0.08, max: 0.45 };
|
|
16372
|
+
var DEFAULT_CRACKLES = { base: 2, perSqrtFire: 3, max: 14, volume: 0.5 };
|
|
16373
|
+
var DEFAULT_INDOOR_CONFINEMENT = 1.3;
|
|
14916
16374
|
function createDestructionSound(engine, options = {}) {
|
|
14917
16375
|
engine.register(DESTRUCTION_SOUND_BANK);
|
|
14918
16376
|
engine.register(GAME_SFX_BANK);
|
|
14919
|
-
|
|
16377
|
+
engine.register(FOLEY_BANK);
|
|
16378
|
+
const fire2 = { ...DEFAULT_FIRE, ...options.fire };
|
|
16379
|
+
const crackles = options.crackles === false ? null : { ...DEFAULT_CRACKLES, ...options.crackles };
|
|
16380
|
+
const fireLoop = options.fireLoop ?? "fire_loop";
|
|
16381
|
+
const kinds = { ...BLAST_KIND_OF, ...options.blastKinds };
|
|
16382
|
+
const farDistance = options.blastFarDistance ?? BLAST_FAR_DISTANCE;
|
|
16383
|
+
const indoorFrom = options.indoorConfinement ?? DEFAULT_INDOOR_CONFINEMENT;
|
|
14920
16384
|
const rules = { ...DESTRUCTION_SOUND_KEYS.art_scene, ...options.style === "game" ? DESTRUCTION_SOUND_KEYS.game : {}, ...options.keys };
|
|
16385
|
+
const blastByKind = options.style !== "game" && !(options.keys && "explode" in options.keys);
|
|
16386
|
+
const channel = engine.channel({ seed: options.seed ?? 1 });
|
|
14921
16387
|
let loop;
|
|
14922
16388
|
let burning = 0;
|
|
16389
|
+
const fires = [];
|
|
16390
|
+
let nextCrackle = 0;
|
|
14923
16391
|
const setFire = () => {
|
|
14924
16392
|
if (options.burnLoop === false) return;
|
|
14925
16393
|
if (burning <= 0) {
|
|
@@ -14927,35 +16395,120 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
14927
16395
|
loop = void 0;
|
|
14928
16396
|
return;
|
|
14929
16397
|
}
|
|
14930
|
-
loop ?? (loop = engine.loop(
|
|
14931
|
-
loop.set({ volume: Math.min(
|
|
16398
|
+
loop ?? (loop = engine.loop(fireLoop));
|
|
16399
|
+
loop.set({ volume: Math.min(fire2.max, fire2.perFire * burning) });
|
|
16400
|
+
};
|
|
16401
|
+
const forget = (point) => {
|
|
16402
|
+
let best = -1;
|
|
16403
|
+
let bestD = Infinity;
|
|
16404
|
+
fires.forEach((f, i) => {
|
|
16405
|
+
const d = (f[0] - point[0]) ** 2 + (f[1] - point[1]) ** 2 + (f[2] - point[2]) ** 2;
|
|
16406
|
+
if (d < bestD) {
|
|
16407
|
+
bestD = d;
|
|
16408
|
+
best = i;
|
|
16409
|
+
}
|
|
16410
|
+
});
|
|
16411
|
+
if (best >= 0) fires.splice(best, 1);
|
|
16412
|
+
};
|
|
16413
|
+
const blastSound = (point, volume, detail) => {
|
|
16414
|
+
const named = detail?.effect === void 0 ? void 0 : kinds[detail.effect];
|
|
16415
|
+
const kind = named ?? ((detail?.radius ?? 0) >= BIG_BLAST_RADIUS || volume >= 0.9 ? "big" : "grenade");
|
|
16416
|
+
const sound = BLAST_SOUND_OF[kind];
|
|
16417
|
+
const distance = engine.plan(sound, { position: point, seed: 1 })?.distance ?? 0;
|
|
16418
|
+
return kind !== "molotov" && distance > farDistance ? "explosion_far" : sound;
|
|
14932
16419
|
};
|
|
14933
16420
|
return {
|
|
14934
|
-
onSound(key, point, volume) {
|
|
16421
|
+
onSound(key, point, volume, detail) {
|
|
14935
16422
|
if (key === "burn_loop") {
|
|
14936
16423
|
burning += 1;
|
|
16424
|
+
fires.push(point);
|
|
14937
16425
|
setFire();
|
|
14938
16426
|
return;
|
|
14939
16427
|
}
|
|
14940
16428
|
if (key === "burn_end") {
|
|
14941
16429
|
if (burning > 0) burning -= 1;
|
|
16430
|
+
forget(point);
|
|
14942
16431
|
setFire();
|
|
14943
16432
|
return;
|
|
14944
16433
|
}
|
|
14945
|
-
|
|
14946
|
-
|
|
14947
|
-
|
|
14948
|
-
|
|
16434
|
+
if (key === "explode" && blastByKind) {
|
|
16435
|
+
const sound2 = blastSound(point, volume, detail);
|
|
16436
|
+
engine.play(sound2, { position: point, volume });
|
|
16437
|
+
if (sound2 !== "explosion_far" && sound2 !== "molotov_break_ignite" && (detail?.confinement ?? 1) >= indoorFrom) engine.play("explosion_indoor_tail", { position: point, volume });
|
|
16438
|
+
return;
|
|
16439
|
+
}
|
|
16440
|
+
let rule;
|
|
16441
|
+
for (const k of detail?.keys ?? []) {
|
|
16442
|
+
if (k in rules) {
|
|
16443
|
+
rule = rules[k];
|
|
16444
|
+
break;
|
|
16445
|
+
}
|
|
16446
|
+
}
|
|
16447
|
+
if (rule === void 0) rule = key in rules ? rules[key] : rules[key.replace(/^shot_/, "impact_")];
|
|
16448
|
+
if (rule === null) return;
|
|
16449
|
+
if (!rule) {
|
|
16450
|
+
if (engine.registry.sound(key)) engine.play(key, { position: point, volume });
|
|
16451
|
+
return;
|
|
16452
|
+
}
|
|
16453
|
+
const wanted = rule.above && volume >= rule.above.volume ? rule.above.sound : rule.sound;
|
|
16454
|
+
const sound = rule.fallback && !engine.registry.sound(wanted) ? rule.fallback : wanted;
|
|
16455
|
+
const params = detail?.seconds === void 0 ? rule.params : { ...rule.params, seconds: detail.seconds };
|
|
16456
|
+
engine.play(sound, { position: point, volume: volume * (rule.volumeScale ?? 1), ...params ? { params } : {} });
|
|
16457
|
+
},
|
|
16458
|
+
update(dt) {
|
|
16459
|
+
if (!crackles || fires.length === 0 || options.burnLoop === false) return;
|
|
16460
|
+
nextCrackle -= dt;
|
|
16461
|
+
for (let i = 0; i < 4 && nextCrackle <= 0; i++) {
|
|
16462
|
+
const rate = Math.min(crackles.max, crackles.base + crackles.perSqrtFire * Math.sqrt(fires.length));
|
|
16463
|
+
nextCrackle += (0.4 + channel.random() * 1.2) / rate;
|
|
16464
|
+
const at3 = fires[Math.floor(channel.random() * fires.length)];
|
|
16465
|
+
engine.play(channel.random() < 0.18 ? "fire_pop" : "fire_crackle", { position: at3, volume: crackles.volume });
|
|
16466
|
+
}
|
|
16467
|
+
if (nextCrackle < 0) nextCrackle = 0;
|
|
16468
|
+
},
|
|
16469
|
+
blastSound,
|
|
16470
|
+
rule(key, detail) {
|
|
16471
|
+
for (const k of detail?.keys ?? []) if (k in rules) return rules[k] ?? void 0;
|
|
16472
|
+
return rules[key] ?? void 0;
|
|
14949
16473
|
},
|
|
14950
|
-
rule: (key) => rules[key] ?? void 0,
|
|
14951
16474
|
burning: () => burning,
|
|
14952
16475
|
dispose() {
|
|
14953
16476
|
loop?.stop();
|
|
14954
16477
|
loop = void 0;
|
|
14955
16478
|
burning = 0;
|
|
16479
|
+
fires.length = 0;
|
|
14956
16480
|
}
|
|
14957
16481
|
};
|
|
14958
16482
|
}
|
|
16483
|
+
|
|
16484
|
+
// src/audio/samples.ts
|
|
16485
|
+
var blast2 = (gain) => ({ bus: "world", gain, falloff: BLAST_FALLOFF, cutoffK: 6e-3, priority: 3 });
|
|
16486
|
+
var fire = (gain, group) => ({ bus: "world", gain, falloff: FIRE_FALLOFF, cutoffK: 0.01, ...group ? { group } : {} });
|
|
16487
|
+
var BLAST_FIRE_SAMPLES = {
|
|
16488
|
+
explosion_grenade: blast2(1),
|
|
16489
|
+
explosion_big: blast2(1),
|
|
16490
|
+
explosion_car: blast2(1),
|
|
16491
|
+
explosion_flashbang: blast2(1),
|
|
16492
|
+
molotov_break_ignite: blast2(0.8),
|
|
16493
|
+
// the far takes are already muffled: no extra distance lowpass
|
|
16494
|
+
explosion_far: { bus: "world", gain: 1, falloff: BLAST_FAR_FALLOFF, cutoffK: 0, priority: 2 },
|
|
16495
|
+
fire_ignite: fire(0.8, "fire_ignite"),
|
|
16496
|
+
fire_crackle: fire(0.8, "fire_crackle"),
|
|
16497
|
+
fire_pop: fire(0.6, "fire_crackle"),
|
|
16498
|
+
fire_extinguish: fire(0.7),
|
|
16499
|
+
gas_leak: fire(0.5),
|
|
16500
|
+
// the roar: recorded fires chained with a crossfade (the level comes from `createDestructionSound`, by how much burns)
|
|
16501
|
+
fire_loop: { bus: "world", gain: 4, loop: { crossfade: 1 } }
|
|
16502
|
+
};
|
|
16503
|
+
function blastFireSampleBank(manifest, options = {}) {
|
|
16504
|
+
const sounds = options.sounds ?? BLAST_FIRE_SAMPLES;
|
|
16505
|
+
const bank = sampleBankFromManifest(manifest, { id: options.id ?? "destruction-samples", ...options.baseUrl === void 0 ? {} : { baseUrl: options.baseUrl }, sounds });
|
|
16506
|
+
const samples = (bank.samples ?? []).map((sample) => {
|
|
16507
|
+
const loop = sounds[sample.id]?.loop;
|
|
16508
|
+
return loop === void 0 ? sample : { ...sample, loop };
|
|
16509
|
+
});
|
|
16510
|
+
return { ...bank, samples };
|
|
16511
|
+
}
|
|
14959
16512
|
return __toCommonJS(index_exports);
|
|
14960
16513
|
})();
|
|
14961
16514
|
//# sourceMappingURL=index.global.js.map
|