@adatechnology/game-animals-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/dist/index.d.ts +55 -2
- package/dist/index.global.js +247 -2
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +100 -2
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { AnimalSpecies, QuadrupedSpec, TextureMarker, AnimalVisualState } from '@adatechnology/game-animals';
|
|
2
2
|
import { NodeSkin } from '@adatechnology/game-props3d';
|
|
3
3
|
import * as THREE_NS from 'three';
|
|
4
|
-
import {
|
|
4
|
+
import { SoundRecipe, SoundBank } from '@adatechnology/game-audio';
|
|
5
|
+
import { Vec3, SoundRequest, TestableModule } from '@adatechnology/game-contracts';
|
|
5
6
|
|
|
6
7
|
/** What the animation needs each frame. */
|
|
7
8
|
type AnimateParams = {
|
|
@@ -98,6 +99,56 @@ type AnimalRig = {
|
|
|
98
99
|
triangles: number;
|
|
99
100
|
};
|
|
100
101
|
|
|
102
|
+
/** `latido`: two square clicks 0.22 s apart, 520 Hz falling to 0.6, 0.12 s each. */
|
|
103
|
+
declare const DOG_BARK: SoundRecipe;
|
|
104
|
+
/** `queroquero`: three squares 0.14 s apart, 2400 Hz falling to 0.6, 0.09 s each. */
|
|
105
|
+
declare const LAPWING_CALL: SoundRecipe;
|
|
106
|
+
/** `cacarejo`: four squares 0.14 s apart, 900 Hz falling to 0.6, 0.09 s each. */
|
|
107
|
+
declare const HEN_CLUCK: SoundRecipe;
|
|
108
|
+
/** `mugido`: one sawtooth, 140 Hz falling to 0.8, 1.2 s. */
|
|
109
|
+
declare const COW_MOO: SoundRecipe;
|
|
110
|
+
declare const ANIMAL_SOUNDS: readonly SoundRecipe[];
|
|
111
|
+
declare const ANIMAL_SOUND_BANK: SoundBank;
|
|
112
|
+
|
|
113
|
+
/** The call of a species: the recipe, the seconds the page waits before the same animal calls again, and the metres its noise reaches the AI (`emitNoise`). */
|
|
114
|
+
type AnimalCall = {
|
|
115
|
+
readonly sound: string;
|
|
116
|
+
readonly cooldown: number;
|
|
117
|
+
readonly noiseMetres: number;
|
|
118
|
+
};
|
|
119
|
+
/** The calls the page delivered, by species id. The other species (horse, pig, boar, capybara, jaguar, cat, vulture, snake, rat) have none: the page gives them no sound. */
|
|
120
|
+
declare const ANIMAL_CALLS: Readonly<Record<string, AnimalCall>>;
|
|
121
|
+
declare const ANIMAL_CALL_SOURCES: readonly string[];
|
|
122
|
+
/** The part of the host's sound an animal needs: `play`, and `register` to put the bank in its engine (`createAudioSink(...)` has both). */
|
|
123
|
+
type AnimalSoundSink = {
|
|
124
|
+
play(request: SoundRequest): unknown;
|
|
125
|
+
register?(bank: unknown): void;
|
|
126
|
+
};
|
|
127
|
+
type AnimalSoundOptions = {
|
|
128
|
+
/** Replaces a species' call; `null` silences it. */
|
|
129
|
+
readonly calls?: Readonly<Record<string, AnimalCall | null>>;
|
|
130
|
+
};
|
|
131
|
+
type AnimalSound = {
|
|
132
|
+
/** The call of a species, if it has one. */
|
|
133
|
+
callOf(speciesId: string): AnimalCall | undefined;
|
|
134
|
+
/**
|
|
135
|
+
* Makes the species call where the animal is. `key` is the animal (default the species): the same animal waits out its cooldown, and the call is
|
|
136
|
+
* refused (false) until then. Returns whether a sound was asked for.
|
|
137
|
+
*/
|
|
138
|
+
call(speciesId: string, position: Vec3, options?: {
|
|
139
|
+
readonly volume?: number;
|
|
140
|
+
readonly key?: string;
|
|
141
|
+
}): boolean;
|
|
142
|
+
/** Counts the cooldowns down: call it each frame. */
|
|
143
|
+
update(dt: number): void;
|
|
144
|
+
dispose(): void;
|
|
145
|
+
};
|
|
146
|
+
/**
|
|
147
|
+
* Plays the calls of the animals on the host's sound: the four of the Bichos do Vale (hen, lapwing, cow, dog), positional with the page's linear 70 m
|
|
148
|
+
* fall, each animal waiting out the page's cooldown. The bank is registered in the host's engine.
|
|
149
|
+
*/
|
|
150
|
+
declare function createAnimalSound(sink: AnimalSoundSink, options?: AnimalSoundOptions): AnimalSound;
|
|
151
|
+
|
|
101
152
|
type MaterialExtras = Partial<THREE_NS.MeshStandardMaterialParameters>;
|
|
102
153
|
/** The part builders of the page's `Animal` (`M`, `ball`, `limb`, `joint`, `pivot`), bound to one rig. */
|
|
103
154
|
type RigTools = {
|
|
@@ -210,6 +261,8 @@ type AnimalsTestOptions = {
|
|
|
210
261
|
readonly timeScale: number;
|
|
211
262
|
}) => OutbreakLike;
|
|
212
263
|
readonly document?: DocumentLike;
|
|
264
|
+
/** The calls of the animals on the room's engine (`host.audio`); `false` leaves the area silent. */
|
|
265
|
+
readonly sound?: false | AnimalSoundOptions;
|
|
213
266
|
/** Seed of the draws of the area (default 7, the page's). */
|
|
214
267
|
readonly seed?: number;
|
|
215
268
|
};
|
|
@@ -248,4 +301,4 @@ type AnimalsThree = {
|
|
|
248
301
|
};
|
|
249
302
|
declare const createAnimalsThree: (THREE: Three, options?: AnimalsThreeOptions) => AnimalsThree;
|
|
250
303
|
|
|
251
|
-
export { ANIMALS_AREA_ID, ANIMAL_ITEM_PREFIX, type AnimalLeg, type AnimalPivot, type AnimalRig, type AnimalWing, type AnimalsContext, type AnimalsTestOptions, type AnimalsThree, type AnimalsThreeOptions, type AnimateParams, BIRD_EXTRAS, type BirdExtra, type BirdParts, type CanvasLike, type DocumentLike, type ExtraContext, type LineUpOptions, type OutbreakLike, QUADRUPED_EXTRAS, type QuadrupedExtra, type QuadrupedParts, type Three, applyVisualState, createAnimalsTestModule, createAnimalsThree, createCoatTexture, lineUpAnimals, profileGeometry, setJointView, setSplit, updateSplit };
|
|
304
|
+
export { ANIMALS_AREA_ID, ANIMAL_CALLS, ANIMAL_CALL_SOURCES, ANIMAL_ITEM_PREFIX, ANIMAL_SOUNDS, ANIMAL_SOUND_BANK, type AnimalCall, type AnimalLeg, type AnimalPivot, type AnimalRig, type AnimalSound, type AnimalSoundOptions, type AnimalSoundSink, type AnimalWing, type AnimalsContext, type AnimalsTestOptions, type AnimalsThree, type AnimalsThreeOptions, type AnimateParams, BIRD_EXTRAS, type BirdExtra, type BirdParts, COW_MOO, type CanvasLike, DOG_BARK, type DocumentLike, type ExtraContext, HEN_CLUCK, LAPWING_CALL, type LineUpOptions, type OutbreakLike, QUADRUPED_EXTRAS, type QuadrupedExtra, type QuadrupedParts, type Three, applyVisualState, createAnimalSound, createAnimalsTestModule, createAnimalsThree, createCoatTexture, lineUpAnimals, profileGeometry, setJointView, setSplit, updateSplit };
|
package/dist/index.global.js
CHANGED
|
@@ -22,10 +22,19 @@ var GameAnimalsThree = (() => {
|
|
|
22
22
|
var index_exports = {};
|
|
23
23
|
__export(index_exports, {
|
|
24
24
|
ANIMALS_AREA_ID: () => ANIMALS_AREA_ID,
|
|
25
|
+
ANIMAL_CALLS: () => ANIMAL_CALLS,
|
|
26
|
+
ANIMAL_CALL_SOURCES: () => ANIMAL_CALL_SOURCES,
|
|
25
27
|
ANIMAL_ITEM_PREFIX: () => ANIMAL_ITEM_PREFIX,
|
|
28
|
+
ANIMAL_SOUNDS: () => ANIMAL_SOUNDS,
|
|
29
|
+
ANIMAL_SOUND_BANK: () => ANIMAL_SOUND_BANK,
|
|
26
30
|
BIRD_EXTRAS: () => BIRD_EXTRAS,
|
|
31
|
+
COW_MOO: () => COW_MOO,
|
|
32
|
+
DOG_BARK: () => DOG_BARK,
|
|
33
|
+
HEN_CLUCK: () => HEN_CLUCK,
|
|
34
|
+
LAPWING_CALL: () => LAPWING_CALL,
|
|
27
35
|
QUADRUPED_EXTRAS: () => QUADRUPED_EXTRAS,
|
|
28
36
|
applyVisualState: () => applyVisualState,
|
|
37
|
+
createAnimalSound: () => createAnimalSound,
|
|
29
38
|
createAnimalsTestModule: () => createAnimalsTestModule,
|
|
30
39
|
createAnimalsThree: () => createAnimalsThree,
|
|
31
40
|
createCoatTexture: () => createCoatTexture,
|
|
@@ -280,6 +289,24 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
280
289
|
}
|
|
281
290
|
};
|
|
282
291
|
};
|
|
292
|
+
var LEAF = (() => {
|
|
293
|
+
const f = [0, 0, 0, -0.5, 0.4, 0, 0.5, 0.4, 0, 0, 1, 0];
|
|
294
|
+
const positions = [];
|
|
295
|
+
const normals = [];
|
|
296
|
+
const uvs = [];
|
|
297
|
+
const indices = [];
|
|
298
|
+
for (const side of [1, -1]) {
|
|
299
|
+
const base = positions.length / 3;
|
|
300
|
+
for (let i = 0; i < 4; i++) {
|
|
301
|
+
positions.push(f[i * 3], f[i * 3 + 1], f[i * 3 + 2]);
|
|
302
|
+
normals.push(0, 0, side);
|
|
303
|
+
uvs.push(f[i * 3] + 0.5, f[i * 3 + 1]);
|
|
304
|
+
}
|
|
305
|
+
if (side === 1) indices.push(base, base + 2, base + 1, base + 1, base + 2, base + 3);
|
|
306
|
+
else indices.push(base, base + 1, base + 2, base + 1, base + 3, base + 2);
|
|
307
|
+
}
|
|
308
|
+
return { positions, normals, uvs, indices };
|
|
309
|
+
})();
|
|
283
310
|
|
|
284
311
|
// src/animate-bird.ts
|
|
285
312
|
var { PI } = Math;
|
|
@@ -971,6 +998,213 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
971
998
|
});
|
|
972
999
|
};
|
|
973
1000
|
|
|
1001
|
+
// ../game-audio/dist/index.js
|
|
1002
|
+
var DISTANCE_CURVES = {
|
|
1003
|
+
/** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
|
|
1004
|
+
game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
|
|
1005
|
+
/** The game's `grito`: `1 / (1 + d² × 0.006)`, silent below 0.02 (jogo L62129–62130). */
|
|
1006
|
+
game_scream: { model: "inverse_square", k: 6e-3, minGain: 0.02 },
|
|
1007
|
+
/** The game's `voz`: `1 / (1 + d² × 0.01)`, silent below 0.02 (jogo L62146–62147). */
|
|
1008
|
+
game_voice: { model: "inverse_square", k: 0.01, minGain: 0.02 },
|
|
1009
|
+
/** The game's `boom`: `1.4 / (1 + d² × 0.002)`, never silent (jogo L68280). */
|
|
1010
|
+
game_boom: { model: "inverse_square", k: 2e-3, scale: 1.4 },
|
|
1011
|
+
/** The art scene's `outAt`: `vol / (1 + d² × 0.008)` (cena L1320). */
|
|
1012
|
+
art_scene: { model: "inverse_square", k: 8e-3 },
|
|
1013
|
+
/** The game's animal calls: `max(0, 1 − d / 70) × 0.25`, silent at or below 0.005 (jogo L66627–66628). */
|
|
1014
|
+
animals: { model: "linear", range: 70, scale: 0.25, minGain: 5e-3 }
|
|
1015
|
+
};
|
|
1016
|
+
var mix_profiles_default = [
|
|
1017
|
+
{
|
|
1018
|
+
id: "game",
|
|
1019
|
+
master: 0.5,
|
|
1020
|
+
noise: { seconds: 1.5, create: "lazy" },
|
|
1021
|
+
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"]
|
|
1022
|
+
},
|
|
1023
|
+
{
|
|
1024
|
+
id: "art_scene",
|
|
1025
|
+
master: 0.85,
|
|
1026
|
+
compressor: { threshold: -12, ratio: 5 },
|
|
1027
|
+
reverb: { seconds: 2.2, decay: 3.4, wet: 0.4 },
|
|
1028
|
+
noise: { seconds: 2, create: "eager" },
|
|
1029
|
+
sources: [
|
|
1030
|
+
"cena:L1308 compressor -12 dB, ratio 5",
|
|
1031
|
+
"cena:L1309 master 0.85",
|
|
1032
|
+
"cena:L1310 convolver, impulse 2.2 s of (1 - i/len)^3.4",
|
|
1033
|
+
"cena:L1311 wet 0.4",
|
|
1034
|
+
"cena:L1312 noise 2 s made with the chain"
|
|
1035
|
+
]
|
|
1036
|
+
}
|
|
1037
|
+
];
|
|
1038
|
+
var MIX_PROFILES = Object.fromEntries(
|
|
1039
|
+
mix_profiles_default.map((profile) => [profile.id, profile])
|
|
1040
|
+
);
|
|
1041
|
+
var game_sfx_default = {
|
|
1042
|
+
sources: ["jogo:L62089-62107"],
|
|
1043
|
+
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`.",
|
|
1044
|
+
classes: [
|
|
1045
|
+
{ id: "pistol", team: "pistola", bus: "weapons", cutoff: 1800, gain: 0.9, seconds: 0.18 },
|
|
1046
|
+
{ id: "shotgun", team: "escopeta", bus: "weapons", cutoff: 900, gain: 1.2, seconds: 0.35 },
|
|
1047
|
+
{ id: "rifle", team: "fuzil", bus: "weapons", cutoff: 1400, gain: 1.1, seconds: 0.28 },
|
|
1048
|
+
{ id: "long_rifle", team: "rifle", bus: "weapons", cutoff: 1100, gain: 1.3, seconds: 0.45 },
|
|
1049
|
+
{ id: "impact", team: "impacto", bus: "world", cutoff: 2500, gain: 0.25, seconds: 0.05 },
|
|
1050
|
+
{ id: "flesh", team: "carne", bus: "world", cutoff: 600, gain: 0.35, seconds: 0.08 },
|
|
1051
|
+
{ id: "step", team: "passo", bus: "world", cutoff: 400, gain: 0.08, seconds: 0.05 },
|
|
1052
|
+
{ id: "glass", team: "vidro", bus: "world", cutoff: 5e3, gain: 0.5, seconds: 0.3 },
|
|
1053
|
+
{ id: "wood", team: "madeira", bus: "world", cutoff: 700, gain: 0.5, seconds: 0.2 },
|
|
1054
|
+
{ id: "reload", team: "recarga", bus: "weapons", cutoff: 3e3, gain: 0.15, seconds: 0.06 },
|
|
1055
|
+
{ id: "empty", team: "vazio", bus: "weapons", cutoff: 4e3, gain: 0.12, seconds: 0.03 },
|
|
1056
|
+
{ id: "explosion", team: "explosao", bus: "world", cutoff: 200, gain: 1.6, seconds: 1.4 }
|
|
1057
|
+
],
|
|
1058
|
+
fallback: { id: "unknown", team: "(any other name)", bus: "world", cutoff: 1e3, gain: 0.5, seconds: 0.1 }
|
|
1059
|
+
};
|
|
1060
|
+
var GAME_SFX = game_sfx_default;
|
|
1061
|
+
var GAME_SFX_CLASSES = GAME_SFX.classes;
|
|
1062
|
+
var GAME_SFX_FALLBACK = GAME_SFX.fallback;
|
|
1063
|
+
function noiseClassRecipe(row, id = `sfx_${row.id}`) {
|
|
1064
|
+
return {
|
|
1065
|
+
id,
|
|
1066
|
+
bus: row.bus,
|
|
1067
|
+
order: "burst",
|
|
1068
|
+
duration: row.seconds,
|
|
1069
|
+
tail: 0.05,
|
|
1070
|
+
layers: [
|
|
1071
|
+
{
|
|
1072
|
+
source: { kind: "noise", offset: "random" },
|
|
1073
|
+
filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: row.cutoff } }] },
|
|
1074
|
+
envelope: [
|
|
1075
|
+
[0, row.gain, "set"],
|
|
1076
|
+
["1d", 1e-3, "exp", "fixed"]
|
|
1077
|
+
]
|
|
1078
|
+
}
|
|
1079
|
+
],
|
|
1080
|
+
falloff: DISTANCE_CURVES.game_sfx,
|
|
1081
|
+
sources: [...GAME_SFX.sources.map((source) => `${source} ${row.team}`)]
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
var GAME_SFX_BANK = { id: "game_sfx", sounds: [...GAME_SFX_CLASSES, GAME_SFX_FALLBACK].map((row) => noiseClassRecipe(row)) };
|
|
1085
|
+
var BENCH_BANK = {
|
|
1086
|
+
id: "audio_bench",
|
|
1087
|
+
sounds: [
|
|
1088
|
+
{
|
|
1089
|
+
id: "bench_ping",
|
|
1090
|
+
bus: "ui",
|
|
1091
|
+
pan: true,
|
|
1092
|
+
duration: 0.25,
|
|
1093
|
+
layers: [
|
|
1094
|
+
{
|
|
1095
|
+
gain: 0.5,
|
|
1096
|
+
wet: 0.3,
|
|
1097
|
+
source: { kind: "osc", wave: "sine", frequency: { from: 880 } },
|
|
1098
|
+
envelope: [
|
|
1099
|
+
[0, 1e-4, "set", "fixed"],
|
|
1100
|
+
[2e-3, 1, "exp"],
|
|
1101
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
1102
|
+
]
|
|
1103
|
+
}
|
|
1104
|
+
],
|
|
1105
|
+
falloff: DISTANCE_CURVES.art_scene,
|
|
1106
|
+
sources: ["sdk: bench probe, a 880 Hz ping through the art scene output stage"]
|
|
1107
|
+
},
|
|
1108
|
+
{
|
|
1109
|
+
id: "bench_hiss",
|
|
1110
|
+
bus: "ui",
|
|
1111
|
+
pan: true,
|
|
1112
|
+
duration: [0.3, 0.9],
|
|
1113
|
+
layers: [
|
|
1114
|
+
{
|
|
1115
|
+
gain: 0.4,
|
|
1116
|
+
source: { kind: "noise", offset: "random", offsetScale: 1.5, loop: true },
|
|
1117
|
+
filters: { mode: "serial", bank: [{ type: "highpass", frequency: { set: 3e3 }, q: 0.7 }] },
|
|
1118
|
+
envelope: [
|
|
1119
|
+
[0, 1e-4, "set", "fixed"],
|
|
1120
|
+
[2e-3, 1, "exp"],
|
|
1121
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
1122
|
+
]
|
|
1123
|
+
}
|
|
1124
|
+
],
|
|
1125
|
+
falloff: DISTANCE_CURVES.art_scene,
|
|
1126
|
+
sources: ["sdk: bench probe, a highpass hiss of random length"]
|
|
1127
|
+
}
|
|
1128
|
+
]
|
|
1129
|
+
};
|
|
1130
|
+
|
|
1131
|
+
// src/audio/recipes.ts
|
|
1132
|
+
var call = (o) => ({
|
|
1133
|
+
id: o.id,
|
|
1134
|
+
bus: "world",
|
|
1135
|
+
order: "calls",
|
|
1136
|
+
duration: o.seconds,
|
|
1137
|
+
tail: 0.02,
|
|
1138
|
+
// the page makes its gain and filter before it looks at the level
|
|
1139
|
+
keepSilent: true,
|
|
1140
|
+
layers: [
|
|
1141
|
+
{
|
|
1142
|
+
repeat: { count: o.count, spacing: o.spacing },
|
|
1143
|
+
source: { kind: "osc", wave: o.wave, frequency: { from: o.frequency, to: o.frequency * o.drop, curve: "exp", over: "duration" } },
|
|
1144
|
+
filters: { mode: "serial", bank: [{ type: "bandpass", frequency: { set: o.frequency * 1.2 }, q: 3 }] },
|
|
1145
|
+
envelope: [
|
|
1146
|
+
[0, 1e-4, "set", "fixed"],
|
|
1147
|
+
[0.015, 1, "exp"],
|
|
1148
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
1149
|
+
]
|
|
1150
|
+
}
|
|
1151
|
+
],
|
|
1152
|
+
falloff: DISTANCE_CURVES.animals,
|
|
1153
|
+
sources: [`jogo:L66625-66639 bichoSom('${o.team}')`]
|
|
1154
|
+
});
|
|
1155
|
+
var DOG_BARK = call({ id: "dog_bark", team: "latido", count: 2, spacing: 0.22, seconds: 0.12, wave: "square", frequency: 520, drop: 0.6 });
|
|
1156
|
+
var LAPWING_CALL = call({ id: "lapwing_call", team: "queroquero", count: 3, spacing: 0.14, seconds: 0.09, wave: "square", frequency: 2400, drop: 0.6 });
|
|
1157
|
+
var HEN_CLUCK = call({ id: "hen_cluck", team: "cacarejo", count: 4, spacing: 0.14, seconds: 0.09, wave: "square", frequency: 900, drop: 0.6 });
|
|
1158
|
+
var COW_MOO = call({ id: "cow_moo", team: "mugido", count: 1, spacing: 0.14, seconds: 1.2, wave: "sawtooth", frequency: 140, drop: 0.8 });
|
|
1159
|
+
var ANIMAL_SOUNDS = [DOG_BARK, LAPWING_CALL, HEN_CLUCK, COW_MOO];
|
|
1160
|
+
var ANIMAL_SOUND_BANK = { id: "animals_three", sounds: ANIMAL_SOUNDS };
|
|
1161
|
+
|
|
1162
|
+
// src/audio/calls.json
|
|
1163
|
+
var calls_default = {
|
|
1164
|
+
sources: [
|
|
1165
|
+
"jogo:L66677 galinha: cacarejo, 6 s between calls, noise 30 m",
|
|
1166
|
+
"jogo:L66680 quero-quero: queroquero when the player is near (alarme), 8 s, noise 40 m",
|
|
1167
|
+
"jogo:L66681 vaca: mugido, 30 s, noise 80 m",
|
|
1168
|
+
"jogo:L66683 cachorro: latido when a zombie is within 12 m, 3 s, noise 60 m"
|
|
1169
|
+
],
|
|
1170
|
+
species: {
|
|
1171
|
+
chicken: { sound: "hen_cluck", cooldown: 6, noiseMetres: 30 },
|
|
1172
|
+
southern_lapwing: { sound: "lapwing_call", cooldown: 8, noiseMetres: 40 },
|
|
1173
|
+
cow: { sound: "cow_moo", cooldown: 30, noiseMetres: 80 },
|
|
1174
|
+
dog: { sound: "dog_bark", cooldown: 3, noiseMetres: 60 }
|
|
1175
|
+
}
|
|
1176
|
+
};
|
|
1177
|
+
|
|
1178
|
+
// src/audio/sound.ts
|
|
1179
|
+
var DATA = calls_default;
|
|
1180
|
+
var ANIMAL_CALLS = DATA.species;
|
|
1181
|
+
var ANIMAL_CALL_SOURCES = DATA.sources;
|
|
1182
|
+
function createAnimalSound(sink, options = {}) {
|
|
1183
|
+
sink.register?.(ANIMAL_SOUND_BANK);
|
|
1184
|
+
const calls = { ...ANIMAL_CALLS, ...options.calls };
|
|
1185
|
+
const waiting = /* @__PURE__ */ new Map();
|
|
1186
|
+
const callOf = (speciesId) => calls[speciesId] ?? void 0;
|
|
1187
|
+
return {
|
|
1188
|
+
callOf,
|
|
1189
|
+
call(speciesId, position, o = {}) {
|
|
1190
|
+
const found = callOf(speciesId);
|
|
1191
|
+
if (!found) return false;
|
|
1192
|
+
const key = o.key ?? speciesId;
|
|
1193
|
+
if ((waiting.get(key) ?? 0) > 0) return false;
|
|
1194
|
+
waiting.set(key, found.cooldown);
|
|
1195
|
+
sink.play({ sound: found.sound, position, ...o.volume === void 0 ? {} : { volume: o.volume } });
|
|
1196
|
+
return true;
|
|
1197
|
+
},
|
|
1198
|
+
update(dt) {
|
|
1199
|
+
for (const [key, seconds] of waiting) {
|
|
1200
|
+
if (seconds - dt <= 0) waiting.delete(key);
|
|
1201
|
+
else waiting.set(key, seconds - dt);
|
|
1202
|
+
}
|
|
1203
|
+
},
|
|
1204
|
+
dispose: () => waiting.clear()
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
|
|
974
1208
|
// src/line-up.ts
|
|
975
1209
|
var lineUpAnimals = (rigs, options = {}) => {
|
|
976
1210
|
const start = options.start ?? -19;
|
|
@@ -1073,7 +1307,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
1073
1307
|
time_scale: "Game seconds per real second for the bite timers (60: ten minutes pass in ten seconds)"
|
|
1074
1308
|
},
|
|
1075
1309
|
options: { visual_state: { alive: "Alive", infected: "Infected", dead: "Dead" }, gait: { idle: "Idle", walk: "Walk", run: "Run" } },
|
|
1076
|
-
actions: { bite_all: "Bite every animal", recover: "Heal every animal", skin_40: "Add 40 animals as node skins", clear_skins: "Remove the skins" },
|
|
1310
|
+
actions: { bite_all: "Bite every animal", recover: "Heal every animal", call: "Make the animals with a call call (hen, lapwing, cow, dog)", skin_40: "Add 40 animals as node skins", clear_skins: "Remove the skins" },
|
|
1077
1311
|
layers: { joints: "Joints", split: "Split view", sound_range: "Sound range", carcass_lure: "Carcass lure radius" },
|
|
1078
1312
|
metrics: { animals: "Animals", draw_calls: "Draw calls", triangles: "Triangles", nodes_per_skin: "Nodes per skin", incubating: "Incubating", turned: "Turned", dead: "Dead" },
|
|
1079
1313
|
scenarios: {
|
|
@@ -1096,7 +1330,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
1096
1330
|
time_scale: "Segundos de jogo por segundo real nos prazos da mordida (60: dez minutos passam em dez segundos)"
|
|
1097
1331
|
},
|
|
1098
1332
|
options: { visual_state: { alive: "Vivo", infected: "Infectado", dead: "Morto" }, gait: { idle: "Parado", walk: "Andando", run: "Correndo" } },
|
|
1099
|
-
actions: { bite_all: "Morder todos os bichos", recover: "Curar todos os bichos", skin_40: "P\xF4r 40 bichos como pele de n\xF3s", clear_skins: "Tirar as peles" },
|
|
1333
|
+
actions: { bite_all: "Morder todos os bichos", recover: "Curar todos os bichos", call: "Fazer os bichos com chamado chamarem (galinha, quero-quero, vaca, cachorro)", skin_40: "P\xF4r 40 bichos como pele de n\xF3s", clear_skins: "Tirar as peles" },
|
|
1100
1334
|
layers: { joints: "Juntas", split: "Vista aberta", sound_range: "Alcance do som", carcass_lure: "Raio de atra\xE7\xE3o da carca\xE7a" },
|
|
1101
1335
|
metrics: { animals: "Bichos", draw_calls: "Chamadas de desenho", triangles: "Tri\xE2ngulos", nodes_per_skin: "N\xF3s por pele", incubating: "Incubando", turned: "Viraram", dead: "Morreram" },
|
|
1102
1336
|
scenarios: {
|
|
@@ -1125,6 +1359,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
1125
1359
|
let animals = null;
|
|
1126
1360
|
let host = null;
|
|
1127
1361
|
let outbreak = null;
|
|
1362
|
+
let sound = null;
|
|
1128
1363
|
let time = 0;
|
|
1129
1364
|
let clock = 0;
|
|
1130
1365
|
let skinGroup = null;
|
|
@@ -1227,6 +1462,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
1227
1462
|
delete entry.counted;
|
|
1228
1463
|
animals?.setVisualState(entry.rig, settings.visual);
|
|
1229
1464
|
}
|
|
1465
|
+
} else if (change.id === "call" && sound) {
|
|
1466
|
+
for (const [id, entry] of placed) {
|
|
1467
|
+
const at = entry.rig.root.getWorldPosition(new three.Vector3());
|
|
1468
|
+
sound.call(entry.rig.species.id, [at.x, at.y + 0.5, at.z], { key: id });
|
|
1469
|
+
}
|
|
1230
1470
|
} else if (change.id === "skin_40") addSkins();
|
|
1231
1471
|
else if (change.id === "clear_skins") clearSkins();
|
|
1232
1472
|
return;
|
|
@@ -1257,6 +1497,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
1257
1497
|
const frame = (dt) => {
|
|
1258
1498
|
time += dt * settings.speed;
|
|
1259
1499
|
clock += dt;
|
|
1500
|
+
sound?.update(dt);
|
|
1260
1501
|
for (const [id, entry] of placed) {
|
|
1261
1502
|
if (!entry.rig.root.parent) {
|
|
1262
1503
|
placed.delete(id);
|
|
@@ -1334,6 +1575,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
1334
1575
|
{ kind: "number", id: "time_scale", name: text.controls.time_scale, hint: text.hints.time_scale, min: 1, max: 600, step: 1, default: DEFAULT_TIME_SCALE },
|
|
1335
1576
|
{ kind: "action", id: "bite_all", name: text.actions.bite_all },
|
|
1336
1577
|
{ kind: "action", id: "recover", name: text.actions.recover },
|
|
1578
|
+
{ kind: "action", id: "call", name: text.actions.call },
|
|
1337
1579
|
{ kind: "action", id: "skin_40", name: text.actions.skin_40 },
|
|
1338
1580
|
{ kind: "action", id: "clear_skins", name: text.actions.clear_skins }
|
|
1339
1581
|
],
|
|
@@ -1351,6 +1593,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
1351
1593
|
attach(lent) {
|
|
1352
1594
|
host = lent;
|
|
1353
1595
|
ensure(lent.THREE);
|
|
1596
|
+
sound = lent.audio && options.sound !== false ? createAnimalSound(lent.audio, options.sound ?? {}) : null;
|
|
1354
1597
|
const stopChange = lent.bench?.onChange(onChange);
|
|
1355
1598
|
const stopFrame = lent.onFrame(frame);
|
|
1356
1599
|
return () => {
|
|
@@ -1358,6 +1601,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
1358
1601
|
stopFrame();
|
|
1359
1602
|
clearRings();
|
|
1360
1603
|
clearSkins();
|
|
1604
|
+
sound?.dispose();
|
|
1605
|
+
sound = null;
|
|
1361
1606
|
host = null;
|
|
1362
1607
|
};
|
|
1363
1608
|
}
|