@adatechnology/game-characters-three 0.1.3 → 0.2.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 +5 -0
- package/dist/index.d.ts +171 -21
- package/dist/index.global.js +557 -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,
|
|
@@ -2864,7 +2873,7 @@ var GameCharactersThree = (() => {
|
|
|
2864
2873
|
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
2874
|
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
2875
|
const torsoGeo = (sx, sz, fem) => {
|
|
2867
|
-
const g = new THREE.LatheGeometry(new THREE.SplineCurve((fem ? TORSO_F : TORSO_P).map((
|
|
2876
|
+
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
2877
|
g.scale(1.12 * (sx || 1), 1, 0.64 * (sz || 1));
|
|
2869
2878
|
return g;
|
|
2870
2879
|
};
|
|
@@ -2952,34 +2961,34 @@ var GameCharactersThree = (() => {
|
|
|
2952
2961
|
const skinFinal = P.char ? 1840658 : P.wet ? col(skinC, 8032160, 0.55) : skinC;
|
|
2953
2962
|
const skinM = M(skinFinal);
|
|
2954
2963
|
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 = (
|
|
2964
|
+
const add = (p2, geo, m, x, y, z2, rx, ry, rz) => {
|
|
2956
2965
|
const o = new THREE.Mesh(geo, m);
|
|
2957
2966
|
o.position.set(x || 0, y || 0, z2 || 0);
|
|
2958
2967
|
if (rx || ry || rz) o.rotation.set(rx || 0, ry || 0, rz || 0);
|
|
2959
|
-
|
|
2968
|
+
p2.add(o);
|
|
2960
2969
|
return o;
|
|
2961
2970
|
};
|
|
2962
|
-
const ball = (
|
|
2971
|
+
const ball = (p2, r, m, x, y, z2) => add(p2, SPH(r, SEG, 12), m, x, y, z2);
|
|
2963
2972
|
topM_ref = topM;
|
|
2964
2973
|
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 = (
|
|
2974
|
+
const flat = (p2, x, y, zz, sx, sy, c) => {
|
|
2966
2975
|
const m = new THREE.Mesh(BLOB, skM(c));
|
|
2967
2976
|
m.rotation.set(PI / 2, 0, BR() * 6.28);
|
|
2968
2977
|
m.scale.set(sx, 1, sy);
|
|
2969
2978
|
m.position.set(x, y, zz);
|
|
2970
|
-
|
|
2979
|
+
p2.add(m);
|
|
2971
2980
|
return m;
|
|
2972
2981
|
};
|
|
2973
|
-
const splat = (
|
|
2974
|
-
const a = flat(
|
|
2982
|
+
const splat = (p2, x, y, zz, r, c, n) => {
|
|
2983
|
+
const a = flat(p2, x, y, zz + 4e-3, r, r * (0.7 + BR() * 0.5), c);
|
|
2975
2984
|
for (let k = 0; k < (n || 0); k++) {
|
|
2976
2985
|
const an = BR() * 6.28, dd = r * (1.2 + BR() * 0.9), q = r * (0.12 + BR() * 0.18);
|
|
2977
|
-
flat(
|
|
2986
|
+
flat(p2, x + Math.cos(an) * dd, y + Math.sin(an) * dd, zz + 4e-3, q, q * 0.7, c);
|
|
2978
2987
|
}
|
|
2979
|
-
if (n) run(
|
|
2988
|
+
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
2989
|
return a;
|
|
2981
2990
|
};
|
|
2982
|
-
const run = (
|
|
2991
|
+
const run = (p2, x, y0, y1, z0, z1, c, w) => {
|
|
2983
2992
|
const L = y0 - y1, sh = new THREE.Shape();
|
|
2984
2993
|
sh.moveTo(-w / 2, 0);
|
|
2985
2994
|
sh.lineTo(w / 2, 0);
|
|
@@ -2989,30 +2998,30 @@ var GameCharactersThree = (() => {
|
|
|
2989
2998
|
const g = new THREE.ShapeGeometry(sh), m = new THREE.Mesh(g, skM(c));
|
|
2990
2999
|
m.position.set(x, y0, z0);
|
|
2991
3000
|
m.rotation.x = -Math.atan2(z0 - z1, L);
|
|
2992
|
-
|
|
3001
|
+
p2.add(m);
|
|
2993
3002
|
const bl = new THREE.Mesh(SPH(w * 0.42, 10, 8), skM(c));
|
|
2994
3003
|
bl.scale.set(1, 1.35, 0.5);
|
|
2995
3004
|
bl.position.set(x + w * 0.03, y1, z1);
|
|
2996
|
-
|
|
3005
|
+
p2.add(bl);
|
|
2997
3006
|
return bl;
|
|
2998
3007
|
};
|
|
2999
|
-
const stump = (
|
|
3000
|
-
const st = ball(
|
|
3008
|
+
const stump = (p2, r, y, up) => {
|
|
3009
|
+
const st = ball(p2, r * 1.02, red, 0, y, 0);
|
|
3001
3010
|
st.scale.set(1, 0.35, 1);
|
|
3002
|
-
add(
|
|
3011
|
+
add(p2, CYL(r * 0.32, r * 0.36, 0.07, 10), M(15261900), 0, y + (up ? 0.04 : -0.04), 0);
|
|
3003
3012
|
};
|
|
3004
|
-
const ring = (
|
|
3005
|
-
const o = add(
|
|
3013
|
+
const ring = (p2, r, h, m, y, sx, sz) => {
|
|
3014
|
+
const o = add(p2, CYL(r, r, h, 24), m, 0, y, 0);
|
|
3006
3015
|
o.scale.set(sx || 1.12, 1, sz || 0.7);
|
|
3007
3016
|
return o;
|
|
3008
3017
|
};
|
|
3009
3018
|
const root = new THREE.Group(), fig = new THREE.Group();
|
|
3010
|
-
const drip = (
|
|
3019
|
+
const drip = (p2, x, y, zz, kind, every) => {
|
|
3011
3020
|
if (d >= 3 && kind !== "bile") return;
|
|
3012
3021
|
const o = new THREE.Object3D();
|
|
3013
3022
|
o.position.set(x, y, zz);
|
|
3014
3023
|
o.userData.drip = { kind: kind || (d < 1 ? "blood" : "old"), every: every || (d < 1 ? 1.2 : 2.4) };
|
|
3015
|
-
|
|
3024
|
+
p2.add(o);
|
|
3016
3025
|
};
|
|
3017
3026
|
fig.scale.set(P.s * P.bulk, P.s, P.s * Math.min(1.15, P.bulk));
|
|
3018
3027
|
fig.position.y = P.drop * P.s;
|
|
@@ -4182,7 +4191,7 @@ var GameCharactersThree = (() => {
|
|
|
4182
4191
|
}
|
|
4183
4192
|
function torsoGeo(fem) {
|
|
4184
4193
|
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((
|
|
4194
|
+
const pts = new THREE.SplineCurve(P.map((p2) => new THREE.Vector2(p2[0], p2[1]))).getPoints(30);
|
|
4186
4195
|
const g = new THREE.LatheGeometry(pts, 24);
|
|
4187
4196
|
g.scale(1.12, 1, 0.64);
|
|
4188
4197
|
return g;
|
|
@@ -4537,15 +4546,15 @@ var GameCharactersThree = (() => {
|
|
|
4537
4546
|
}
|
|
4538
4547
|
const MOVES_IDLE = MOVES.idle;
|
|
4539
4548
|
function pose(c, z, W, t) {
|
|
4540
|
-
const
|
|
4541
|
-
const breathe = reduce ? 0 : Math.sin(
|
|
4549
|
+
const p2 = c.ph + t, freq = z ? 3.4 : 5.6, ph = t * freq + c.ph;
|
|
4550
|
+
const breathe = reduce ? 0 : Math.sin(p2 * 1.6) * 0.012;
|
|
4542
4551
|
c.upper.scale.y = 1 + breathe;
|
|
4543
4552
|
const hunch = c.hunch + (z ? 0.38 : 0) + W * 0.05;
|
|
4544
4553
|
c.upper.rotation.x = hunch;
|
|
4545
4554
|
c.upper.rotation.y = W * Math.sin(ph) * 0.1;
|
|
4546
4555
|
c.upper.rotation.z = z ? Math.sin(ph * 0.5) * 0.06 * W + 0.05 : 0;
|
|
4547
4556
|
c.fig.position.y = -W * Math.abs(Math.sin(ph)) * 0.035;
|
|
4548
|
-
c.headG.rotation.y = reduce ? 0 : Math.sin(
|
|
4557
|
+
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
4558
|
c.headG.rotation.x = -hunch * 0.6 + (z ? 0.15 : 0);
|
|
4550
4559
|
c.headG.rotation.z = z ? 0.22 : 0;
|
|
4551
4560
|
c.legs.forEach((l, k) => {
|
|
@@ -4558,7 +4567,7 @@ var GameCharactersThree = (() => {
|
|
|
4558
4567
|
const raise = z ? 1 : 0;
|
|
4559
4568
|
const base = a.hold ? -0.2 : 0;
|
|
4560
4569
|
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(
|
|
4570
|
+
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
4571
|
a.g.rotation.z = a.s * (0.07 + (z ? 0.1 : 0)) + (a.grip && !z ? -a.s * 0.35 : 0);
|
|
4563
4572
|
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
4573
|
if (a.fingers) {
|
|
@@ -4583,16 +4592,16 @@ var GameCharactersThree = (() => {
|
|
|
4583
4592
|
c.mouth.visible = true;
|
|
4584
4593
|
c.bags.material.opacity = 0.9;
|
|
4585
4594
|
}
|
|
4586
|
-
function buildPerson(
|
|
4595
|
+
function buildPerson(p2, zed) {
|
|
4587
4596
|
const root = new THREE.Group(), chars = [];
|
|
4588
|
-
if (
|
|
4589
|
-
const c = build(
|
|
4597
|
+
if (p2.b) {
|
|
4598
|
+
const c = build(p2.b, 0);
|
|
4590
4599
|
chars.push(c);
|
|
4591
4600
|
root.add(c.root);
|
|
4592
|
-
if (zed && !
|
|
4593
|
-
c.z = zed && !
|
|
4601
|
+
if (zed && !p2.kid) zombify(c, p2.zcat);
|
|
4602
|
+
c.z = zed && !p2.kid;
|
|
4594
4603
|
}
|
|
4595
|
-
(
|
|
4604
|
+
(p2.kids || []).forEach((k) => {
|
|
4596
4605
|
const c = build(k, 0);
|
|
4597
4606
|
c.root.position.x = k.x;
|
|
4598
4607
|
c.root.rotation.y = -k.x * 0.4;
|
|
@@ -4850,11 +4859,11 @@ var GameCharactersThree = (() => {
|
|
|
4850
4859
|
};
|
|
4851
4860
|
return {
|
|
4852
4861
|
pieces,
|
|
4853
|
-
launch(source,
|
|
4862
|
+
launch(source, scene2, direction, dress, tag) {
|
|
4854
4863
|
source.updateWorldMatrix(true, true);
|
|
4855
4864
|
const clone = source.clone(true);
|
|
4856
4865
|
source.matrixWorld.decompose(clone.position, clone.quaternion, clone.scale);
|
|
4857
|
-
|
|
4866
|
+
scene2.add(clone);
|
|
4858
4867
|
dress?.(clone);
|
|
4859
4868
|
return add(
|
|
4860
4869
|
clone,
|
|
@@ -5003,7 +5012,7 @@ var GameCharactersThree = (() => {
|
|
|
5003
5012
|
// src/wounds/wounds.ts
|
|
5004
5013
|
var worldPosition = (three, object) => object.getWorldPosition(new three.Vector3());
|
|
5005
5014
|
var createWounds = (three, options) => {
|
|
5006
|
-
const { random, scene, bridge } = options;
|
|
5015
|
+
const { random, scene: scene2, bridge, sound } = options;
|
|
5007
5016
|
const materials = options.materials ?? createWoundMaterials(three);
|
|
5008
5017
|
const flying = createFlyingPieces(three, { random, ...options.groundAt ? { groundAt: options.groundAt } : {}, ...options.maxPieces ? { max: options.maxPieces } : {} });
|
|
5009
5018
|
const states = /* @__PURE__ */ new Map();
|
|
@@ -5012,9 +5021,9 @@ var GameCharactersThree = (() => {
|
|
|
5012
5021
|
if (!found) throw new Error("game-characters-three: this body is not tracked by the wounds (call `track` first)");
|
|
5013
5022
|
return found;
|
|
5014
5023
|
};
|
|
5015
|
-
const burstBlood = (change, object) => {
|
|
5024
|
+
const burstBlood = (state, change, object, direction) => {
|
|
5016
5025
|
const point = worldPosition(three, object);
|
|
5017
|
-
bridge?.burst(change, [point.x, point.y, point.z]);
|
|
5026
|
+
bridge?.burst(change, [point.x, point.y, point.z], state.body.blood, direction ? [direction.x, direction.y, direction.z] : void 0);
|
|
5018
5027
|
};
|
|
5019
5028
|
const sideOf2 = (object, body) => new three.Vector3(object.position.x >= 0 ? 1 : -1, 0, 0).applyQuaternion(body.root.quaternion);
|
|
5020
5029
|
const hideBelow = (state, id) => {
|
|
@@ -5029,7 +5038,7 @@ var GameCharactersThree = (() => {
|
|
|
5029
5038
|
}
|
|
5030
5039
|
const { node, radius, flip } = target;
|
|
5031
5040
|
const direction = sideOf2(node, state.body);
|
|
5032
|
-
const fell = flying.launch(node,
|
|
5041
|
+
const fell = flying.launch(node, scene2, direction, (clone) => {
|
|
5033
5042
|
makeCut(three, materials, random, clone, radius, true);
|
|
5034
5043
|
}, id);
|
|
5035
5044
|
void fell;
|
|
@@ -5043,7 +5052,7 @@ var GameCharactersThree = (() => {
|
|
|
5043
5052
|
for (let o = pendulum.node; o; o = o.parent) if (!o.visible) shown = false;
|
|
5044
5053
|
if (!shown) state.pendulums.splice(i, 1);
|
|
5045
5054
|
}
|
|
5046
|
-
burstBlood("severed", node);
|
|
5055
|
+
burstBlood(state, "severed", node, direction);
|
|
5047
5056
|
if (id === "head") state.dead = true;
|
|
5048
5057
|
};
|
|
5049
5058
|
const destroy = (state, id, direction) => {
|
|
@@ -5052,14 +5061,14 @@ var GameCharactersThree = (() => {
|
|
|
5052
5061
|
const { node, radius, flip } = target;
|
|
5053
5062
|
const box = new three.Box3().setFromObject(node);
|
|
5054
5063
|
explodeChunks(three, materials, random, box, direction, (chunk, velocity, spin) => {
|
|
5055
|
-
|
|
5064
|
+
scene2.add(chunk);
|
|
5056
5065
|
flying.throwObject(chunk, velocity, spin, id);
|
|
5057
5066
|
});
|
|
5058
5067
|
node.visible = false;
|
|
5059
5068
|
makeStump(three, materials, random, node.parent, node.position, radius, flip);
|
|
5060
5069
|
state.gone.add(id);
|
|
5061
5070
|
hideBelow(state, id);
|
|
5062
|
-
burstBlood("destroyed", node);
|
|
5071
|
+
burstBlood(state, "destroyed", node, direction);
|
|
5063
5072
|
if (id === "head") state.dead = true;
|
|
5064
5073
|
};
|
|
5065
5074
|
const breakBone = (state, id) => {
|
|
@@ -5079,7 +5088,7 @@ var GameCharactersThree = (() => {
|
|
|
5079
5088
|
const split2 = (state, direction) => {
|
|
5080
5089
|
const upper = state.body.rig.upper;
|
|
5081
5090
|
if (!upper.visible) return;
|
|
5082
|
-
flying.launch(upper,
|
|
5091
|
+
flying.launch(upper, scene2, direction, (clone) => {
|
|
5083
5092
|
makeCut(three, materials, random, clone, 0.16, false);
|
|
5084
5093
|
}, "torso");
|
|
5085
5094
|
upper.visible = false;
|
|
@@ -5087,7 +5096,7 @@ var GameCharactersThree = (() => {
|
|
|
5087
5096
|
for (const id of ["torso", "neck", "head", "jaw", "upperArmL", "upperArmR", "forearmL", "forearmR", "handL", "handR"]) state.gone.add(id);
|
|
5088
5097
|
state.pendulums.length = 0;
|
|
5089
5098
|
state.dead = true;
|
|
5090
|
-
burstBlood("split", upper);
|
|
5099
|
+
burstBlood(state, "split", upper, direction);
|
|
5091
5100
|
};
|
|
5092
5101
|
const direction3 = (v, fallback) => v ? new three.Vector3(v[0], v[1], v[2]).normalize() : fallback;
|
|
5093
5102
|
return {
|
|
@@ -5121,6 +5130,10 @@ var GameCharactersThree = (() => {
|
|
|
5121
5130
|
}
|
|
5122
5131
|
if (event.type !== "body") return;
|
|
5123
5132
|
const id = event.part;
|
|
5133
|
+
if (sound) {
|
|
5134
|
+
const heard = worldPosition(three, (id ? body.nodes[id]?.node : void 0) ?? body.root);
|
|
5135
|
+
sound.body(event, [heard.x, heard.y, heard.z]);
|
|
5136
|
+
}
|
|
5124
5137
|
const fallback = new three.Vector3(0, 0.2, 1);
|
|
5125
5138
|
const direction = direction3(event.exit, fallback);
|
|
5126
5139
|
switch (event.change) {
|
|
@@ -5147,8 +5160,10 @@ var GameCharactersThree = (() => {
|
|
|
5147
5160
|
break;
|
|
5148
5161
|
case "wound": {
|
|
5149
5162
|
const target = id ? body.nodes[id] : void 0;
|
|
5163
|
+
const at = worldPosition(three, target?.node ?? body.root);
|
|
5164
|
+
bridge?.wound([at.x, at.y, at.z], body.blood, event.exit ? [direction.x, direction.y, direction.z] : void 0);
|
|
5150
5165
|
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
|
-
|
|
5166
|
+
scene2.add(chunk);
|
|
5152
5167
|
flying.throwObject(chunk, velocity, spin, id);
|
|
5153
5168
|
});
|
|
5154
5169
|
break;
|
|
@@ -5194,8 +5209,28 @@ var GameCharactersThree = (() => {
|
|
|
5194
5209
|
};
|
|
5195
5210
|
|
|
5196
5211
|
// src/wounds/fluids-bridge.ts
|
|
5212
|
+
var colorOf = (hex2) => Number.parseInt(hex2.replace(/^#|^0x/i, ""), 16);
|
|
5213
|
+
var bloodLookOfAge = (age, options = {}) => ({
|
|
5214
|
+
...age.blood < (options.thinBelow ?? 0.3) ? { liquid: options.thinLiquid ?? "old_blood" } : {},
|
|
5215
|
+
tint: { fresh: colorOf(age.freshBloodColor), dry: colorOf(age.dryBloodColor) },
|
|
5216
|
+
amount: age.blood
|
|
5217
|
+
});
|
|
5197
5218
|
var BURST_LITERS = { severed: 0.35, destroyed: 0.6, split: 0.9 };
|
|
5198
|
-
var
|
|
5219
|
+
var BURST_DROPS = { severed: 4, destroyed: 7, split: 10 };
|
|
5220
|
+
var createFluidsBridge = ({ sink, film, spray, burstDrops = BURST_DROPS, liquid = "blood", spurtSpeed = 1.4 }) => {
|
|
5221
|
+
const throwDrops = (point, wanted, look, direction, speed, radius) => {
|
|
5222
|
+
const amount = look?.amount ?? 1;
|
|
5223
|
+
const count = amount <= 0 ? 0 : Math.max(1, Math.round(wanted * Math.min(1, amount)));
|
|
5224
|
+
return film && count > 0 ? film.splat({
|
|
5225
|
+
fluid: look?.liquid ?? liquid,
|
|
5226
|
+
point,
|
|
5227
|
+
count,
|
|
5228
|
+
...direction ? { direction } : {},
|
|
5229
|
+
...speed !== void 0 ? { speed } : {},
|
|
5230
|
+
...radius !== void 0 ? { radius } : {},
|
|
5231
|
+
...look?.tint ? { tint: { fresh: look.tint.fresh, dry: look.tint.dry } } : {}
|
|
5232
|
+
}) : 0;
|
|
5233
|
+
};
|
|
5199
5234
|
const bleed = (point, litersPerSecond, dt, direction = [0, -1, 0], pressurized = false) => {
|
|
5200
5235
|
const liters = litersPerSecond * dt;
|
|
5201
5236
|
if (liters <= 0) return;
|
|
@@ -5207,10 +5242,462 @@ var GameCharactersThree = (() => {
|
|
|
5207
5242
|
handle(event) {
|
|
5208
5243
|
if (event.type === "leak" && event.fluid === "blood") bleed(event.point, event.rate, 1, event.direction, event.pressurized);
|
|
5209
5244
|
},
|
|
5210
|
-
burst
|
|
5245
|
+
burst(change, point, look, direction) {
|
|
5246
|
+
sink.splash(look?.liquid ?? liquid, point, BURST_LITERS[change]);
|
|
5247
|
+
throwDrops(point, burstDrops[change], look, direction);
|
|
5248
|
+
},
|
|
5249
|
+
wound: (point, look, direction) => throwDrops(point, spray?.count ?? 3, look, direction, spray?.speed, spray?.radius)
|
|
5211
5250
|
};
|
|
5212
5251
|
};
|
|
5213
5252
|
|
|
5253
|
+
// ../game-audio/dist/index.js
|
|
5254
|
+
var DISTANCE_CURVES = {
|
|
5255
|
+
/** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
|
|
5256
|
+
game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
|
|
5257
|
+
/** The game's `grito`: `1 / (1 + d² × 0.006)`, silent below 0.02 (jogo L62129–62130). */
|
|
5258
|
+
game_scream: { model: "inverse_square", k: 6e-3, minGain: 0.02 },
|
|
5259
|
+
/** The game's `voz`: `1 / (1 + d² × 0.01)`, silent below 0.02 (jogo L62146–62147). */
|
|
5260
|
+
game_voice: { model: "inverse_square", k: 0.01, minGain: 0.02 },
|
|
5261
|
+
/** The game's `boom`: `1.4 / (1 + d² × 0.002)`, never silent (jogo L68280). */
|
|
5262
|
+
game_boom: { model: "inverse_square", k: 2e-3, scale: 1.4 },
|
|
5263
|
+
/** The art scene's `outAt`: `vol / (1 + d² × 0.008)` (cena L1320). */
|
|
5264
|
+
art_scene: { model: "inverse_square", k: 8e-3 },
|
|
5265
|
+
/** The game's animal calls: `max(0, 1 − d / 70) × 0.25`, silent at or below 0.005 (jogo L66627–66628). */
|
|
5266
|
+
animals: { model: "linear", range: 70, scale: 0.25, minGain: 5e-3 }
|
|
5267
|
+
};
|
|
5268
|
+
var mix_profiles_default = [
|
|
5269
|
+
{
|
|
5270
|
+
id: "game",
|
|
5271
|
+
master: 0.5,
|
|
5272
|
+
noise: { seconds: 1.5, create: "lazy" },
|
|
5273
|
+
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"]
|
|
5274
|
+
},
|
|
5275
|
+
{
|
|
5276
|
+
id: "art_scene",
|
|
5277
|
+
master: 0.85,
|
|
5278
|
+
compressor: { threshold: -12, ratio: 5 },
|
|
5279
|
+
reverb: { seconds: 2.2, decay: 3.4, wet: 0.4 },
|
|
5280
|
+
noise: { seconds: 2, create: "eager" },
|
|
5281
|
+
sources: [
|
|
5282
|
+
"cena:L1308 compressor -12 dB, ratio 5",
|
|
5283
|
+
"cena:L1309 master 0.85",
|
|
5284
|
+
"cena:L1310 convolver, impulse 2.2 s of (1 - i/len)^3.4",
|
|
5285
|
+
"cena:L1311 wet 0.4",
|
|
5286
|
+
"cena:L1312 noise 2 s made with the chain"
|
|
5287
|
+
]
|
|
5288
|
+
}
|
|
5289
|
+
];
|
|
5290
|
+
var MIX_PROFILES = Object.fromEntries(
|
|
5291
|
+
mix_profiles_default.map((profile) => [profile.id, profile])
|
|
5292
|
+
);
|
|
5293
|
+
var game_sfx_default = {
|
|
5294
|
+
sources: ["jogo:L62089-62107"],
|
|
5295
|
+
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`.",
|
|
5296
|
+
classes: [
|
|
5297
|
+
{ id: "pistol", team: "pistola", bus: "weapons", cutoff: 1800, gain: 0.9, seconds: 0.18 },
|
|
5298
|
+
{ id: "shotgun", team: "escopeta", bus: "weapons", cutoff: 900, gain: 1.2, seconds: 0.35 },
|
|
5299
|
+
{ id: "rifle", team: "fuzil", bus: "weapons", cutoff: 1400, gain: 1.1, seconds: 0.28 },
|
|
5300
|
+
{ id: "long_rifle", team: "rifle", bus: "weapons", cutoff: 1100, gain: 1.3, seconds: 0.45 },
|
|
5301
|
+
{ id: "impact", team: "impacto", bus: "world", cutoff: 2500, gain: 0.25, seconds: 0.05 },
|
|
5302
|
+
{ id: "flesh", team: "carne", bus: "world", cutoff: 600, gain: 0.35, seconds: 0.08 },
|
|
5303
|
+
{ id: "step", team: "passo", bus: "world", cutoff: 400, gain: 0.08, seconds: 0.05 },
|
|
5304
|
+
{ id: "glass", team: "vidro", bus: "world", cutoff: 5e3, gain: 0.5, seconds: 0.3 },
|
|
5305
|
+
{ id: "wood", team: "madeira", bus: "world", cutoff: 700, gain: 0.5, seconds: 0.2 },
|
|
5306
|
+
{ id: "reload", team: "recarga", bus: "weapons", cutoff: 3e3, gain: 0.15, seconds: 0.06 },
|
|
5307
|
+
{ id: "empty", team: "vazio", bus: "weapons", cutoff: 4e3, gain: 0.12, seconds: 0.03 },
|
|
5308
|
+
{ id: "explosion", team: "explosao", bus: "world", cutoff: 200, gain: 1.6, seconds: 1.4 }
|
|
5309
|
+
],
|
|
5310
|
+
fallback: { id: "unknown", team: "(any other name)", bus: "world", cutoff: 1e3, gain: 0.5, seconds: 0.1 }
|
|
5311
|
+
};
|
|
5312
|
+
var GAME_SFX = game_sfx_default;
|
|
5313
|
+
var GAME_SFX_CLASSES = GAME_SFX.classes;
|
|
5314
|
+
var GAME_SFX_FALLBACK = GAME_SFX.fallback;
|
|
5315
|
+
function noiseClassRecipe(row, id = `sfx_${row.id}`) {
|
|
5316
|
+
return {
|
|
5317
|
+
id,
|
|
5318
|
+
bus: row.bus,
|
|
5319
|
+
order: "burst",
|
|
5320
|
+
duration: row.seconds,
|
|
5321
|
+
tail: 0.05,
|
|
5322
|
+
layers: [
|
|
5323
|
+
{
|
|
5324
|
+
source: { kind: "noise", offset: "random" },
|
|
5325
|
+
filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: row.cutoff } }] },
|
|
5326
|
+
envelope: [
|
|
5327
|
+
[0, row.gain, "set"],
|
|
5328
|
+
["1d", 1e-3, "exp", "fixed"]
|
|
5329
|
+
]
|
|
5330
|
+
}
|
|
5331
|
+
],
|
|
5332
|
+
falloff: DISTANCE_CURVES.game_sfx,
|
|
5333
|
+
sources: [...GAME_SFX.sources.map((source) => `${source} ${row.team}`)]
|
|
5334
|
+
};
|
|
5335
|
+
}
|
|
5336
|
+
var GAME_SFX_BANK = { id: "game_sfx", sounds: [...GAME_SFX_CLASSES, GAME_SFX_FALLBACK].map((row) => noiseClassRecipe(row)) };
|
|
5337
|
+
var ATTACK = 2e-3;
|
|
5338
|
+
function lengthOf(d, attack) {
|
|
5339
|
+
if (typeof d === "number") return attack + d;
|
|
5340
|
+
if (Array.isArray(d)) return [attack + d[0], attack + d[1]];
|
|
5341
|
+
return { ...d, add: (d.add ?? 0) + attack };
|
|
5342
|
+
}
|
|
5343
|
+
var envelope = (attack) => [
|
|
5344
|
+
[0, 1e-4, "set", "fixed"],
|
|
5345
|
+
[attack, 1, "exp"],
|
|
5346
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
5347
|
+
];
|
|
5348
|
+
function sceneNoise(o) {
|
|
5349
|
+
const a = o.a ?? ATTACK;
|
|
5350
|
+
const over = typeof o.d === "number" ? o.d : 0;
|
|
5351
|
+
return {
|
|
5352
|
+
filters: {
|
|
5353
|
+
mode: "serial",
|
|
5354
|
+
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 }]
|
|
5355
|
+
},
|
|
5356
|
+
duration: lengthOf(o.d, a),
|
|
5357
|
+
gain: o.vol,
|
|
5358
|
+
...o.delay === void 0 ? {} : { at: o.delay },
|
|
5359
|
+
...o.wet === void 0 ? {} : { wet: o.wet },
|
|
5360
|
+
source: { kind: "noise", offset: "random", offsetScale: 1.5, loop: true },
|
|
5361
|
+
envelope: envelope(a)
|
|
5362
|
+
};
|
|
5363
|
+
}
|
|
5364
|
+
function sceneTone(o) {
|
|
5365
|
+
return {
|
|
5366
|
+
source: { kind: "osc", wave: o.wave ?? "sine", frequency: { from: o.f, to: o.f2 ?? "from", curve: "exp", over: "duration" } },
|
|
5367
|
+
duration: lengthOf(o.d, ATTACK),
|
|
5368
|
+
gain: o.vol,
|
|
5369
|
+
...o.delay === void 0 ? {} : { at: o.delay },
|
|
5370
|
+
...o.wet === void 0 ? {} : { wet: o.wet },
|
|
5371
|
+
envelope: envelope(ATTACK)
|
|
5372
|
+
};
|
|
5373
|
+
}
|
|
5374
|
+
function sceneVoice(o) {
|
|
5375
|
+
return {
|
|
5376
|
+
duration: lengthOf(o.d, 0),
|
|
5377
|
+
gain: o.vol,
|
|
5378
|
+
wet: 0.45,
|
|
5379
|
+
source: {
|
|
5380
|
+
kind: "formant_voice",
|
|
5381
|
+
wave: o.wave ?? "sawtooth",
|
|
5382
|
+
frequency: { from: o.f0, to: o.f1, curve: "linear", over: "duration" },
|
|
5383
|
+
vibrato: { rate: [4, 10], depth: 0.08 },
|
|
5384
|
+
formants: [
|
|
5385
|
+
{ frequency: o.fA, q: 4 },
|
|
5386
|
+
{ frequency: o.fB, q: 6 }
|
|
5387
|
+
],
|
|
5388
|
+
breath: { frequency: o.fB, q: 1.1, gain: o.noise },
|
|
5389
|
+
mix: 3.2
|
|
5390
|
+
},
|
|
5391
|
+
envelope: [
|
|
5392
|
+
[0, 1e-4, "set", "fixed"],
|
|
5393
|
+
[0.1, 1, "exp"],
|
|
5394
|
+
["0.6d", 1, "set"],
|
|
5395
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
5396
|
+
]
|
|
5397
|
+
};
|
|
5398
|
+
}
|
|
5399
|
+
function sceneRecipe(id, layers, line, options = {}) {
|
|
5400
|
+
return {
|
|
5401
|
+
id,
|
|
5402
|
+
bus: options.bus ?? "world",
|
|
5403
|
+
pan: true,
|
|
5404
|
+
layers,
|
|
5405
|
+
falloff: DISTANCE_CURVES.art_scene,
|
|
5406
|
+
...options.vars ? { vars: options.vars } : {},
|
|
5407
|
+
...options.group ? { group: options.group } : {},
|
|
5408
|
+
sources: [`cena:${line}`]
|
|
5409
|
+
};
|
|
5410
|
+
}
|
|
5411
|
+
var BENCH_BANK = {
|
|
5412
|
+
id: "audio_bench",
|
|
5413
|
+
sounds: [
|
|
5414
|
+
{
|
|
5415
|
+
id: "bench_ping",
|
|
5416
|
+
bus: "ui",
|
|
5417
|
+
pan: true,
|
|
5418
|
+
duration: 0.25,
|
|
5419
|
+
layers: [
|
|
5420
|
+
{
|
|
5421
|
+
gain: 0.5,
|
|
5422
|
+
wet: 0.3,
|
|
5423
|
+
source: { kind: "osc", wave: "sine", frequency: { from: 880 } },
|
|
5424
|
+
envelope: [
|
|
5425
|
+
[0, 1e-4, "set", "fixed"],
|
|
5426
|
+
[2e-3, 1, "exp"],
|
|
5427
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
5428
|
+
]
|
|
5429
|
+
}
|
|
5430
|
+
],
|
|
5431
|
+
falloff: DISTANCE_CURVES.art_scene,
|
|
5432
|
+
sources: ["sdk: bench probe, a 880 Hz ping through the art scene output stage"]
|
|
5433
|
+
},
|
|
5434
|
+
{
|
|
5435
|
+
id: "bench_hiss",
|
|
5436
|
+
bus: "ui",
|
|
5437
|
+
pan: true,
|
|
5438
|
+
duration: [0.3, 0.9],
|
|
5439
|
+
layers: [
|
|
5440
|
+
{
|
|
5441
|
+
gain: 0.4,
|
|
5442
|
+
source: { kind: "noise", offset: "random", offsetScale: 1.5, loop: true },
|
|
5443
|
+
filters: { mode: "serial", bank: [{ type: "highpass", frequency: { set: 3e3 }, q: 0.7 }] },
|
|
5444
|
+
envelope: [
|
|
5445
|
+
[0, 1e-4, "set", "fixed"],
|
|
5446
|
+
[2e-3, 1, "exp"],
|
|
5447
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
5448
|
+
]
|
|
5449
|
+
}
|
|
5450
|
+
],
|
|
5451
|
+
falloff: DISTANCE_CURVES.art_scene,
|
|
5452
|
+
sources: ["sdk: bench probe, a highpass hiss of random length"]
|
|
5453
|
+
}
|
|
5454
|
+
]
|
|
5455
|
+
};
|
|
5456
|
+
|
|
5457
|
+
// src/audio/recipes.ts
|
|
5458
|
+
var UNDEAD_VOICE_GROUP = "undead_voice";
|
|
5459
|
+
var voiced = { bus: "voices", group: UNDEAD_VOICE_GROUP };
|
|
5460
|
+
var p = (param) => ({ param });
|
|
5461
|
+
var SCREAM_HOARSE = {
|
|
5462
|
+
id: "scream_hoarse",
|
|
5463
|
+
bus: "voices",
|
|
5464
|
+
order: "scream",
|
|
5465
|
+
duration: [1, 1.4],
|
|
5466
|
+
layers: [
|
|
5467
|
+
{
|
|
5468
|
+
source: { kind: "noise", offset: "random" },
|
|
5469
|
+
filters: {
|
|
5470
|
+
mode: "parallel",
|
|
5471
|
+
bank: [
|
|
5472
|
+
{ type: "bandpass", q: 6, frequency: { from: 700 * 1.15, to: 700 * 0.8, curve: "linear", over: "duration" }, level: 1 },
|
|
5473
|
+
{ type: "bandpass", q: 8, frequency: { from: 1150 * 1.15, to: 1150 * 0.8, curve: "linear", over: "duration" }, level: 0.7 },
|
|
5474
|
+
{ type: "bandpass", q: 10, frequency: { from: 2600 * 1.15, to: 2600 * 0.8, curve: "linear", over: "duration" }, level: 0.35 }
|
|
5475
|
+
]
|
|
5476
|
+
},
|
|
5477
|
+
modulators: [{ target: "gain", wave: "square", rate: [31, 40], depth: 0.35 }],
|
|
5478
|
+
envelope: [
|
|
5479
|
+
[0, 0, "set"],
|
|
5480
|
+
[0.06, 0.9, "linear"],
|
|
5481
|
+
["0.6d", 0.9, "set"],
|
|
5482
|
+
["1d", 1e-3, "exp", "fixed"]
|
|
5483
|
+
]
|
|
5484
|
+
}
|
|
5485
|
+
],
|
|
5486
|
+
falloff: DISTANCE_CURVES.game_scream,
|
|
5487
|
+
sources: ["jogo:L62128-62142 grito"]
|
|
5488
|
+
};
|
|
5489
|
+
var groanLayer = (base) => ({
|
|
5490
|
+
source: {
|
|
5491
|
+
kind: "osc",
|
|
5492
|
+
wave: "sawtooth",
|
|
5493
|
+
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" }
|
|
5494
|
+
},
|
|
5495
|
+
filters: { mode: "serial", bank: [{ type: "bandpass", q: 3, frequency: { set: typeof base === "number" ? base * 3 : { ...base, scale: 3 } } }] },
|
|
5496
|
+
envelope: [
|
|
5497
|
+
[0, 0, "set"],
|
|
5498
|
+
[0.15, 0.25, "linear"],
|
|
5499
|
+
["1d", 1e-3, "exp", "fixed"]
|
|
5500
|
+
]
|
|
5501
|
+
});
|
|
5502
|
+
var GROAN = {
|
|
5503
|
+
id: "groan",
|
|
5504
|
+
...voiced,
|
|
5505
|
+
order: "groan",
|
|
5506
|
+
vars: { base: [95, 135], dur: [0.9, 1.5] },
|
|
5507
|
+
duration: p("dur"),
|
|
5508
|
+
layers: [groanLayer(p("base"))],
|
|
5509
|
+
falloff: DISTANCE_CURVES.game_voice,
|
|
5510
|
+
sources: ["jogo:L62143-62155 voz gemido"]
|
|
5511
|
+
};
|
|
5512
|
+
var RUNNER_GROAN = {
|
|
5513
|
+
id: "runner_groan",
|
|
5514
|
+
...voiced,
|
|
5515
|
+
order: "groan",
|
|
5516
|
+
vars: { dur: [0.9, 1.5] },
|
|
5517
|
+
duration: p("dur"),
|
|
5518
|
+
layers: [groanLayer(300)],
|
|
5519
|
+
falloff: DISTANCE_CURVES.game_voice,
|
|
5520
|
+
sources: ["jogo:L62143-62155 voz corredor"]
|
|
5521
|
+
};
|
|
5522
|
+
var scene = (id, layers, line, options = {}) => sceneRecipe(id, layers, line, options);
|
|
5523
|
+
var groan = (id, vars, voice, line) => scene(id, [sceneVoice(voice)], line, { vars, ...voiced });
|
|
5524
|
+
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)");
|
|
5525
|
+
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)");
|
|
5526
|
+
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)");
|
|
5527
|
+
var SCREAM = scene(
|
|
5528
|
+
"scream",
|
|
5529
|
+
[
|
|
5530
|
+
sceneVoice({ f0: 520, f1: 880, d: 2.6, fA: 1800, fB: 3200, noise: 0.9, vol: 1.6 }),
|
|
5531
|
+
sceneVoice({ f0: 640, f1: 1020, d: 2.4, fA: 2400, fB: 3800, noise: 0.6, vol: 1.1, wave: "square" })
|
|
5532
|
+
],
|
|
5533
|
+
"L1347 scream",
|
|
5534
|
+
{ bus: "voices" }
|
|
5535
|
+
);
|
|
5536
|
+
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" });
|
|
5537
|
+
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" });
|
|
5538
|
+
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" });
|
|
5539
|
+
var BITE = scene(
|
|
5540
|
+
"bite",
|
|
5541
|
+
[
|
|
5542
|
+
sceneNoise({ f: 1400, d: 0.2, vol: 1.1 }),
|
|
5543
|
+
...[0, 1, 2, 3].map((k) => sceneNoise({ type: "highpass", f: 2500, d: 0.03, vol: 0.5, delay: 0.03 + k * 0.04 })),
|
|
5544
|
+
sceneTone({ wave: "sawtooth", f: 320, f2: 170, d: 0.5, vol: 0.35, delay: 0.05 })
|
|
5545
|
+
],
|
|
5546
|
+
"L1351 bite",
|
|
5547
|
+
{ bus: "voices" }
|
|
5548
|
+
);
|
|
5549
|
+
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" });
|
|
5550
|
+
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");
|
|
5551
|
+
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)");
|
|
5552
|
+
var SEVER = scene(
|
|
5553
|
+
"sever",
|
|
5554
|
+
[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 })],
|
|
5555
|
+
"L1355 sever"
|
|
5556
|
+
);
|
|
5557
|
+
var GORE = scene(
|
|
5558
|
+
"gore",
|
|
5559
|
+
[
|
|
5560
|
+
sceneNoise({ f: 900, f2: 200, d: 0.4, vol: 1.1, wet: 0.3 }),
|
|
5561
|
+
...[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 }))
|
|
5562
|
+
],
|
|
5563
|
+
"L1356 gore"
|
|
5564
|
+
);
|
|
5565
|
+
var CHARACTER_SOUNDS = [
|
|
5566
|
+
SCREAM_HOARSE,
|
|
5567
|
+
GROAN,
|
|
5568
|
+
RUNNER_GROAN,
|
|
5569
|
+
GROAN_WALKER,
|
|
5570
|
+
GROAN_BRUTE,
|
|
5571
|
+
GROAN_RUNNER,
|
|
5572
|
+
SCREAM,
|
|
5573
|
+
INHALE,
|
|
5574
|
+
LEAP,
|
|
5575
|
+
GRAB,
|
|
5576
|
+
BITE,
|
|
5577
|
+
HURT,
|
|
5578
|
+
FLESH,
|
|
5579
|
+
FLESH_HEAD,
|
|
5580
|
+
SEVER,
|
|
5581
|
+
GORE
|
|
5582
|
+
];
|
|
5583
|
+
var CHARACTER_SOUND_BANK = { id: "characters_three", sounds: CHARACTER_SOUNDS };
|
|
5584
|
+
|
|
5585
|
+
// src/audio/voices.json
|
|
5586
|
+
var voices_default = {
|
|
5587
|
+
sources: [
|
|
5588
|
+
"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",
|
|
5589
|
+
"cena:L1238, L1248, L1249 the scream and the inhale belong to the Gritador, the leap to the Saltador",
|
|
5590
|
+
"cena:L1226 the groan when a body wakes (FEIGN to CHASE) and the game L67275/L67328 voz('corredor') when one notices the player",
|
|
5591
|
+
"jogo:L66986 the groan of the game: 'corredor' for the runner category, 'gemido' for the rest; jogo:L66989 screamAt plays 'grito'",
|
|
5592
|
+
"types.json: the voice line of each Bestiario type"
|
|
5593
|
+
],
|
|
5594
|
+
types: {
|
|
5595
|
+
walker: { origin: "team", groan: "groan_walker", gameGroan: "groan" },
|
|
5596
|
+
runner: { origin: "team", groan: "groan_runner", gameGroan: "runner_groan" },
|
|
5597
|
+
crawler: { origin: "rule", groan: "groan_walker", gameGroan: "groan" },
|
|
5598
|
+
brute: { origin: "team", groan: "groan_brute", gameGroan: "groan" },
|
|
5599
|
+
sniffer: {
|
|
5600
|
+
origin: "extra",
|
|
5601
|
+
groan: "groan_runner",
|
|
5602
|
+
gameGroan: "groan",
|
|
5603
|
+
idle: [{ sound: "inhale" }, { sound: "groan_runner", delay: 0.6 }]
|
|
5604
|
+
},
|
|
5605
|
+
leaper: { origin: "team", groan: "groan_runner", gameGroan: "groan", special: [{ sound: "leap" }] },
|
|
5606
|
+
bloater: { origin: "rule", groan: "groan_walker", gameGroan: "groan" },
|
|
5607
|
+
stalker: { origin: "rule", groan: "groan_runner", gameGroan: "groan", idle: [] },
|
|
5608
|
+
blind: { origin: "rule", groan: "groan_walker", gameGroan: "groan" },
|
|
5609
|
+
screamer: {
|
|
5610
|
+
origin: "team",
|
|
5611
|
+
groan: "groan_walker",
|
|
5612
|
+
gameGroan: "groan",
|
|
5613
|
+
special: [{ sound: "inhale" }, { sound: "scream", delay: 1.5 }],
|
|
5614
|
+
gameSpecial: [{ sound: "scream_hoarse" }]
|
|
5615
|
+
},
|
|
5616
|
+
charred: { origin: "rule", groan: "groan_walker", gameGroan: "groan" },
|
|
5617
|
+
drowned: { origin: "rule", groan: "groan_walker", gameGroan: "groan" },
|
|
5618
|
+
devourer: {
|
|
5619
|
+
origin: "extra",
|
|
5620
|
+
groan: "groan_walker",
|
|
5621
|
+
gameGroan: "groan",
|
|
5622
|
+
idle: [{ sound: "groan_walker" }, { sound: "bite", delay: 0.4 }]
|
|
5623
|
+
}
|
|
5624
|
+
}
|
|
5625
|
+
};
|
|
5626
|
+
|
|
5627
|
+
// src/audio/sound.ts
|
|
5628
|
+
var DATA = voices_default;
|
|
5629
|
+
var UNDEAD_VOICES = DATA.types;
|
|
5630
|
+
var UNDEAD_VOICE_SOURCES = DATA.sources;
|
|
5631
|
+
var BODY_SOUNDS = {
|
|
5632
|
+
art_scene: {
|
|
5633
|
+
wound: { sound: "flesh", head: "flesh_head" },
|
|
5634
|
+
severed: { sound: "sever" },
|
|
5635
|
+
destroyed: { sound: "gore" },
|
|
5636
|
+
split: { sound: "gore" }
|
|
5637
|
+
},
|
|
5638
|
+
game: {
|
|
5639
|
+
wound: { sound: "sfx_flesh" }
|
|
5640
|
+
}
|
|
5641
|
+
};
|
|
5642
|
+
var PLAYER_SOUNDS = { grab: "grab", bite: "bite", hurt: "hurt" };
|
|
5643
|
+
var HEAD_PARTS = /* @__PURE__ */ new Set(["head", "jaw"]);
|
|
5644
|
+
function createCharacterSound(sink, options = {}) {
|
|
5645
|
+
sink.register?.(CHARACTER_SOUND_BANK);
|
|
5646
|
+
sink.register?.(GAME_SFX_BANK);
|
|
5647
|
+
const style = options.style ?? "art_scene";
|
|
5648
|
+
const voices = { ...UNDEAD_VOICES, ...options.voices };
|
|
5649
|
+
const rules = { ...BODY_SOUNDS.art_scene, ...style === "game" ? BODY_SOUNDS.game : {}, ...options.body };
|
|
5650
|
+
const queue = [];
|
|
5651
|
+
const voiceOf = (typeId) => {
|
|
5652
|
+
const own = voices[typeId];
|
|
5653
|
+
if (own === null) return void 0;
|
|
5654
|
+
return own ?? (options.fallbackType ? voices[options.fallbackType] ?? void 0 : void 0);
|
|
5655
|
+
};
|
|
5656
|
+
const stepsOf = (typeId, moment) => {
|
|
5657
|
+
const voice = voiceOf(typeId);
|
|
5658
|
+
if (!voice) return [];
|
|
5659
|
+
const groan2 = style === "game" ? voice.gameGroan : voice.groan;
|
|
5660
|
+
if (moment === "special") return (style === "game" ? voice.gameSpecial ?? voice.special : voice.special) ?? [];
|
|
5661
|
+
if (moment === "alert") return voice.alert ?? [{ sound: style === "game" ? "runner_groan" : groan2 }];
|
|
5662
|
+
return voice.idle ?? [{ sound: groan2 }];
|
|
5663
|
+
};
|
|
5664
|
+
const start = (sound, at, volume) => void sink.play({ sound, position: at, volume });
|
|
5665
|
+
return {
|
|
5666
|
+
stepsOf,
|
|
5667
|
+
voice(typeId, moment, position, volume = 1) {
|
|
5668
|
+
const steps = stepsOf(typeId, moment);
|
|
5669
|
+
for (const step of steps) {
|
|
5670
|
+
if (step.delay && step.delay > 0) queue.push({ sound: step.sound, at: position, volume, wait: step.delay });
|
|
5671
|
+
else start(step.sound, position, volume);
|
|
5672
|
+
}
|
|
5673
|
+
return steps.length;
|
|
5674
|
+
},
|
|
5675
|
+
body(event, position, volume = 1) {
|
|
5676
|
+
if (event.type !== "body") return false;
|
|
5677
|
+
const rule = rules[event.change];
|
|
5678
|
+
if (!rule) return false;
|
|
5679
|
+
const head = event.part !== void 0 && HEAD_PARTS.has(event.part);
|
|
5680
|
+
start(head && rule.head ? rule.head : rule.sound, position, volume);
|
|
5681
|
+
return true;
|
|
5682
|
+
},
|
|
5683
|
+
player: (kind, volume = 1) => void sink.play({ sound: PLAYER_SOUNDS[kind], volume }),
|
|
5684
|
+
update(dt) {
|
|
5685
|
+
for (let i = queue.length - 1; i >= 0; i--) {
|
|
5686
|
+
const item = queue[i];
|
|
5687
|
+
item.wait -= dt;
|
|
5688
|
+
if (item.wait <= 0) {
|
|
5689
|
+
queue.splice(i, 1);
|
|
5690
|
+
start(item.sound, item.at, item.volume);
|
|
5691
|
+
}
|
|
5692
|
+
}
|
|
5693
|
+
},
|
|
5694
|
+
pending: () => queue.length,
|
|
5695
|
+
dispose() {
|
|
5696
|
+
queue.length = 0;
|
|
5697
|
+
}
|
|
5698
|
+
};
|
|
5699
|
+
}
|
|
5700
|
+
|
|
5214
5701
|
// src/test-area/crowd.ts
|
|
5215
5702
|
var FIELD = { x0: 12, x1: 30, z0: -16, z1: 16 };
|
|
5216
5703
|
var STRIDE = 1;
|
|
@@ -5475,7 +5962,7 @@ var GameCharactersThree = (() => {
|
|
|
5475
5962
|
hit_preset: "What the Fire hit button does to the body you look at",
|
|
5476
5963
|
protection: "Worn by the bodies created from now on"
|
|
5477
5964
|
},
|
|
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" },
|
|
5965
|
+
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
5966
|
options: {
|
|
5480
5967
|
penetration: { physical: "Physical", "team-game": "Team game" },
|
|
5481
5968
|
death_rule: { "vitality-or-head": "Vitality or head", "head-only": "Head only" },
|
|
@@ -5520,7 +6007,7 @@ var GameCharactersThree = (() => {
|
|
|
5520
6007
|
hit_preset: "O que o bot\xE3o Disparar faz no corpo para o qual voc\xEA olha",
|
|
5521
6008
|
protection: "Vestida pelos corpos criados daqui em diante"
|
|
5522
6009
|
},
|
|
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" },
|
|
6010
|
+
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
6011
|
options: {
|
|
5525
6012
|
penetration: { physical: "F\xEDsica", "team-game": "Do jogo" },
|
|
5526
6013
|
death_rule: { "vitality-or-head": "Vitalidade ou cabe\xE7a", "head-only": "S\xF3 a cabe\xE7a" },
|
|
@@ -5575,6 +6062,7 @@ var GameCharactersThree = (() => {
|
|
|
5575
6062
|
let best = null;
|
|
5576
6063
|
let people = null;
|
|
5577
6064
|
let wounds = null;
|
|
6065
|
+
let sound = null;
|
|
5578
6066
|
let crowd = null;
|
|
5579
6067
|
let selected = null;
|
|
5580
6068
|
let time = 0;
|
|
@@ -5667,6 +6155,9 @@ var GameCharactersThree = (() => {
|
|
|
5667
6155
|
if (Math.abs(scale - 1) > 0.01) object.scale.setScalar(scale);
|
|
5668
6156
|
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
6157
|
entry.character = wrap(entry, character);
|
|
6158
|
+
const age = made.kind === "zombie" ? undead?.traitsOf(character)?.age : void 0;
|
|
6159
|
+
const blood = age !== void 0 ? options.bloodOf?.(age) : void 0;
|
|
6160
|
+
if (entry.body && blood) entry.body.blood = blood;
|
|
5670
6161
|
entries.set(id, entry);
|
|
5671
6162
|
selected ?? (selected = entry);
|
|
5672
6163
|
trackEntry(entry);
|
|
@@ -5749,8 +6240,8 @@ var GameCharactersThree = (() => {
|
|
|
5749
6240
|
const selectedOrFirst = () => selected ?? entries.values().next().value ?? null;
|
|
5750
6241
|
const fireOn = (entry) => {
|
|
5751
6242
|
const preset2 = hitPresetOf(settings.hit);
|
|
5752
|
-
const
|
|
5753
|
-
entry.character.hit(hitFor(preset2, [
|
|
6243
|
+
const p2 = entry.root.position;
|
|
6244
|
+
entry.character.hit(hitFor(preset2, [p2.x, p2.y, p2.z], 1.3, kit.calibers));
|
|
5754
6245
|
};
|
|
5755
6246
|
const ensureCrowd = () => {
|
|
5756
6247
|
if (crowd) return crowd;
|
|
@@ -5785,7 +6276,14 @@ var GameCharactersThree = (() => {
|
|
|
5785
6276
|
if (infection.reanimated) target.character = wrap(target, undead.turn(target.character));
|
|
5786
6277
|
}
|
|
5787
6278
|
} else if (change.id === "fire_preset" && target) fireOn(target);
|
|
5788
|
-
else if (change.id === "
|
|
6279
|
+
else if ((change.id === "voice" || change.id === "special_call") && sound) {
|
|
6280
|
+
const speaker = target?.kind === "zombie" ? target : [...entries.values()].find((entry) => entry.kind === "zombie");
|
|
6281
|
+
if (speaker) {
|
|
6282
|
+
const at = speaker.root.getWorldPosition(new host.THREE.Vector3());
|
|
6283
|
+
const hurried = settings.moment === "alert" || settings.moment === "chase" || settings.moment === "sprint";
|
|
6284
|
+
sound.voice(speaker.cardId, change.id === "special_call" ? "special" : hurried ? "alert" : "idle", [at.x, at.y + 1.5, at.z]);
|
|
6285
|
+
}
|
|
6286
|
+
} else if (change.id === "spawn_100" || change.id === "spawn_1000") {
|
|
5789
6287
|
ensureBuilders(host?.THREE ?? three);
|
|
5790
6288
|
ensureCrowd().spawn(change.id === "spawn_100" ? 100 : 1e3);
|
|
5791
6289
|
}
|
|
@@ -5890,6 +6388,8 @@ var GameCharactersThree = (() => {
|
|
|
5890
6388
|
withHint(choice("hit_preset", HIT_PRESETS.map((preset2) => preset2.id), "9x19"), text.hints.hit_preset),
|
|
5891
6389
|
withHint(choice("protection", ["none", "vest_police", "vest_military", "helmet_combat", "turnout_gear", "vest_helmet"], "none"), text.hints.protection),
|
|
5892
6390
|
{ kind: "action", id: "fire_preset", name: text.actions.fire_preset },
|
|
6391
|
+
{ kind: "action", id: "voice", name: text.actions.voice },
|
|
6392
|
+
{ kind: "action", id: "special_call", name: text.actions.special_call },
|
|
5893
6393
|
{ kind: "action", id: "heal", name: text.actions.heal },
|
|
5894
6394
|
{ kind: "action", id: "kill", name: text.actions.kill },
|
|
5895
6395
|
{ kind: "action", id: "infect", name: text.actions.infect },
|
|
@@ -5917,9 +6417,10 @@ var GameCharactersThree = (() => {
|
|
|
5917
6417
|
attach(lent) {
|
|
5918
6418
|
host = lent;
|
|
5919
6419
|
ensureBuilders(lent.THREE);
|
|
5920
|
-
const
|
|
5921
|
-
const bridge = options.fluids ? createFluidsBridge({ sink: options.fluids }) : void 0;
|
|
5922
|
-
|
|
6420
|
+
const scene2 = lent.scene;
|
|
6421
|
+
const bridge = options.fluids ? createFluidsBridge({ sink: options.fluids, ...options.film ? { film: options.film } : {} }) : void 0;
|
|
6422
|
+
sound = lent.audio && options.sound !== false ? createCharacterSound(lent.audio, options.sound ?? {}) : null;
|
|
6423
|
+
wounds = createWounds(lent.THREE, { random, scene: scene2, groundAt: (x, z) => lent.groundAt(x, z), ...bridge ? { bridge } : {}, ...sound ? { sound } : {} });
|
|
5923
6424
|
for (const entry of entries.values()) trackEntry(entry);
|
|
5924
6425
|
const stopChange = lent.bench?.onChange(onChange);
|
|
5925
6426
|
const stopFrame = lent.onFrame((dt) => {
|
|
@@ -5932,6 +6433,7 @@ var GameCharactersThree = (() => {
|
|
|
5932
6433
|
animate(entry, dt);
|
|
5933
6434
|
}
|
|
5934
6435
|
wounds?.update(dt);
|
|
6436
|
+
sound?.update(dt);
|
|
5935
6437
|
crowd?.update(dt, lent.camera);
|
|
5936
6438
|
});
|
|
5937
6439
|
return () => {
|
|
@@ -5940,6 +6442,8 @@ var GameCharactersThree = (() => {
|
|
|
5940
6442
|
clearOverlays();
|
|
5941
6443
|
wounds?.dispose();
|
|
5942
6444
|
wounds = null;
|
|
6445
|
+
sound?.dispose();
|
|
6446
|
+
sound = null;
|
|
5943
6447
|
if (crowd) {
|
|
5944
6448
|
crowd.group.parent?.remove(crowd.group);
|
|
5945
6449
|
crowd = null;
|