@adatechnology/game-characters-three 0.1.4 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/dist/index.d.ts +171 -21
- package/dist/index.global.js +564 -53
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +357 -53
- package/dist/index.js.map +1 -1
- package/package.json +7 -6
package/dist/index.global.js
CHANGED
|
@@ -24,7 +24,10 @@ var GameCharactersThree = (() => {
|
|
|
24
24
|
BAKE_NEUTRAL_POSE: () => BAKE_NEUTRAL_POSE,
|
|
25
25
|
BODY_CHUNK: () => BODY_CHUNK,
|
|
26
26
|
BODY_MATERIAL_DEF: () => BODY_MATERIAL_DEF,
|
|
27
|
+
BODY_SOUNDS: () => BODY_SOUNDS,
|
|
27
28
|
CHARACTERS_AREA_ID: () => CHARACTERS_AREA_ID,
|
|
29
|
+
CHARACTER_SOUNDS: () => CHARACTER_SOUNDS,
|
|
30
|
+
CHARACTER_SOUND_BANK: () => CHARACTER_SOUND_BANK,
|
|
28
31
|
EXTRAS: () => EXTRAS,
|
|
29
32
|
FACE_FEATURES: () => FACE_FEATURES,
|
|
30
33
|
HAND_ITEMS: () => HAND_ITEMS,
|
|
@@ -37,16 +40,22 @@ var GameCharactersThree = (() => {
|
|
|
37
40
|
LOD_SEGMENTS: () => LOD_SEGMENTS,
|
|
38
41
|
PENDULUM: () => PENDULUM,
|
|
39
42
|
PERSON_ITEM_PREFIX: () => PERSON_ITEM_PREFIX,
|
|
43
|
+
PLAYER_SOUNDS: () => PLAYER_SOUNDS,
|
|
44
|
+
UNDEAD_VOICES: () => UNDEAD_VOICES,
|
|
45
|
+
UNDEAD_VOICE_GROUP: () => UNDEAD_VOICE_GROUP,
|
|
46
|
+
UNDEAD_VOICE_SOURCES: () => UNDEAD_VOICE_SOURCES,
|
|
40
47
|
ZOMBIE_ITEM_PREFIX: () => ZOMBIE_ITEM_PREFIX,
|
|
41
48
|
bakeBody: () => bakeBody,
|
|
42
49
|
bakeVariants: () => bakeVariants,
|
|
43
50
|
blobGeometry: () => blobGeometry,
|
|
44
51
|
blobRadii: () => blobRadii,
|
|
52
|
+
bloodLookOfAge: () => bloodLookOfAge,
|
|
45
53
|
buildInstancedBody: () => buildInstancedBody,
|
|
46
54
|
createBestBuilder: () => createBestBuilder,
|
|
47
55
|
createBodyBatch: () => createBodyBatch,
|
|
48
56
|
createBodyChunk: () => createBodyChunk,
|
|
49
57
|
createBodyMaterial: () => createBodyMaterial,
|
|
58
|
+
createCharacterSound: () => createCharacterSound,
|
|
50
59
|
createCharactersTestModule: () => createCharactersTestModule,
|
|
51
60
|
createEye: () => createEye,
|
|
52
61
|
createFluidsBridge: () => createFluidsBridge,
|
|
@@ -349,6 +358,13 @@ var GameCharactersThree = (() => {
|
|
|
349
358
|
}
|
|
350
359
|
return removed;
|
|
351
360
|
},
|
|
361
|
+
remove(index) {
|
|
362
|
+
const entry = entries[index];
|
|
363
|
+
if (!entry) return void 0;
|
|
364
|
+
entries[index] = entries[entries.length - 1];
|
|
365
|
+
entries.pop();
|
|
366
|
+
return entry.data;
|
|
367
|
+
},
|
|
352
368
|
clear() {
|
|
353
369
|
entries.length = 0;
|
|
354
370
|
}
|
|
@@ -2864,7 +2880,7 @@ var GameCharactersThree = (() => {
|
|
|
2864
2880
|
const TORSO_P = [[0.18, 0.86], [0.205, 0.95], [0.195, 1.03], [0.19, 1.12], [0.225, 1.27], [0.26, 1.4], [0.265, 1.47], [0.21, 1.55], [0.085, 1.6]];
|
|
2865
2881
|
const TORSO_F = [[0.17, 0.86], [0.215, 0.95], [0.2, 1.02], [0.165, 1.1], [0.2, 1.25], [0.245, 1.38], [0.25, 1.46], [0.2, 1.54], [0.085, 1.6]];
|
|
2866
2882
|
const torsoGeo = (sx, sz, fem) => {
|
|
2867
|
-
const g = new THREE.LatheGeometry(new THREE.SplineCurve((fem ? TORSO_F : TORSO_P).map((
|
|
2883
|
+
const g = new THREE.LatheGeometry(new THREE.SplineCurve((fem ? TORSO_F : TORSO_P).map((p2) => new THREE.Vector2(p2[0], p2[1]))).getPoints(Math.max(8, Math.round(30 * LK))), Math.max(6, Math.round(24 * LK)));
|
|
2868
2884
|
g.scale(1.12 * (sx || 1), 1, 0.64 * (sz || 1));
|
|
2869
2885
|
return g;
|
|
2870
2886
|
};
|
|
@@ -2952,34 +2968,34 @@ var GameCharactersThree = (() => {
|
|
|
2952
2968
|
const skinFinal = P.char ? 1840658 : P.wet ? col(skinC, 8032160, 0.55) : skinC;
|
|
2953
2969
|
const skinM = M(skinFinal);
|
|
2954
2970
|
const topM = M(P.char ? col(topC, 1380880, 0.75) : P.wet ? col(topC, 1712688, 0.45) : col(topC, GRAY2, d * 0.3)), pantsM = M(col(pantC, GRAY2, d * 0.3)), shoeM = M(T.shoeColor), red = M(RED2);
|
|
2955
|
-
const add = (
|
|
2971
|
+
const add = (p2, geo, m, x, y, z2, rx, ry, rz) => {
|
|
2956
2972
|
const o = new THREE.Mesh(geo, m);
|
|
2957
2973
|
o.position.set(x || 0, y || 0, z2 || 0);
|
|
2958
2974
|
if (rx || ry || rz) o.rotation.set(rx || 0, ry || 0, rz || 0);
|
|
2959
|
-
|
|
2975
|
+
p2.add(o);
|
|
2960
2976
|
return o;
|
|
2961
2977
|
};
|
|
2962
|
-
const ball = (
|
|
2978
|
+
const ball = (p2, r, m, x, y, z2) => add(p2, SPH(r, SEG, 12), m, x, y, z2);
|
|
2963
2979
|
topM_ref = topM;
|
|
2964
2980
|
const SKM = {}, skM = (c) => SKM[c] || (SKM[c] = new THREE.MeshStandardMaterial({ color: c, roughness: 0.3, metalness: 0, polygonOffset: true, polygonOffsetFactor: -4, polygonOffsetUnits: -4 }));
|
|
2965
|
-
const flat = (
|
|
2981
|
+
const flat = (p2, x, y, zz, sx, sy, c) => {
|
|
2966
2982
|
const m = new THREE.Mesh(BLOB, skM(c));
|
|
2967
2983
|
m.rotation.set(PI / 2, 0, BR() * 6.28);
|
|
2968
2984
|
m.scale.set(sx, 1, sy);
|
|
2969
2985
|
m.position.set(x, y, zz);
|
|
2970
|
-
|
|
2986
|
+
p2.add(m);
|
|
2971
2987
|
return m;
|
|
2972
2988
|
};
|
|
2973
|
-
const splat = (
|
|
2974
|
-
const a = flat(
|
|
2989
|
+
const splat = (p2, x, y, zz, r, c, n) => {
|
|
2990
|
+
const a = flat(p2, x, y, zz + 4e-3, r, r * (0.7 + BR() * 0.5), c);
|
|
2975
2991
|
for (let k = 0; k < (n || 0); k++) {
|
|
2976
2992
|
const an = BR() * 6.28, dd = r * (1.2 + BR() * 0.9), q = r * (0.12 + BR() * 0.18);
|
|
2977
|
-
flat(
|
|
2993
|
+
flat(p2, x + Math.cos(an) * dd, y + Math.sin(an) * dd, zz + 4e-3, q, q * 0.7, c);
|
|
2978
2994
|
}
|
|
2979
|
-
if (n) run(
|
|
2995
|
+
if (n) run(p2, x + r * 0.15, y - r * 0.5, y - r * (2.2 + BR() * 1.2), zz + 3e-3, zz, c, r * 0.35);
|
|
2980
2996
|
return a;
|
|
2981
2997
|
};
|
|
2982
|
-
const run = (
|
|
2998
|
+
const run = (p2, x, y0, y1, z0, z1, c, w) => {
|
|
2983
2999
|
const L = y0 - y1, sh = new THREE.Shape();
|
|
2984
3000
|
sh.moveTo(-w / 2, 0);
|
|
2985
3001
|
sh.lineTo(w / 2, 0);
|
|
@@ -2989,30 +3005,30 @@ var GameCharactersThree = (() => {
|
|
|
2989
3005
|
const g = new THREE.ShapeGeometry(sh), m = new THREE.Mesh(g, skM(c));
|
|
2990
3006
|
m.position.set(x, y0, z0);
|
|
2991
3007
|
m.rotation.x = -Math.atan2(z0 - z1, L);
|
|
2992
|
-
|
|
3008
|
+
p2.add(m);
|
|
2993
3009
|
const bl = new THREE.Mesh(SPH(w * 0.42, 10, 8), skM(c));
|
|
2994
3010
|
bl.scale.set(1, 1.35, 0.5);
|
|
2995
3011
|
bl.position.set(x + w * 0.03, y1, z1);
|
|
2996
|
-
|
|
3012
|
+
p2.add(bl);
|
|
2997
3013
|
return bl;
|
|
2998
3014
|
};
|
|
2999
|
-
const stump = (
|
|
3000
|
-
const st = ball(
|
|
3015
|
+
const stump = (p2, r, y, up) => {
|
|
3016
|
+
const st = ball(p2, r * 1.02, red, 0, y, 0);
|
|
3001
3017
|
st.scale.set(1, 0.35, 1);
|
|
3002
|
-
add(
|
|
3018
|
+
add(p2, CYL(r * 0.32, r * 0.36, 0.07, 10), M(15261900), 0, y + (up ? 0.04 : -0.04), 0);
|
|
3003
3019
|
};
|
|
3004
|
-
const ring = (
|
|
3005
|
-
const o = add(
|
|
3020
|
+
const ring = (p2, r, h, m, y, sx, sz) => {
|
|
3021
|
+
const o = add(p2, CYL(r, r, h, 24), m, 0, y, 0);
|
|
3006
3022
|
o.scale.set(sx || 1.12, 1, sz || 0.7);
|
|
3007
3023
|
return o;
|
|
3008
3024
|
};
|
|
3009
3025
|
const root = new THREE.Group(), fig = new THREE.Group();
|
|
3010
|
-
const drip = (
|
|
3026
|
+
const drip = (p2, x, y, zz, kind, every) => {
|
|
3011
3027
|
if (d >= 3 && kind !== "bile") return;
|
|
3012
3028
|
const o = new THREE.Object3D();
|
|
3013
3029
|
o.position.set(x, y, zz);
|
|
3014
3030
|
o.userData.drip = { kind: kind || (d < 1 ? "blood" : "old"), every: every || (d < 1 ? 1.2 : 2.4) };
|
|
3015
|
-
|
|
3031
|
+
p2.add(o);
|
|
3016
3032
|
};
|
|
3017
3033
|
fig.scale.set(P.s * P.bulk, P.s, P.s * Math.min(1.15, P.bulk));
|
|
3018
3034
|
fig.position.y = P.drop * P.s;
|
|
@@ -4182,7 +4198,7 @@ var GameCharactersThree = (() => {
|
|
|
4182
4198
|
}
|
|
4183
4199
|
function torsoGeo(fem) {
|
|
4184
4200
|
const P = fem ? [[0.17, 0.86], [0.215, 0.95], [0.2, 1.02], [0.165, 1.1], [0.2, 1.25], [0.245, 1.38], [0.25, 1.46], [0.2, 1.54], [0.085, 1.6]] : [[0.18, 0.86], [0.205, 0.95], [0.195, 1.03], [0.19, 1.12], [0.225, 1.27], [0.26, 1.4], [0.265, 1.47], [0.21, 1.55], [0.085, 1.6]];
|
|
4185
|
-
const pts = new THREE.SplineCurve(P.map((
|
|
4201
|
+
const pts = new THREE.SplineCurve(P.map((p2) => new THREE.Vector2(p2[0], p2[1]))).getPoints(30);
|
|
4186
4202
|
const g = new THREE.LatheGeometry(pts, 24);
|
|
4187
4203
|
g.scale(1.12, 1, 0.64);
|
|
4188
4204
|
return g;
|
|
@@ -4537,15 +4553,15 @@ var GameCharactersThree = (() => {
|
|
|
4537
4553
|
}
|
|
4538
4554
|
const MOVES_IDLE = MOVES.idle;
|
|
4539
4555
|
function pose(c, z, W, t) {
|
|
4540
|
-
const
|
|
4541
|
-
const breathe = reduce ? 0 : Math.sin(
|
|
4556
|
+
const p2 = c.ph + t, freq = z ? 3.4 : 5.6, ph = t * freq + c.ph;
|
|
4557
|
+
const breathe = reduce ? 0 : Math.sin(p2 * 1.6) * 0.012;
|
|
4542
4558
|
c.upper.scale.y = 1 + breathe;
|
|
4543
4559
|
const hunch = c.hunch + (z ? 0.38 : 0) + W * 0.05;
|
|
4544
4560
|
c.upper.rotation.x = hunch;
|
|
4545
4561
|
c.upper.rotation.y = W * Math.sin(ph) * 0.1;
|
|
4546
4562
|
c.upper.rotation.z = z ? Math.sin(ph * 0.5) * 0.06 * W + 0.05 : 0;
|
|
4547
4563
|
c.fig.position.y = -W * Math.abs(Math.sin(ph)) * 0.035;
|
|
4548
|
-
c.headG.rotation.y = reduce ? 0 : Math.sin(
|
|
4564
|
+
c.headG.rotation.y = reduce ? 0 : Math.sin(p2 * 0.5) * 0.25 * (z ? 0.3 : 1) * (W ? 0.4 : 1) * (t ? 1 : 0);
|
|
4549
4565
|
c.headG.rotation.x = -hunch * 0.6 + (z ? 0.15 : 0);
|
|
4550
4566
|
c.headG.rotation.z = z ? 0.22 : 0;
|
|
4551
4567
|
c.legs.forEach((l, k) => {
|
|
@@ -4558,7 +4574,7 @@ var GameCharactersThree = (() => {
|
|
|
4558
4574
|
const raise = z ? 1 : 0;
|
|
4559
4575
|
const base = a.hold ? -0.2 : 0;
|
|
4560
4576
|
const swing = -a.s * Math.sin(ph) * (z ? 0.12 : 0.42) * W * (a.grip ? 0 : 1);
|
|
4561
|
-
a.g.rotation.x = (a.grip && !z ? -0.75 : base - raise * (z ? 1.12 : 1.3)) + swing + (z && !reduce && t ? Math.sin(
|
|
4577
|
+
a.g.rotation.x = (a.grip && !z ? -0.75 : base - raise * (z ? 1.12 : 1.3)) + swing + (z && !reduce && t ? Math.sin(p2 * 3 + a.s * 2) * 0.08 : 0);
|
|
4562
4578
|
a.g.rotation.z = a.s * (0.07 + (z ? 0.1 : 0)) + (a.grip && !z ? -a.s * 0.35 : 0);
|
|
4563
4579
|
a.el.rotation.x = z ? -0.18 : a.grip ? -1.1 : -(0.12 + (a.hold ? 0.25 : 0) + W * (0.25 + Math.max(0, a.s * Math.sin(ph)) * 0.3));
|
|
4564
4580
|
if (a.fingers) {
|
|
@@ -4583,16 +4599,16 @@ var GameCharactersThree = (() => {
|
|
|
4583
4599
|
c.mouth.visible = true;
|
|
4584
4600
|
c.bags.material.opacity = 0.9;
|
|
4585
4601
|
}
|
|
4586
|
-
function buildPerson(
|
|
4602
|
+
function buildPerson(p2, zed) {
|
|
4587
4603
|
const root = new THREE.Group(), chars = [];
|
|
4588
|
-
if (
|
|
4589
|
-
const c = build(
|
|
4604
|
+
if (p2.b) {
|
|
4605
|
+
const c = build(p2.b, 0);
|
|
4590
4606
|
chars.push(c);
|
|
4591
4607
|
root.add(c.root);
|
|
4592
|
-
if (zed && !
|
|
4593
|
-
c.z = zed && !
|
|
4608
|
+
if (zed && !p2.kid) zombify(c, p2.zcat);
|
|
4609
|
+
c.z = zed && !p2.kid;
|
|
4594
4610
|
}
|
|
4595
|
-
(
|
|
4611
|
+
(p2.kids || []).forEach((k) => {
|
|
4596
4612
|
const c = build(k, 0);
|
|
4597
4613
|
c.root.position.x = k.x;
|
|
4598
4614
|
c.root.rotation.y = -k.x * 0.4;
|
|
@@ -4850,11 +4866,11 @@ var GameCharactersThree = (() => {
|
|
|
4850
4866
|
};
|
|
4851
4867
|
return {
|
|
4852
4868
|
pieces,
|
|
4853
|
-
launch(source,
|
|
4869
|
+
launch(source, scene2, direction, dress, tag) {
|
|
4854
4870
|
source.updateWorldMatrix(true, true);
|
|
4855
4871
|
const clone = source.clone(true);
|
|
4856
4872
|
source.matrixWorld.decompose(clone.position, clone.quaternion, clone.scale);
|
|
4857
|
-
|
|
4873
|
+
scene2.add(clone);
|
|
4858
4874
|
dress?.(clone);
|
|
4859
4875
|
return add(
|
|
4860
4876
|
clone,
|
|
@@ -5003,7 +5019,7 @@ var GameCharactersThree = (() => {
|
|
|
5003
5019
|
// src/wounds/wounds.ts
|
|
5004
5020
|
var worldPosition = (three, object) => object.getWorldPosition(new three.Vector3());
|
|
5005
5021
|
var createWounds = (three, options) => {
|
|
5006
|
-
const { random, scene, bridge } = options;
|
|
5022
|
+
const { random, scene: scene2, bridge, sound } = options;
|
|
5007
5023
|
const materials = options.materials ?? createWoundMaterials(three);
|
|
5008
5024
|
const flying = createFlyingPieces(three, { random, ...options.groundAt ? { groundAt: options.groundAt } : {}, ...options.maxPieces ? { max: options.maxPieces } : {} });
|
|
5009
5025
|
const states = /* @__PURE__ */ new Map();
|
|
@@ -5012,9 +5028,9 @@ var GameCharactersThree = (() => {
|
|
|
5012
5028
|
if (!found) throw new Error("game-characters-three: this body is not tracked by the wounds (call `track` first)");
|
|
5013
5029
|
return found;
|
|
5014
5030
|
};
|
|
5015
|
-
const burstBlood = (change, object) => {
|
|
5031
|
+
const burstBlood = (state, change, object, direction) => {
|
|
5016
5032
|
const point = worldPosition(three, object);
|
|
5017
|
-
bridge?.burst(change, [point.x, point.y, point.z]);
|
|
5033
|
+
bridge?.burst(change, [point.x, point.y, point.z], state.body.blood, direction ? [direction.x, direction.y, direction.z] : void 0);
|
|
5018
5034
|
};
|
|
5019
5035
|
const sideOf2 = (object, body) => new three.Vector3(object.position.x >= 0 ? 1 : -1, 0, 0).applyQuaternion(body.root.quaternion);
|
|
5020
5036
|
const hideBelow = (state, id) => {
|
|
@@ -5029,7 +5045,7 @@ var GameCharactersThree = (() => {
|
|
|
5029
5045
|
}
|
|
5030
5046
|
const { node, radius, flip } = target;
|
|
5031
5047
|
const direction = sideOf2(node, state.body);
|
|
5032
|
-
const fell = flying.launch(node,
|
|
5048
|
+
const fell = flying.launch(node, scene2, direction, (clone) => {
|
|
5033
5049
|
makeCut(three, materials, random, clone, radius, true);
|
|
5034
5050
|
}, id);
|
|
5035
5051
|
void fell;
|
|
@@ -5043,7 +5059,7 @@ var GameCharactersThree = (() => {
|
|
|
5043
5059
|
for (let o = pendulum.node; o; o = o.parent) if (!o.visible) shown = false;
|
|
5044
5060
|
if (!shown) state.pendulums.splice(i, 1);
|
|
5045
5061
|
}
|
|
5046
|
-
burstBlood("severed", node);
|
|
5062
|
+
burstBlood(state, "severed", node, direction);
|
|
5047
5063
|
if (id === "head") state.dead = true;
|
|
5048
5064
|
};
|
|
5049
5065
|
const destroy = (state, id, direction) => {
|
|
@@ -5052,14 +5068,14 @@ var GameCharactersThree = (() => {
|
|
|
5052
5068
|
const { node, radius, flip } = target;
|
|
5053
5069
|
const box = new three.Box3().setFromObject(node);
|
|
5054
5070
|
explodeChunks(three, materials, random, box, direction, (chunk, velocity, spin) => {
|
|
5055
|
-
|
|
5071
|
+
scene2.add(chunk);
|
|
5056
5072
|
flying.throwObject(chunk, velocity, spin, id);
|
|
5057
5073
|
});
|
|
5058
5074
|
node.visible = false;
|
|
5059
5075
|
makeStump(three, materials, random, node.parent, node.position, radius, flip);
|
|
5060
5076
|
state.gone.add(id);
|
|
5061
5077
|
hideBelow(state, id);
|
|
5062
|
-
burstBlood("destroyed", node);
|
|
5078
|
+
burstBlood(state, "destroyed", node, direction);
|
|
5063
5079
|
if (id === "head") state.dead = true;
|
|
5064
5080
|
};
|
|
5065
5081
|
const breakBone = (state, id) => {
|
|
@@ -5079,7 +5095,7 @@ var GameCharactersThree = (() => {
|
|
|
5079
5095
|
const split2 = (state, direction) => {
|
|
5080
5096
|
const upper = state.body.rig.upper;
|
|
5081
5097
|
if (!upper.visible) return;
|
|
5082
|
-
flying.launch(upper,
|
|
5098
|
+
flying.launch(upper, scene2, direction, (clone) => {
|
|
5083
5099
|
makeCut(three, materials, random, clone, 0.16, false);
|
|
5084
5100
|
}, "torso");
|
|
5085
5101
|
upper.visible = false;
|
|
@@ -5087,7 +5103,7 @@ var GameCharactersThree = (() => {
|
|
|
5087
5103
|
for (const id of ["torso", "neck", "head", "jaw", "upperArmL", "upperArmR", "forearmL", "forearmR", "handL", "handR"]) state.gone.add(id);
|
|
5088
5104
|
state.pendulums.length = 0;
|
|
5089
5105
|
state.dead = true;
|
|
5090
|
-
burstBlood("split", upper);
|
|
5106
|
+
burstBlood(state, "split", upper, direction);
|
|
5091
5107
|
};
|
|
5092
5108
|
const direction3 = (v, fallback) => v ? new three.Vector3(v[0], v[1], v[2]).normalize() : fallback;
|
|
5093
5109
|
return {
|
|
@@ -5121,6 +5137,10 @@ var GameCharactersThree = (() => {
|
|
|
5121
5137
|
}
|
|
5122
5138
|
if (event.type !== "body") return;
|
|
5123
5139
|
const id = event.part;
|
|
5140
|
+
if (sound) {
|
|
5141
|
+
const heard = worldPosition(three, (id ? body.nodes[id]?.node : void 0) ?? body.root);
|
|
5142
|
+
sound.body(event, [heard.x, heard.y, heard.z]);
|
|
5143
|
+
}
|
|
5124
5144
|
const fallback = new three.Vector3(0, 0.2, 1);
|
|
5125
5145
|
const direction = direction3(event.exit, fallback);
|
|
5126
5146
|
switch (event.change) {
|
|
@@ -5147,8 +5167,10 @@ var GameCharactersThree = (() => {
|
|
|
5147
5167
|
break;
|
|
5148
5168
|
case "wound": {
|
|
5149
5169
|
const target = id ? body.nodes[id] : void 0;
|
|
5170
|
+
const at = worldPosition(three, target?.node ?? body.root);
|
|
5171
|
+
bridge?.wound([at.x, at.y, at.z], body.blood, event.exit ? [direction.x, direction.y, direction.z] : void 0);
|
|
5150
5172
|
if (target && event.exit) gouge(three, materials, random, target.node, id.replace(/[LR]$/, ""), worldPosition(three, target.node), direction.clone().negate(), direction, 60, (chunk, velocity, spin) => {
|
|
5151
|
-
|
|
5173
|
+
scene2.add(chunk);
|
|
5152
5174
|
flying.throwObject(chunk, velocity, spin, id);
|
|
5153
5175
|
});
|
|
5154
5176
|
break;
|
|
@@ -5194,8 +5216,28 @@ var GameCharactersThree = (() => {
|
|
|
5194
5216
|
};
|
|
5195
5217
|
|
|
5196
5218
|
// src/wounds/fluids-bridge.ts
|
|
5219
|
+
var colorOf = (hex2) => Number.parseInt(hex2.replace(/^#|^0x/i, ""), 16);
|
|
5220
|
+
var bloodLookOfAge = (age, options = {}) => ({
|
|
5221
|
+
...age.blood < (options.thinBelow ?? 0.3) ? { liquid: options.thinLiquid ?? "old_blood" } : {},
|
|
5222
|
+
tint: { fresh: colorOf(age.freshBloodColor), dry: colorOf(age.dryBloodColor) },
|
|
5223
|
+
amount: age.blood
|
|
5224
|
+
});
|
|
5197
5225
|
var BURST_LITERS = { severed: 0.35, destroyed: 0.6, split: 0.9 };
|
|
5198
|
-
var
|
|
5226
|
+
var BURST_DROPS = { severed: 4, destroyed: 7, split: 10 };
|
|
5227
|
+
var createFluidsBridge = ({ sink, film, spray, burstDrops = BURST_DROPS, liquid = "blood", spurtSpeed = 1.4 }) => {
|
|
5228
|
+
const throwDrops = (point, wanted, look, direction, speed, radius) => {
|
|
5229
|
+
const amount = look?.amount ?? 1;
|
|
5230
|
+
const count = amount <= 0 ? 0 : Math.max(1, Math.round(wanted * Math.min(1, amount)));
|
|
5231
|
+
return film && count > 0 ? film.splat({
|
|
5232
|
+
fluid: look?.liquid ?? liquid,
|
|
5233
|
+
point,
|
|
5234
|
+
count,
|
|
5235
|
+
...direction ? { direction } : {},
|
|
5236
|
+
...speed !== void 0 ? { speed } : {},
|
|
5237
|
+
...radius !== void 0 ? { radius } : {},
|
|
5238
|
+
...look?.tint ? { tint: { fresh: look.tint.fresh, dry: look.tint.dry } } : {}
|
|
5239
|
+
}) : 0;
|
|
5240
|
+
};
|
|
5199
5241
|
const bleed = (point, litersPerSecond, dt, direction = [0, -1, 0], pressurized = false) => {
|
|
5200
5242
|
const liters = litersPerSecond * dt;
|
|
5201
5243
|
if (liters <= 0) return;
|
|
@@ -5207,10 +5249,462 @@ var GameCharactersThree = (() => {
|
|
|
5207
5249
|
handle(event) {
|
|
5208
5250
|
if (event.type === "leak" && event.fluid === "blood") bleed(event.point, event.rate, 1, event.direction, event.pressurized);
|
|
5209
5251
|
},
|
|
5210
|
-
burst
|
|
5252
|
+
burst(change, point, look, direction) {
|
|
5253
|
+
sink.splash(look?.liquid ?? liquid, point, BURST_LITERS[change]);
|
|
5254
|
+
throwDrops(point, burstDrops[change], look, direction);
|
|
5255
|
+
},
|
|
5256
|
+
wound: (point, look, direction) => throwDrops(point, spray?.count ?? 3, look, direction, spray?.speed, spray?.radius)
|
|
5257
|
+
};
|
|
5258
|
+
};
|
|
5259
|
+
|
|
5260
|
+
// ../game-audio/dist/index.js
|
|
5261
|
+
var DISTANCE_CURVES = {
|
|
5262
|
+
/** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
|
|
5263
|
+
game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
|
|
5264
|
+
/** The game's `grito`: `1 / (1 + d² × 0.006)`, silent below 0.02 (jogo L62129–62130). */
|
|
5265
|
+
game_scream: { model: "inverse_square", k: 6e-3, minGain: 0.02 },
|
|
5266
|
+
/** The game's `voz`: `1 / (1 + d² × 0.01)`, silent below 0.02 (jogo L62146–62147). */
|
|
5267
|
+
game_voice: { model: "inverse_square", k: 0.01, minGain: 0.02 },
|
|
5268
|
+
/** The game's `boom`: `1.4 / (1 + d² × 0.002)`, never silent (jogo L68280). */
|
|
5269
|
+
game_boom: { model: "inverse_square", k: 2e-3, scale: 1.4 },
|
|
5270
|
+
/** The art scene's `outAt`: `vol / (1 + d² × 0.008)` (cena L1320). */
|
|
5271
|
+
art_scene: { model: "inverse_square", k: 8e-3 },
|
|
5272
|
+
/** The game's animal calls: `max(0, 1 − d / 70) × 0.25`, silent at or below 0.005 (jogo L66627–66628). */
|
|
5273
|
+
animals: { model: "linear", range: 70, scale: 0.25, minGain: 5e-3 }
|
|
5274
|
+
};
|
|
5275
|
+
var mix_profiles_default = [
|
|
5276
|
+
{
|
|
5277
|
+
id: "game",
|
|
5278
|
+
master: 0.5,
|
|
5279
|
+
noise: { seconds: 1.5, create: "lazy" },
|
|
5280
|
+
sources: ["jogo:L62077-62081 master 0.5 to the output", "jogo:L62082-62088 noise 1.5 s made by the first sound that needs it"]
|
|
5281
|
+
},
|
|
5282
|
+
{
|
|
5283
|
+
id: "art_scene",
|
|
5284
|
+
master: 0.85,
|
|
5285
|
+
compressor: { threshold: -12, ratio: 5 },
|
|
5286
|
+
reverb: { seconds: 2.2, decay: 3.4, wet: 0.4 },
|
|
5287
|
+
noise: { seconds: 2, create: "eager" },
|
|
5288
|
+
sources: [
|
|
5289
|
+
"cena:L1308 compressor -12 dB, ratio 5",
|
|
5290
|
+
"cena:L1309 master 0.85",
|
|
5291
|
+
"cena:L1310 convolver, impulse 2.2 s of (1 - i/len)^3.4",
|
|
5292
|
+
"cena:L1311 wet 0.4",
|
|
5293
|
+
"cena:L1312 noise 2 s made with the chain"
|
|
5294
|
+
]
|
|
5295
|
+
}
|
|
5296
|
+
];
|
|
5297
|
+
var MIX_PROFILES = Object.fromEntries(
|
|
5298
|
+
mix_profiles_default.map((profile) => [profile.id, profile])
|
|
5299
|
+
);
|
|
5300
|
+
var game_sfx_default = {
|
|
5301
|
+
sources: ["jogo:L62089-62107"],
|
|
5302
|
+
note: "The game's sfx table P: [lowpass cutoff Hz, peak gain, seconds]. Played as a noise burst with the game's distance curve (falloff game_sfx) and a 0.05 s tail. Team names in `team`.",
|
|
5303
|
+
classes: [
|
|
5304
|
+
{ id: "pistol", team: "pistola", bus: "weapons", cutoff: 1800, gain: 0.9, seconds: 0.18 },
|
|
5305
|
+
{ id: "shotgun", team: "escopeta", bus: "weapons", cutoff: 900, gain: 1.2, seconds: 0.35 },
|
|
5306
|
+
{ id: "rifle", team: "fuzil", bus: "weapons", cutoff: 1400, gain: 1.1, seconds: 0.28 },
|
|
5307
|
+
{ id: "long_rifle", team: "rifle", bus: "weapons", cutoff: 1100, gain: 1.3, seconds: 0.45 },
|
|
5308
|
+
{ id: "impact", team: "impacto", bus: "world", cutoff: 2500, gain: 0.25, seconds: 0.05 },
|
|
5309
|
+
{ id: "flesh", team: "carne", bus: "world", cutoff: 600, gain: 0.35, seconds: 0.08 },
|
|
5310
|
+
{ id: "step", team: "passo", bus: "world", cutoff: 400, gain: 0.08, seconds: 0.05 },
|
|
5311
|
+
{ id: "glass", team: "vidro", bus: "world", cutoff: 5e3, gain: 0.5, seconds: 0.3 },
|
|
5312
|
+
{ id: "wood", team: "madeira", bus: "world", cutoff: 700, gain: 0.5, seconds: 0.2 },
|
|
5313
|
+
{ id: "reload", team: "recarga", bus: "weapons", cutoff: 3e3, gain: 0.15, seconds: 0.06 },
|
|
5314
|
+
{ id: "empty", team: "vazio", bus: "weapons", cutoff: 4e3, gain: 0.12, seconds: 0.03 },
|
|
5315
|
+
{ id: "explosion", team: "explosao", bus: "world", cutoff: 200, gain: 1.6, seconds: 1.4 }
|
|
5316
|
+
],
|
|
5317
|
+
fallback: { id: "unknown", team: "(any other name)", bus: "world", cutoff: 1e3, gain: 0.5, seconds: 0.1 }
|
|
5318
|
+
};
|
|
5319
|
+
var GAME_SFX = game_sfx_default;
|
|
5320
|
+
var GAME_SFX_CLASSES = GAME_SFX.classes;
|
|
5321
|
+
var GAME_SFX_FALLBACK = GAME_SFX.fallback;
|
|
5322
|
+
function noiseClassRecipe(row, id = `sfx_${row.id}`) {
|
|
5323
|
+
return {
|
|
5324
|
+
id,
|
|
5325
|
+
bus: row.bus,
|
|
5326
|
+
order: "burst",
|
|
5327
|
+
duration: row.seconds,
|
|
5328
|
+
tail: 0.05,
|
|
5329
|
+
layers: [
|
|
5330
|
+
{
|
|
5331
|
+
source: { kind: "noise", offset: "random" },
|
|
5332
|
+
filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: row.cutoff } }] },
|
|
5333
|
+
envelope: [
|
|
5334
|
+
[0, row.gain, "set"],
|
|
5335
|
+
["1d", 1e-3, "exp", "fixed"]
|
|
5336
|
+
]
|
|
5337
|
+
}
|
|
5338
|
+
],
|
|
5339
|
+
falloff: DISTANCE_CURVES.game_sfx,
|
|
5340
|
+
sources: [...GAME_SFX.sources.map((source) => `${source} ${row.team}`)]
|
|
5211
5341
|
};
|
|
5342
|
+
}
|
|
5343
|
+
var GAME_SFX_BANK = { id: "game_sfx", sounds: [...GAME_SFX_CLASSES, GAME_SFX_FALLBACK].map((row) => noiseClassRecipe(row)) };
|
|
5344
|
+
var ATTACK = 2e-3;
|
|
5345
|
+
function lengthOf(d, attack) {
|
|
5346
|
+
if (typeof d === "number") return attack + d;
|
|
5347
|
+
if (Array.isArray(d)) return [attack + d[0], attack + d[1]];
|
|
5348
|
+
return { ...d, add: (d.add ?? 0) + attack };
|
|
5349
|
+
}
|
|
5350
|
+
var envelope = (attack) => [
|
|
5351
|
+
[0, 1e-4, "set", "fixed"],
|
|
5352
|
+
[attack, 1, "exp"],
|
|
5353
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
5354
|
+
];
|
|
5355
|
+
function sceneNoise(o) {
|
|
5356
|
+
const a = o.a ?? ATTACK;
|
|
5357
|
+
const over = typeof o.d === "number" ? o.d : 0;
|
|
5358
|
+
return {
|
|
5359
|
+
filters: {
|
|
5360
|
+
mode: "serial",
|
|
5361
|
+
bank: [{ type: o.type ?? "lowpass", frequency: o.f2 === void 0 ? { set: o.f } : { set: o.f, to: o.f2, curve: "exp", over }, q: o.q ?? 0.7 }]
|
|
5362
|
+
},
|
|
5363
|
+
duration: lengthOf(o.d, a),
|
|
5364
|
+
gain: o.vol,
|
|
5365
|
+
...o.delay === void 0 ? {} : { at: o.delay },
|
|
5366
|
+
...o.wet === void 0 ? {} : { wet: o.wet },
|
|
5367
|
+
source: { kind: "noise", offset: "random", offsetScale: 1.5, loop: true },
|
|
5368
|
+
envelope: envelope(a)
|
|
5369
|
+
};
|
|
5370
|
+
}
|
|
5371
|
+
function sceneTone(o) {
|
|
5372
|
+
return {
|
|
5373
|
+
source: { kind: "osc", wave: o.wave ?? "sine", frequency: { from: o.f, to: o.f2 ?? "from", curve: "exp", over: "duration" } },
|
|
5374
|
+
duration: lengthOf(o.d, ATTACK),
|
|
5375
|
+
gain: o.vol,
|
|
5376
|
+
...o.delay === void 0 ? {} : { at: o.delay },
|
|
5377
|
+
...o.wet === void 0 ? {} : { wet: o.wet },
|
|
5378
|
+
envelope: envelope(ATTACK)
|
|
5379
|
+
};
|
|
5380
|
+
}
|
|
5381
|
+
function sceneVoice(o) {
|
|
5382
|
+
return {
|
|
5383
|
+
duration: lengthOf(o.d, 0),
|
|
5384
|
+
gain: o.vol,
|
|
5385
|
+
wet: 0.45,
|
|
5386
|
+
source: {
|
|
5387
|
+
kind: "formant_voice",
|
|
5388
|
+
wave: o.wave ?? "sawtooth",
|
|
5389
|
+
frequency: { from: o.f0, to: o.f1, curve: "linear", over: "duration" },
|
|
5390
|
+
vibrato: { rate: [4, 10], depth: 0.08 },
|
|
5391
|
+
formants: [
|
|
5392
|
+
{ frequency: o.fA, q: 4 },
|
|
5393
|
+
{ frequency: o.fB, q: 6 }
|
|
5394
|
+
],
|
|
5395
|
+
breath: { frequency: o.fB, q: 1.1, gain: o.noise },
|
|
5396
|
+
mix: 3.2
|
|
5397
|
+
},
|
|
5398
|
+
envelope: [
|
|
5399
|
+
[0, 1e-4, "set", "fixed"],
|
|
5400
|
+
[0.1, 1, "exp"],
|
|
5401
|
+
["0.6d", 1, "set"],
|
|
5402
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
5403
|
+
]
|
|
5404
|
+
};
|
|
5405
|
+
}
|
|
5406
|
+
function sceneRecipe(id, layers, line, options = {}) {
|
|
5407
|
+
return {
|
|
5408
|
+
id,
|
|
5409
|
+
bus: options.bus ?? "world",
|
|
5410
|
+
pan: true,
|
|
5411
|
+
layers,
|
|
5412
|
+
falloff: DISTANCE_CURVES.art_scene,
|
|
5413
|
+
...options.vars ? { vars: options.vars } : {},
|
|
5414
|
+
...options.group ? { group: options.group } : {},
|
|
5415
|
+
sources: [`cena:${line}`]
|
|
5416
|
+
};
|
|
5417
|
+
}
|
|
5418
|
+
var BENCH_BANK = {
|
|
5419
|
+
id: "audio_bench",
|
|
5420
|
+
sounds: [
|
|
5421
|
+
{
|
|
5422
|
+
id: "bench_ping",
|
|
5423
|
+
bus: "ui",
|
|
5424
|
+
pan: true,
|
|
5425
|
+
duration: 0.25,
|
|
5426
|
+
layers: [
|
|
5427
|
+
{
|
|
5428
|
+
gain: 0.5,
|
|
5429
|
+
wet: 0.3,
|
|
5430
|
+
source: { kind: "osc", wave: "sine", frequency: { from: 880 } },
|
|
5431
|
+
envelope: [
|
|
5432
|
+
[0, 1e-4, "set", "fixed"],
|
|
5433
|
+
[2e-3, 1, "exp"],
|
|
5434
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
5435
|
+
]
|
|
5436
|
+
}
|
|
5437
|
+
],
|
|
5438
|
+
falloff: DISTANCE_CURVES.art_scene,
|
|
5439
|
+
sources: ["sdk: bench probe, a 880 Hz ping through the art scene output stage"]
|
|
5440
|
+
},
|
|
5441
|
+
{
|
|
5442
|
+
id: "bench_hiss",
|
|
5443
|
+
bus: "ui",
|
|
5444
|
+
pan: true,
|
|
5445
|
+
duration: [0.3, 0.9],
|
|
5446
|
+
layers: [
|
|
5447
|
+
{
|
|
5448
|
+
gain: 0.4,
|
|
5449
|
+
source: { kind: "noise", offset: "random", offsetScale: 1.5, loop: true },
|
|
5450
|
+
filters: { mode: "serial", bank: [{ type: "highpass", frequency: { set: 3e3 }, q: 0.7 }] },
|
|
5451
|
+
envelope: [
|
|
5452
|
+
[0, 1e-4, "set", "fixed"],
|
|
5453
|
+
[2e-3, 1, "exp"],
|
|
5454
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
5455
|
+
]
|
|
5456
|
+
}
|
|
5457
|
+
],
|
|
5458
|
+
falloff: DISTANCE_CURVES.art_scene,
|
|
5459
|
+
sources: ["sdk: bench probe, a highpass hiss of random length"]
|
|
5460
|
+
}
|
|
5461
|
+
]
|
|
5212
5462
|
};
|
|
5213
5463
|
|
|
5464
|
+
// src/audio/recipes.ts
|
|
5465
|
+
var UNDEAD_VOICE_GROUP = "undead_voice";
|
|
5466
|
+
var voiced = { bus: "voices", group: UNDEAD_VOICE_GROUP };
|
|
5467
|
+
var p = (param) => ({ param });
|
|
5468
|
+
var SCREAM_HOARSE = {
|
|
5469
|
+
id: "scream_hoarse",
|
|
5470
|
+
bus: "voices",
|
|
5471
|
+
order: "scream",
|
|
5472
|
+
duration: [1, 1.4],
|
|
5473
|
+
layers: [
|
|
5474
|
+
{
|
|
5475
|
+
source: { kind: "noise", offset: "random" },
|
|
5476
|
+
filters: {
|
|
5477
|
+
mode: "parallel",
|
|
5478
|
+
bank: [
|
|
5479
|
+
{ type: "bandpass", q: 6, frequency: { from: 700 * 1.15, to: 700 * 0.8, curve: "linear", over: "duration" }, level: 1 },
|
|
5480
|
+
{ type: "bandpass", q: 8, frequency: { from: 1150 * 1.15, to: 1150 * 0.8, curve: "linear", over: "duration" }, level: 0.7 },
|
|
5481
|
+
{ type: "bandpass", q: 10, frequency: { from: 2600 * 1.15, to: 2600 * 0.8, curve: "linear", over: "duration" }, level: 0.35 }
|
|
5482
|
+
]
|
|
5483
|
+
},
|
|
5484
|
+
modulators: [{ target: "gain", wave: "square", rate: [31, 40], depth: 0.35 }],
|
|
5485
|
+
envelope: [
|
|
5486
|
+
[0, 0, "set"],
|
|
5487
|
+
[0.06, 0.9, "linear"],
|
|
5488
|
+
["0.6d", 0.9, "set"],
|
|
5489
|
+
["1d", 1e-3, "exp", "fixed"]
|
|
5490
|
+
]
|
|
5491
|
+
}
|
|
5492
|
+
],
|
|
5493
|
+
falloff: DISTANCE_CURVES.game_scream,
|
|
5494
|
+
sources: ["jogo:L62128-62142 grito"]
|
|
5495
|
+
};
|
|
5496
|
+
var groanLayer = (base) => ({
|
|
5497
|
+
source: {
|
|
5498
|
+
kind: "osc",
|
|
5499
|
+
wave: "sawtooth",
|
|
5500
|
+
frequency: typeof base === "number" ? { from: base, to: base * 0.7, curve: "linear", over: "duration" } : { from: base, to: { ...base, scale: 0.7 }, curve: "linear", over: "duration" }
|
|
5501
|
+
},
|
|
5502
|
+
filters: { mode: "serial", bank: [{ type: "bandpass", q: 3, frequency: { set: typeof base === "number" ? base * 3 : { ...base, scale: 3 } } }] },
|
|
5503
|
+
envelope: [
|
|
5504
|
+
[0, 0, "set"],
|
|
5505
|
+
[0.15, 0.25, "linear"],
|
|
5506
|
+
["1d", 1e-3, "exp", "fixed"]
|
|
5507
|
+
]
|
|
5508
|
+
});
|
|
5509
|
+
var GROAN = {
|
|
5510
|
+
id: "groan",
|
|
5511
|
+
...voiced,
|
|
5512
|
+
order: "groan",
|
|
5513
|
+
vars: { base: [95, 135], dur: [0.9, 1.5] },
|
|
5514
|
+
duration: p("dur"),
|
|
5515
|
+
layers: [groanLayer(p("base"))],
|
|
5516
|
+
falloff: DISTANCE_CURVES.game_voice,
|
|
5517
|
+
sources: ["jogo:L62143-62155 voz gemido"]
|
|
5518
|
+
};
|
|
5519
|
+
var RUNNER_GROAN = {
|
|
5520
|
+
id: "runner_groan",
|
|
5521
|
+
...voiced,
|
|
5522
|
+
order: "groan",
|
|
5523
|
+
vars: { dur: [0.9, 1.5] },
|
|
5524
|
+
duration: p("dur"),
|
|
5525
|
+
layers: [groanLayer(300)],
|
|
5526
|
+
falloff: DISTANCE_CURVES.game_voice,
|
|
5527
|
+
sources: ["jogo:L62143-62155 voz corredor"]
|
|
5528
|
+
};
|
|
5529
|
+
var scene = (id, layers, line, options = {}) => sceneRecipe(id, layers, line, options);
|
|
5530
|
+
var groan = (id, vars, voice, line) => scene(id, [sceneVoice(voice)], line, { vars, ...voiced });
|
|
5531
|
+
var GROAN_WALKER = groan("groan_walker", { f0: [72, 107], d: [0.9, 2], fA: [480, 680], fB: [1050, 1350] }, { f0: p("f0"), f1: 0, d: p("d"), fA: p("fA"), fB: p("fB"), noise: 0.35, vol: 0.65 }, "L1345 groan (walker)");
|
|
5532
|
+
var GROAN_BRUTE = groan("groan_brute", { f0: [48, 62], d: [0.9, 2], fA: [480, 680], fB: [1050, 1350] }, { f0: p("f0"), f1: 0, d: p("d"), fA: p("fA"), fB: p("fB"), noise: 0.35, vol: 0.65 }, "L1345 groan (brute)");
|
|
5533
|
+
var GROAN_RUNNER = groan("groan_runner", { f0: [160, 250], d: [0.45, 0.85] }, { f0: p("f0"), f1: 0, d: p("d"), fA: 950, fB: 2300, noise: 0.6, vol: 0.5, wave: "square" }, "L1345 groan (runner)");
|
|
5534
|
+
var SCREAM = scene(
|
|
5535
|
+
"scream",
|
|
5536
|
+
[
|
|
5537
|
+
sceneVoice({ f0: 520, f1: 880, d: 2.6, fA: 1800, fB: 3200, noise: 0.9, vol: 1.6 }),
|
|
5538
|
+
sceneVoice({ f0: 640, f1: 1020, d: 2.4, fA: 2400, fB: 3800, noise: 0.6, vol: 1.1, wave: "square" })
|
|
5539
|
+
],
|
|
5540
|
+
"L1347 scream",
|
|
5541
|
+
{ bus: "voices" }
|
|
5542
|
+
);
|
|
5543
|
+
var INHALE = scene("inhale", [sceneNoise({ type: "bandpass", f: 1400, q: 1.5, a: 0.6, d: 0.9, vol: 0.5 })], "L1348 inhale", { bus: "voices" });
|
|
5544
|
+
var LEAP = scene("leap", [sceneVoice({ f0: 200, f1: 330, d: 0.5, fA: 1100, fB: 2500, noise: 0.7, vol: 0.6, wave: "square" }), sceneNoise({ type: "bandpass", f: 600, f2: 1600, d: 0.5, vol: 0.4 })], "L1349 leap", { bus: "voices" });
|
|
5545
|
+
var GRAB = scene("grab", [sceneNoise({ type: "bandpass", f: 500, q: 1, d: 0.25, vol: 0.7 }), sceneTone({ wave: "sawtooth", f: 90, f2: 60, d: 0.4, vol: 0.4 })], "L1350 grab", { bus: "voices" });
|
|
5546
|
+
var BITE = scene(
|
|
5547
|
+
"bite",
|
|
5548
|
+
[
|
|
5549
|
+
sceneNoise({ f: 1400, d: 0.2, vol: 1.1 }),
|
|
5550
|
+
...[0, 1, 2, 3].map((k) => sceneNoise({ type: "highpass", f: 2500, d: 0.03, vol: 0.5, delay: 0.03 + k * 0.04 })),
|
|
5551
|
+
sceneTone({ wave: "sawtooth", f: 320, f2: 170, d: 0.5, vol: 0.35, delay: 0.05 })
|
|
5552
|
+
],
|
|
5553
|
+
"L1351 bite",
|
|
5554
|
+
{ bus: "voices" }
|
|
5555
|
+
);
|
|
5556
|
+
var HURT = scene("hurt", [sceneTone({ wave: "sawtooth", f: 150, f2: 95, d: 0.22, vol: 0.3 }), sceneNoise({ f: 600, d: 0.1, vol: 0.4 })], "L1352 hurt", { bus: "voices" });
|
|
5557
|
+
var FLESH = scene("flesh", [sceneNoise({ f: 650, d: 0.08, vol: 0.6 }), sceneTone({ f: 90, f2: 45, d: 0.07, vol: 0.5 })], "L1353 flesh");
|
|
5558
|
+
var FLESH_HEAD = scene("flesh_head", [sceneNoise({ f: 1100, d: 0.12, vol: 0.9 }), sceneTone({ f: 130, f2: 45, d: 0.07, vol: 0.5 })], "L1353 flesh (head)");
|
|
5559
|
+
var SEVER = scene(
|
|
5560
|
+
"sever",
|
|
5561
|
+
[sceneNoise({ type: "bandpass", f: 500, q: 0.8, d: 0.3, vol: 1 }), sceneNoise({ type: "highpass", f: 2400, d: 0.06, vol: 0.7, delay: 0.02 }), sceneTone({ f: 110, f2: 40, d: 0.15, vol: 0.6 })],
|
|
5562
|
+
"L1355 sever"
|
|
5563
|
+
);
|
|
5564
|
+
var GORE = scene(
|
|
5565
|
+
"gore",
|
|
5566
|
+
[
|
|
5567
|
+
sceneNoise({ f: 900, f2: 200, d: 0.4, vol: 1.1, wet: 0.3 }),
|
|
5568
|
+
...[0, 1, 2].map((k) => sceneNoise({ type: "bandpass", f: [400, 800], q: 2, d: 0.08, vol: 0.5, delay: 0.08 + k * 0.07 }))
|
|
5569
|
+
],
|
|
5570
|
+
"L1356 gore"
|
|
5571
|
+
);
|
|
5572
|
+
var CHARACTER_SOUNDS = [
|
|
5573
|
+
SCREAM_HOARSE,
|
|
5574
|
+
GROAN,
|
|
5575
|
+
RUNNER_GROAN,
|
|
5576
|
+
GROAN_WALKER,
|
|
5577
|
+
GROAN_BRUTE,
|
|
5578
|
+
GROAN_RUNNER,
|
|
5579
|
+
SCREAM,
|
|
5580
|
+
INHALE,
|
|
5581
|
+
LEAP,
|
|
5582
|
+
GRAB,
|
|
5583
|
+
BITE,
|
|
5584
|
+
HURT,
|
|
5585
|
+
FLESH,
|
|
5586
|
+
FLESH_HEAD,
|
|
5587
|
+
SEVER,
|
|
5588
|
+
GORE
|
|
5589
|
+
];
|
|
5590
|
+
var CHARACTER_SOUND_BANK = { id: "characters_three", sounds: CHARACTER_SOUNDS };
|
|
5591
|
+
|
|
5592
|
+
// src/audio/voices.json
|
|
5593
|
+
var voices_default = {
|
|
5594
|
+
sources: [
|
|
5595
|
+
"cena:L1345 groan(z): the Brutamonte has its own, a chase speed above 3.4 is a runner's, every other body groans like a walker",
|
|
5596
|
+
"cena:L1238, L1248, L1249 the scream and the inhale belong to the Gritador, the leap to the Saltador",
|
|
5597
|
+
"cena:L1226 the groan when a body wakes (FEIGN to CHASE) and the game L67275/L67328 voz('corredor') when one notices the player",
|
|
5598
|
+
"jogo:L66986 the groan of the game: 'corredor' for the runner category, 'gemido' for the rest; jogo:L66989 screamAt plays 'grito'",
|
|
5599
|
+
"types.json: the voice line of each Bestiario type"
|
|
5600
|
+
],
|
|
5601
|
+
types: {
|
|
5602
|
+
walker: { origin: "team", groan: "groan_walker", gameGroan: "groan" },
|
|
5603
|
+
runner: { origin: "team", groan: "groan_runner", gameGroan: "runner_groan" },
|
|
5604
|
+
crawler: { origin: "rule", groan: "groan_walker", gameGroan: "groan" },
|
|
5605
|
+
brute: { origin: "team", groan: "groan_brute", gameGroan: "groan" },
|
|
5606
|
+
sniffer: {
|
|
5607
|
+
origin: "extra",
|
|
5608
|
+
groan: "groan_runner",
|
|
5609
|
+
gameGroan: "groan",
|
|
5610
|
+
idle: [{ sound: "inhale" }, { sound: "groan_runner", delay: 0.6 }]
|
|
5611
|
+
},
|
|
5612
|
+
leaper: { origin: "team", groan: "groan_runner", gameGroan: "groan", special: [{ sound: "leap" }] },
|
|
5613
|
+
bloater: { origin: "rule", groan: "groan_walker", gameGroan: "groan" },
|
|
5614
|
+
stalker: { origin: "rule", groan: "groan_runner", gameGroan: "groan", idle: [] },
|
|
5615
|
+
blind: { origin: "rule", groan: "groan_walker", gameGroan: "groan" },
|
|
5616
|
+
screamer: {
|
|
5617
|
+
origin: "team",
|
|
5618
|
+
groan: "groan_walker",
|
|
5619
|
+
gameGroan: "groan",
|
|
5620
|
+
special: [{ sound: "inhale" }, { sound: "scream", delay: 1.5 }],
|
|
5621
|
+
gameSpecial: [{ sound: "scream_hoarse" }]
|
|
5622
|
+
},
|
|
5623
|
+
charred: { origin: "rule", groan: "groan_walker", gameGroan: "groan" },
|
|
5624
|
+
drowned: { origin: "rule", groan: "groan_walker", gameGroan: "groan" },
|
|
5625
|
+
devourer: {
|
|
5626
|
+
origin: "extra",
|
|
5627
|
+
groan: "groan_walker",
|
|
5628
|
+
gameGroan: "groan",
|
|
5629
|
+
idle: [{ sound: "groan_walker" }, { sound: "bite", delay: 0.4 }]
|
|
5630
|
+
}
|
|
5631
|
+
}
|
|
5632
|
+
};
|
|
5633
|
+
|
|
5634
|
+
// src/audio/sound.ts
|
|
5635
|
+
var DATA = voices_default;
|
|
5636
|
+
var UNDEAD_VOICES = DATA.types;
|
|
5637
|
+
var UNDEAD_VOICE_SOURCES = DATA.sources;
|
|
5638
|
+
var BODY_SOUNDS = {
|
|
5639
|
+
art_scene: {
|
|
5640
|
+
wound: { sound: "flesh", head: "flesh_head" },
|
|
5641
|
+
severed: { sound: "sever" },
|
|
5642
|
+
destroyed: { sound: "gore" },
|
|
5643
|
+
split: { sound: "gore" }
|
|
5644
|
+
},
|
|
5645
|
+
game: {
|
|
5646
|
+
wound: { sound: "sfx_flesh" }
|
|
5647
|
+
}
|
|
5648
|
+
};
|
|
5649
|
+
var PLAYER_SOUNDS = { grab: "grab", bite: "bite", hurt: "hurt" };
|
|
5650
|
+
var HEAD_PARTS = /* @__PURE__ */ new Set(["head", "jaw"]);
|
|
5651
|
+
function createCharacterSound(sink, options = {}) {
|
|
5652
|
+
sink.register?.(CHARACTER_SOUND_BANK);
|
|
5653
|
+
sink.register?.(GAME_SFX_BANK);
|
|
5654
|
+
const style = options.style ?? "art_scene";
|
|
5655
|
+
const voices = { ...UNDEAD_VOICES, ...options.voices };
|
|
5656
|
+
const rules = { ...BODY_SOUNDS.art_scene, ...style === "game" ? BODY_SOUNDS.game : {}, ...options.body };
|
|
5657
|
+
const queue = [];
|
|
5658
|
+
const voiceOf = (typeId) => {
|
|
5659
|
+
const own = voices[typeId];
|
|
5660
|
+
if (own === null) return void 0;
|
|
5661
|
+
return own ?? (options.fallbackType ? voices[options.fallbackType] ?? void 0 : void 0);
|
|
5662
|
+
};
|
|
5663
|
+
const stepsOf = (typeId, moment) => {
|
|
5664
|
+
const voice = voiceOf(typeId);
|
|
5665
|
+
if (!voice) return [];
|
|
5666
|
+
const groan2 = style === "game" ? voice.gameGroan : voice.groan;
|
|
5667
|
+
if (moment === "special") return (style === "game" ? voice.gameSpecial ?? voice.special : voice.special) ?? [];
|
|
5668
|
+
if (moment === "alert") return voice.alert ?? [{ sound: style === "game" ? "runner_groan" : groan2 }];
|
|
5669
|
+
return voice.idle ?? [{ sound: groan2 }];
|
|
5670
|
+
};
|
|
5671
|
+
const start = (sound, at, volume) => void sink.play({ sound, position: at, volume });
|
|
5672
|
+
return {
|
|
5673
|
+
stepsOf,
|
|
5674
|
+
voice(typeId, moment, position, volume = 1) {
|
|
5675
|
+
const steps = stepsOf(typeId, moment);
|
|
5676
|
+
for (const step of steps) {
|
|
5677
|
+
if (step.delay && step.delay > 0) queue.push({ sound: step.sound, at: position, volume, wait: step.delay });
|
|
5678
|
+
else start(step.sound, position, volume);
|
|
5679
|
+
}
|
|
5680
|
+
return steps.length;
|
|
5681
|
+
},
|
|
5682
|
+
body(event, position, volume = 1) {
|
|
5683
|
+
if (event.type !== "body") return false;
|
|
5684
|
+
const rule = rules[event.change];
|
|
5685
|
+
if (!rule) return false;
|
|
5686
|
+
const head = event.part !== void 0 && HEAD_PARTS.has(event.part);
|
|
5687
|
+
start(head && rule.head ? rule.head : rule.sound, position, volume);
|
|
5688
|
+
return true;
|
|
5689
|
+
},
|
|
5690
|
+
player: (kind, volume = 1) => void sink.play({ sound: PLAYER_SOUNDS[kind], volume }),
|
|
5691
|
+
update(dt) {
|
|
5692
|
+
for (let i = queue.length - 1; i >= 0; i--) {
|
|
5693
|
+
const item = queue[i];
|
|
5694
|
+
item.wait -= dt;
|
|
5695
|
+
if (item.wait <= 0) {
|
|
5696
|
+
queue.splice(i, 1);
|
|
5697
|
+
start(item.sound, item.at, item.volume);
|
|
5698
|
+
}
|
|
5699
|
+
}
|
|
5700
|
+
},
|
|
5701
|
+
pending: () => queue.length,
|
|
5702
|
+
dispose() {
|
|
5703
|
+
queue.length = 0;
|
|
5704
|
+
}
|
|
5705
|
+
};
|
|
5706
|
+
}
|
|
5707
|
+
|
|
5214
5708
|
// src/test-area/crowd.ts
|
|
5215
5709
|
var FIELD = { x0: 12, x1: 30, z0: -16, z1: 16 };
|
|
5216
5710
|
var STRIDE = 1;
|
|
@@ -5475,7 +5969,7 @@ var GameCharactersThree = (() => {
|
|
|
5475
5969
|
hit_preset: "What the Fire hit button does to the body you look at",
|
|
5476
5970
|
protection: "Worn by the bodies created from now on"
|
|
5477
5971
|
},
|
|
5478
|
-
actions: { heal: "Heal the aimed body", kill: "Kill the aimed body", infect: "Bite the aimed person (accelerated)", spawn_100: "Spawn 100 in the crowd", spawn_1000: "Spawn 1000 in the crowd", fire_preset: "Fire the hit" },
|
|
5972
|
+
actions: { heal: "Heal the aimed body", kill: "Kill the aimed body", infect: "Bite the aimed person (accelerated)", spawn_100: "Spawn 100 in the crowd", spawn_1000: "Spawn 1000 in the crowd", fire_preset: "Fire the hit", voice: "Make the aimed zombie speak (groan, by the moment)", special_call: "Make the aimed zombie use its call (scream, leap)" },
|
|
5479
5973
|
options: {
|
|
5480
5974
|
penetration: { physical: "Physical", "team-game": "Team game" },
|
|
5481
5975
|
death_rule: { "vitality-or-head": "Vitality or head", "head-only": "Head only" },
|
|
@@ -5520,7 +6014,7 @@ var GameCharactersThree = (() => {
|
|
|
5520
6014
|
hit_preset: "O que o bot\xE3o Disparar faz no corpo para o qual voc\xEA olha",
|
|
5521
6015
|
protection: "Vestida pelos corpos criados daqui em diante"
|
|
5522
6016
|
},
|
|
5523
|
-
actions: { heal: "Curar o corpo mirado", kill: "Matar o corpo mirado", infect: "Morder a pessoa mirada (acelerado)", spawn_100: "P\xF4r 100 na multid\xE3o", spawn_1000: "P\xF4r 1000 na multid\xE3o", fire_preset: "Disparar o golpe" },
|
|
6017
|
+
actions: { heal: "Curar o corpo mirado", kill: "Matar o corpo mirado", infect: "Morder a pessoa mirada (acelerado)", spawn_100: "P\xF4r 100 na multid\xE3o", spawn_1000: "P\xF4r 1000 na multid\xE3o", fire_preset: "Disparar o golpe", voice: "Fazer o zumbi mirado falar (gemido, pelo momento)", special_call: "Fazer o zumbi mirado usar o chamado (grito, salto)" },
|
|
5524
6018
|
options: {
|
|
5525
6019
|
penetration: { physical: "F\xEDsica", "team-game": "Do jogo" },
|
|
5526
6020
|
death_rule: { "vitality-or-head": "Vitalidade ou cabe\xE7a", "head-only": "S\xF3 a cabe\xE7a" },
|
|
@@ -5575,6 +6069,7 @@ var GameCharactersThree = (() => {
|
|
|
5575
6069
|
let best = null;
|
|
5576
6070
|
let people = null;
|
|
5577
6071
|
let wounds = null;
|
|
6072
|
+
let sound = null;
|
|
5578
6073
|
let crowd = null;
|
|
5579
6074
|
let selected = null;
|
|
5580
6075
|
let time = 0;
|
|
@@ -5667,6 +6162,9 @@ var GameCharactersThree = (() => {
|
|
|
5667
6162
|
if (Math.abs(scale - 1) > 0.01) object.scale.setScalar(scale);
|
|
5668
6163
|
const entry = { id, kind: made.kind, cardId: made.cardId, root: object, body: woundBodyOf(object), eyes: three ? findEyes(three, object) : null, built: made.built, character, walk: 0, tilt: 0 };
|
|
5669
6164
|
entry.character = wrap(entry, character);
|
|
6165
|
+
const age = made.kind === "zombie" ? undead?.traitsOf(character)?.age : void 0;
|
|
6166
|
+
const blood = age !== void 0 ? options.bloodOf?.(age) : void 0;
|
|
6167
|
+
if (entry.body && blood) entry.body.blood = blood;
|
|
5670
6168
|
entries.set(id, entry);
|
|
5671
6169
|
selected ?? (selected = entry);
|
|
5672
6170
|
trackEntry(entry);
|
|
@@ -5749,8 +6247,8 @@ var GameCharactersThree = (() => {
|
|
|
5749
6247
|
const selectedOrFirst = () => selected ?? entries.values().next().value ?? null;
|
|
5750
6248
|
const fireOn = (entry) => {
|
|
5751
6249
|
const preset2 = hitPresetOf(settings.hit);
|
|
5752
|
-
const
|
|
5753
|
-
entry.character.hit(hitFor(preset2, [
|
|
6250
|
+
const p2 = entry.root.position;
|
|
6251
|
+
entry.character.hit(hitFor(preset2, [p2.x, p2.y, p2.z], 1.3, kit.calibers));
|
|
5754
6252
|
};
|
|
5755
6253
|
const ensureCrowd = () => {
|
|
5756
6254
|
if (crowd) return crowd;
|
|
@@ -5785,7 +6283,14 @@ var GameCharactersThree = (() => {
|
|
|
5785
6283
|
if (infection.reanimated) target.character = wrap(target, undead.turn(target.character));
|
|
5786
6284
|
}
|
|
5787
6285
|
} else if (change.id === "fire_preset" && target) fireOn(target);
|
|
5788
|
-
else if (change.id === "
|
|
6286
|
+
else if ((change.id === "voice" || change.id === "special_call") && sound) {
|
|
6287
|
+
const speaker = target?.kind === "zombie" ? target : [...entries.values()].find((entry) => entry.kind === "zombie");
|
|
6288
|
+
if (speaker) {
|
|
6289
|
+
const at = speaker.root.getWorldPosition(new host.THREE.Vector3());
|
|
6290
|
+
const hurried = settings.moment === "alert" || settings.moment === "chase" || settings.moment === "sprint";
|
|
6291
|
+
sound.voice(speaker.cardId, change.id === "special_call" ? "special" : hurried ? "alert" : "idle", [at.x, at.y + 1.5, at.z]);
|
|
6292
|
+
}
|
|
6293
|
+
} else if (change.id === "spawn_100" || change.id === "spawn_1000") {
|
|
5789
6294
|
ensureBuilders(host?.THREE ?? three);
|
|
5790
6295
|
ensureCrowd().spawn(change.id === "spawn_100" ? 100 : 1e3);
|
|
5791
6296
|
}
|
|
@@ -5890,6 +6395,8 @@ var GameCharactersThree = (() => {
|
|
|
5890
6395
|
withHint(choice("hit_preset", HIT_PRESETS.map((preset2) => preset2.id), "9x19"), text.hints.hit_preset),
|
|
5891
6396
|
withHint(choice("protection", ["none", "vest_police", "vest_military", "helmet_combat", "turnout_gear", "vest_helmet"], "none"), text.hints.protection),
|
|
5892
6397
|
{ kind: "action", id: "fire_preset", name: text.actions.fire_preset },
|
|
6398
|
+
{ kind: "action", id: "voice", name: text.actions.voice },
|
|
6399
|
+
{ kind: "action", id: "special_call", name: text.actions.special_call },
|
|
5893
6400
|
{ kind: "action", id: "heal", name: text.actions.heal },
|
|
5894
6401
|
{ kind: "action", id: "kill", name: text.actions.kill },
|
|
5895
6402
|
{ kind: "action", id: "infect", name: text.actions.infect },
|
|
@@ -5917,9 +6424,10 @@ var GameCharactersThree = (() => {
|
|
|
5917
6424
|
attach(lent) {
|
|
5918
6425
|
host = lent;
|
|
5919
6426
|
ensureBuilders(lent.THREE);
|
|
5920
|
-
const
|
|
5921
|
-
const bridge = options.fluids ? createFluidsBridge({ sink: options.fluids }) : void 0;
|
|
5922
|
-
|
|
6427
|
+
const scene2 = lent.scene;
|
|
6428
|
+
const bridge = options.fluids ? createFluidsBridge({ sink: options.fluids, ...options.film ? { film: options.film } : {} }) : void 0;
|
|
6429
|
+
sound = lent.audio && options.sound !== false ? createCharacterSound(lent.audio, options.sound ?? {}) : null;
|
|
6430
|
+
wounds = createWounds(lent.THREE, { random, scene: scene2, groundAt: (x, z) => lent.groundAt(x, z), ...bridge ? { bridge } : {}, ...sound ? { sound } : {} });
|
|
5923
6431
|
for (const entry of entries.values()) trackEntry(entry);
|
|
5924
6432
|
const stopChange = lent.bench?.onChange(onChange);
|
|
5925
6433
|
const stopFrame = lent.onFrame((dt) => {
|
|
@@ -5932,6 +6440,7 @@ var GameCharactersThree = (() => {
|
|
|
5932
6440
|
animate(entry, dt);
|
|
5933
6441
|
}
|
|
5934
6442
|
wounds?.update(dt);
|
|
6443
|
+
sound?.update(dt);
|
|
5935
6444
|
crowd?.update(dt, lent.camera);
|
|
5936
6445
|
});
|
|
5937
6446
|
return () => {
|
|
@@ -5940,6 +6449,8 @@ var GameCharactersThree = (() => {
|
|
|
5940
6449
|
clearOverlays();
|
|
5941
6450
|
wounds?.dispose();
|
|
5942
6451
|
wounds = null;
|
|
6452
|
+
sound?.dispose();
|
|
6453
|
+
sound = null;
|
|
5943
6454
|
if (crowd) {
|
|
5944
6455
|
crowd.group.parent?.remove(crowd.group);
|
|
5945
6456
|
crowd = null;
|