@adatechnology/game-animals-three 0.3.8 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-SC4QTSML.js +1258 -0
- package/dist/chunk-SC4QTSML.js.map +1 -0
- package/dist/index.d.ts +17 -194
- package/dist/index.global.js +1986 -549
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +23 -1219
- package/dist/index.js.map +1 -1
- package/dist/testing-CjEl69y1.d.ts +184 -0
- package/dist/testing.d.ts +4 -0
- package/dist/testing.js +11 -0
- package/dist/testing.js.map +1 -0
- package/package.json +12 -7
package/dist/index.global.js
CHANGED
|
@@ -45,6 +45,1555 @@ var GameAnimalsThree = (() => {
|
|
|
45
45
|
updateSplit: () => updateSplit
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
+
// ../game-contracts/dist/index.js
|
|
49
|
+
var DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024;
|
|
50
|
+
var DEFERRED_QUEUE_ID = {
|
|
51
|
+
DESTRUCTION_EVENTS: "destruction.events",
|
|
52
|
+
BREACH_PAINT: "floorplan.breach-paint",
|
|
53
|
+
AUDIO_VOICES: "audio.voices",
|
|
54
|
+
VEHICLE_CREASE: "vehicles.crease"
|
|
55
|
+
};
|
|
56
|
+
var DEFERRED_PRIORITY = {
|
|
57
|
+
[DEFERRED_QUEUE_ID.DESTRUCTION_EVENTS]: { priority: 300, phase: "present" },
|
|
58
|
+
[DEFERRED_QUEUE_ID.BREACH_PAINT]: { priority: 250, phase: "present" },
|
|
59
|
+
[DEFERRED_QUEUE_ID.AUDIO_VOICES]: { priority: 200, phase: "idle", reserveMs: 1 },
|
|
60
|
+
[DEFERRED_QUEUE_ID.VEHICLE_CREASE]: { priority: 100, phase: "idle" }
|
|
61
|
+
};
|
|
62
|
+
var KIT_ORIGIN_KEY = "kitOrigin";
|
|
63
|
+
function markKitOrigin(object2, origin) {
|
|
64
|
+
const node = object2;
|
|
65
|
+
node.userData = node.userData ?? {};
|
|
66
|
+
node.userData[KIT_ORIGIN_KEY] = { ...origin };
|
|
67
|
+
return object2;
|
|
68
|
+
}
|
|
69
|
+
var SURFACE_IDS = ["concrete", "asphalt", "wood", "tile", "dirt", "grass", "gravel", "sand", "metal", "water", "glass", "carpet"];
|
|
70
|
+
var GAIT_IDS = ["walk", "run"];
|
|
71
|
+
var LANDING_IDS = ["light", "heavy"];
|
|
72
|
+
var BODY_SOUND_IDS = [
|
|
73
|
+
"jump",
|
|
74
|
+
"cloth_rustle",
|
|
75
|
+
"body_fall",
|
|
76
|
+
"fall_damage",
|
|
77
|
+
"player_hurt",
|
|
78
|
+
"player_breath_run",
|
|
79
|
+
"player_death",
|
|
80
|
+
"bite",
|
|
81
|
+
"grab",
|
|
82
|
+
"punch_swing",
|
|
83
|
+
"punch_hit_body",
|
|
84
|
+
"punch_hit_face",
|
|
85
|
+
"punch_hit_object",
|
|
86
|
+
"kick_swing",
|
|
87
|
+
"kick_hit",
|
|
88
|
+
"kick_hit_object",
|
|
89
|
+
"shove_two_hands",
|
|
90
|
+
"knife_swing",
|
|
91
|
+
"knife_stab",
|
|
92
|
+
"knife_slash",
|
|
93
|
+
"knife_hit_object",
|
|
94
|
+
"blunt_swing",
|
|
95
|
+
"blunt_hit",
|
|
96
|
+
"blunt_hit_object",
|
|
97
|
+
"axe_swing",
|
|
98
|
+
"axe_chop",
|
|
99
|
+
"axe_hit_object"
|
|
100
|
+
];
|
|
101
|
+
var footstepSoundId = (surface, gait) => `footstep_${surface}_${gait}`;
|
|
102
|
+
var FOOTSTEP_SOUND_IDS = SURFACE_IDS.flatMap((surface) => GAIT_IDS.map((gait) => footstepSoundId(surface, gait)));
|
|
103
|
+
var LAND_SOUND_IDS = SURFACE_IDS.flatMap((surface) => LANDING_IDS.map((landing2) => `land_${surface}_${landing2}`));
|
|
104
|
+
var BODY_FOLEY_IDS = [...FOOTSTEP_SOUND_IDS, ...LAND_SOUND_IDS, ...BODY_SOUND_IDS];
|
|
105
|
+
var SWING_LEAD_SECONDS = { punch: 0.07, kick: 0.09, shove: 0, blade: 0.05, blunt: 0.1, chop: 0.11 };
|
|
106
|
+
|
|
107
|
+
// ../game-audio/dist/chunk-7TLFY7VO.js
|
|
108
|
+
var DISTANCE_CURVES = {
|
|
109
|
+
/** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
|
|
110
|
+
game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
|
|
111
|
+
/** The game's `grito`: `1 / (1 + d² × 0.006)`, silent below 0.02 (jogo L62129–62130). */
|
|
112
|
+
game_scream: { model: "inverse_square", k: 6e-3, minGain: 0.02 },
|
|
113
|
+
/** The game's `voz`: `1 / (1 + d² × 0.01)`, silent below 0.02 (jogo L62146–62147). */
|
|
114
|
+
game_voice: { model: "inverse_square", k: 0.01, minGain: 0.02 },
|
|
115
|
+
/** The game's `boom`: `1.4 / (1 + d² × 0.002)`, never silent (jogo L68280). */
|
|
116
|
+
game_boom: { model: "inverse_square", k: 2e-3, scale: 1.4 },
|
|
117
|
+
/** The art scene's `outAt`: `vol / (1 + d² × 0.008)` (cena L1320). */
|
|
118
|
+
art_scene: { model: "inverse_square", k: 8e-3 },
|
|
119
|
+
/** The game's animal calls: `max(0, 1 − d / 70) × 0.25`, silent at or below 0.005 (jogo L66627–66628). */
|
|
120
|
+
animals: { model: "linear", range: 70, scale: 0.25, minGain: 5e-3 }
|
|
121
|
+
};
|
|
122
|
+
var game_sfx_default = {
|
|
123
|
+
sources: ["jogo:L62089-62107"],
|
|
124
|
+
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`.",
|
|
125
|
+
classes: [
|
|
126
|
+
{ id: "pistol", team: "pistola", bus: "weapons", cutoff: 1800, gain: 0.9, seconds: 0.18 },
|
|
127
|
+
{ id: "shotgun", team: "escopeta", bus: "weapons", cutoff: 900, gain: 1.2, seconds: 0.35 },
|
|
128
|
+
{ id: "rifle", team: "fuzil", bus: "weapons", cutoff: 1400, gain: 1.1, seconds: 0.28 },
|
|
129
|
+
{ id: "long_rifle", team: "rifle", bus: "weapons", cutoff: 1100, gain: 1.3, seconds: 0.45 },
|
|
130
|
+
{ id: "impact", team: "impacto", bus: "world", cutoff: 2500, gain: 0.25, seconds: 0.05 },
|
|
131
|
+
{ id: "flesh", team: "carne", bus: "world", cutoff: 600, gain: 0.35, seconds: 0.08 },
|
|
132
|
+
{ id: "step", team: "passo", bus: "world", cutoff: 400, gain: 0.08, seconds: 0.05 },
|
|
133
|
+
{ id: "glass", team: "vidro", bus: "world", cutoff: 5e3, gain: 0.5, seconds: 0.3 },
|
|
134
|
+
{ id: "wood", team: "madeira", bus: "world", cutoff: 700, gain: 0.5, seconds: 0.2 },
|
|
135
|
+
{ id: "reload", team: "recarga", bus: "weapons", cutoff: 3e3, gain: 0.15, seconds: 0.06 },
|
|
136
|
+
{ id: "empty", team: "vazio", bus: "weapons", cutoff: 4e3, gain: 0.12, seconds: 0.03 },
|
|
137
|
+
{ id: "explosion", team: "explosao", bus: "world", cutoff: 200, gain: 1.6, seconds: 1.4 }
|
|
138
|
+
],
|
|
139
|
+
fallback: { id: "unknown", team: "(any other name)", bus: "world", cutoff: 1e3, gain: 0.5, seconds: 0.1 }
|
|
140
|
+
};
|
|
141
|
+
var GAME_SFX = game_sfx_default;
|
|
142
|
+
var GAME_SFX_CLASSES = GAME_SFX.classes;
|
|
143
|
+
var GAME_SFX_FALLBACK = GAME_SFX.fallback;
|
|
144
|
+
function noiseClassRecipe(row, id = `sfx_${row.id}`) {
|
|
145
|
+
return {
|
|
146
|
+
id,
|
|
147
|
+
bus: row.bus,
|
|
148
|
+
order: "burst",
|
|
149
|
+
duration: row.seconds,
|
|
150
|
+
tail: 0.05,
|
|
151
|
+
layers: [
|
|
152
|
+
{
|
|
153
|
+
source: { kind: "noise", offset: "random" },
|
|
154
|
+
filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: row.cutoff } }] },
|
|
155
|
+
envelope: [
|
|
156
|
+
[0, row.gain, "set"],
|
|
157
|
+
["1d", 1e-3, "exp", "fixed"]
|
|
158
|
+
]
|
|
159
|
+
}
|
|
160
|
+
],
|
|
161
|
+
falloff: DISTANCE_CURVES.game_sfx,
|
|
162
|
+
sources: [...GAME_SFX.sources.map((source) => `${source} ${row.team}`)]
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
var GAME_SFX_BANK = { id: "game_sfx", sounds: [...GAME_SFX_CLASSES, GAME_SFX_FALLBACK].map((row) => noiseClassRecipe(row)) };
|
|
166
|
+
var mix_profiles_default = [
|
|
167
|
+
{
|
|
168
|
+
id: "game",
|
|
169
|
+
master: 0.5,
|
|
170
|
+
noise: {
|
|
171
|
+
seconds: 1.5,
|
|
172
|
+
create: "lazy"
|
|
173
|
+
},
|
|
174
|
+
sources: [
|
|
175
|
+
"jogo:L62077-62081 master 0.5 to the output",
|
|
176
|
+
"jogo:L62082-62088 noise 1.5 s made by the first sound that needs it"
|
|
177
|
+
]
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
id: "art_scene",
|
|
181
|
+
master: 0.85,
|
|
182
|
+
compressor: {
|
|
183
|
+
threshold: -12,
|
|
184
|
+
ratio: 5
|
|
185
|
+
},
|
|
186
|
+
reverb: {
|
|
187
|
+
seconds: 2.2,
|
|
188
|
+
decay: 3.4,
|
|
189
|
+
wet: 0.4
|
|
190
|
+
},
|
|
191
|
+
noise: {
|
|
192
|
+
seconds: 2,
|
|
193
|
+
create: "eager"
|
|
194
|
+
},
|
|
195
|
+
sources: [
|
|
196
|
+
"cena:L1308 compressor -12 dB, ratio 5",
|
|
197
|
+
"cena:L1309 master 0.85",
|
|
198
|
+
"cena:L1310 convolver, impulse 2.2 s of (1 - i/len)^3.4",
|
|
199
|
+
"cena:L1311 wet 0.4",
|
|
200
|
+
"cena:L1312 noise 2 s made with the chain"
|
|
201
|
+
]
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
id: "kit",
|
|
205
|
+
master: 0.85,
|
|
206
|
+
compressor: {
|
|
207
|
+
threshold: -12,
|
|
208
|
+
ratio: 5
|
|
209
|
+
},
|
|
210
|
+
reverb: {
|
|
211
|
+
seconds: 2.2,
|
|
212
|
+
decay: 3.4,
|
|
213
|
+
wet: 0.4
|
|
214
|
+
},
|
|
215
|
+
noise: {
|
|
216
|
+
seconds: 2,
|
|
217
|
+
create: "eager"
|
|
218
|
+
},
|
|
219
|
+
sources: [
|
|
220
|
+
"sdk: the art scene chain (cena L1308-L1312) with a limiter after the compressor: the page has none, and a blast with its debris and a fire catching reached +7 dBFS"
|
|
221
|
+
],
|
|
222
|
+
limiter: {
|
|
223
|
+
ceiling: -1,
|
|
224
|
+
knee: -6
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
];
|
|
228
|
+
var MIX_PROFILES = Object.fromEntries(
|
|
229
|
+
mix_profiles_default.map((profile) => [profile.id, profile])
|
|
230
|
+
);
|
|
231
|
+
var BENCH_BANK = {
|
|
232
|
+
id: "audio_bench",
|
|
233
|
+
sounds: [
|
|
234
|
+
{
|
|
235
|
+
id: "bench_ping",
|
|
236
|
+
bus: "ui",
|
|
237
|
+
pan: true,
|
|
238
|
+
duration: 0.25,
|
|
239
|
+
layers: [
|
|
240
|
+
{
|
|
241
|
+
gain: 0.5,
|
|
242
|
+
wet: 0.3,
|
|
243
|
+
source: { kind: "osc", wave: "sine", frequency: { from: 880 } },
|
|
244
|
+
envelope: [
|
|
245
|
+
[0, 1e-4, "set", "fixed"],
|
|
246
|
+
[2e-3, 1, "exp"],
|
|
247
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
248
|
+
]
|
|
249
|
+
}
|
|
250
|
+
],
|
|
251
|
+
falloff: DISTANCE_CURVES.art_scene,
|
|
252
|
+
sources: ["sdk: bench probe, a 880 Hz ping through the art scene output stage"]
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
id: "bench_hiss",
|
|
256
|
+
bus: "ui",
|
|
257
|
+
pan: true,
|
|
258
|
+
duration: [0.3, 0.9],
|
|
259
|
+
layers: [
|
|
260
|
+
{
|
|
261
|
+
gain: 0.4,
|
|
262
|
+
source: { kind: "noise", offset: "random", offsetScale: 1.5, loop: true },
|
|
263
|
+
filters: { mode: "serial", bank: [{ type: "highpass", frequency: { set: 3e3 }, q: 0.7 }] },
|
|
264
|
+
envelope: [
|
|
265
|
+
[0, 1e-4, "set", "fixed"],
|
|
266
|
+
[2e-3, 1, "exp"],
|
|
267
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
268
|
+
]
|
|
269
|
+
}
|
|
270
|
+
],
|
|
271
|
+
falloff: DISTANCE_CURVES.art_scene,
|
|
272
|
+
sources: ["sdk: bench probe, a highpass hiss of random length"]
|
|
273
|
+
}
|
|
274
|
+
]
|
|
275
|
+
};
|
|
276
|
+
var entries = (category, list2) => list2.map(([id, priority, current]) => ({ id, category, priority, ...current ? { current } : {} }));
|
|
277
|
+
var SFX_CATALOG = [
|
|
278
|
+
...entries("armas", [
|
|
279
|
+
["pistol_22lr", 2, "sfx_pistol"],
|
|
280
|
+
["pistol_9mm", 1, "sfx_pistol"],
|
|
281
|
+
["pistol_45", 1, "sfx_pistol"],
|
|
282
|
+
["revolver_38_357", 2, "sfx_pistol"],
|
|
283
|
+
["revolver_44_50ae", 3, "sfx_pistol"],
|
|
284
|
+
["smg_9mm_auto", 1, "sfx_pistol"],
|
|
285
|
+
["shotgun_12", 1, "sfx_shotgun"],
|
|
286
|
+
["rifle_5_56", 1, "sfx_rifle"],
|
|
287
|
+
["rifle_7_62x39", 1, "sfx_rifle"],
|
|
288
|
+
["rifle_auto_burst", 1, "sfx_rifle"],
|
|
289
|
+
["rifle_308_3006", 2, "sfx_rifle"],
|
|
290
|
+
["sniper_338_300wm", 2, "sfx_rifle"],
|
|
291
|
+
["antimateriel_50bmg", 3, "sfx_rifle"],
|
|
292
|
+
["suppressed_pistol", 2],
|
|
293
|
+
["suppressed_rifle", 2],
|
|
294
|
+
["gunshot_far_pistol", 1],
|
|
295
|
+
["gunshot_far_rifle", 1],
|
|
296
|
+
["gunshot_far_shotgun", 1],
|
|
297
|
+
["gunshot_far_heavy", 2],
|
|
298
|
+
["gunshot_tail_indoor", 1],
|
|
299
|
+
["gunshot_tail_outdoor", 1],
|
|
300
|
+
["bullet_crack_by", 2],
|
|
301
|
+
["bullet_whiz", 2],
|
|
302
|
+
["ricochet_metal", 2, "ping"],
|
|
303
|
+
["dry_fire", 1],
|
|
304
|
+
["mag_out", 1],
|
|
305
|
+
["mag_in", 1],
|
|
306
|
+
["slide_pull_release", 1],
|
|
307
|
+
["pump_cycle", 1],
|
|
308
|
+
["casing_drop_concreto_pistol", 1],
|
|
309
|
+
["casing_drop_concreto_rifle", 1],
|
|
310
|
+
["casing_drop_concreto_shell", 1],
|
|
311
|
+
["casing_drop_madeira_pistol", 1],
|
|
312
|
+
["casing_drop_madeira_rifle", 1],
|
|
313
|
+
["casing_drop_madeira_shell", 1],
|
|
314
|
+
["casing_drop_metal_pistol", 1],
|
|
315
|
+
["casing_drop_metal_rifle", 1],
|
|
316
|
+
["casing_drop_metal_shell", 1],
|
|
317
|
+
["casing_drop_terra_pistol", 1],
|
|
318
|
+
["casing_drop_terra_rifle", 1],
|
|
319
|
+
["casing_drop_terra_shell", 1],
|
|
320
|
+
["rocket_fire", 2]
|
|
321
|
+
]),
|
|
322
|
+
...entries("explosoes-fogo", [
|
|
323
|
+
["explosion_grenade", 1, "boom"],
|
|
324
|
+
["explosion_big", 1, "boom_big"],
|
|
325
|
+
["explosion_car", 2, "boom_big"],
|
|
326
|
+
["explosion_far", 1],
|
|
327
|
+
["debris_rain_stone", 1],
|
|
328
|
+
["molotov_break_ignite", 1, "glass_shatter"],
|
|
329
|
+
["fire_ignite", 1, "hiss"],
|
|
330
|
+
["fire_loop_small", 1],
|
|
331
|
+
["fire_loop_large", 1],
|
|
332
|
+
["fire_extinguish", 2, "hiss"],
|
|
333
|
+
["gas_leak_hiss", 2],
|
|
334
|
+
["structure_collapse", 2, "crumble"]
|
|
335
|
+
]),
|
|
336
|
+
...entries("personagem", [
|
|
337
|
+
["footstep_concrete_walk", 1, "sfx_step"],
|
|
338
|
+
["footstep_wood_walk", 1, "sfx_step"],
|
|
339
|
+
["footstep_dirt_walk", 1, "sfx_step"],
|
|
340
|
+
["footstep_grass_walk", 1, "sfx_step"],
|
|
341
|
+
["footstep_gravel_walk", 1, "sfx_step"],
|
|
342
|
+
["land_concrete", 1, "sfx_step"],
|
|
343
|
+
["punch_swing", 1],
|
|
344
|
+
["punch_hit_body", 1, "sfx_flesh"],
|
|
345
|
+
["kick_hit", 1, "sfx_flesh"],
|
|
346
|
+
["knife_stab", 1],
|
|
347
|
+
["blunt_hit", 1],
|
|
348
|
+
["bite", 1, "sfx_flesh"],
|
|
349
|
+
["body_fall", 1],
|
|
350
|
+
["player_hurt", 2]
|
|
351
|
+
]),
|
|
352
|
+
...entries("veiculos", [
|
|
353
|
+
["engine_loop_car", 1],
|
|
354
|
+
["engine_start", 1],
|
|
355
|
+
["crash_light", 1, "crash"],
|
|
356
|
+
["crash_heavy", 1, "crash"],
|
|
357
|
+
["car_door_open", 1, "latch"],
|
|
358
|
+
["car_door_close", 1, "shut_metal"],
|
|
359
|
+
["horn_car", 2, "horn"],
|
|
360
|
+
["tire_skid_asphalt", 2]
|
|
361
|
+
]),
|
|
362
|
+
...entries("itens-portas", [
|
|
363
|
+
["item_pickup_metal", 1],
|
|
364
|
+
["can_open", 1],
|
|
365
|
+
["can_crush", 1],
|
|
366
|
+
["door_wood_open", 1, "latch"],
|
|
367
|
+
["door_wood_close", 1, "shut_wood"],
|
|
368
|
+
["door_creak", 1, "creak_wood"],
|
|
369
|
+
["door_locked_rattle", 1, "rattle"],
|
|
370
|
+
["drawer_open", 2, "slide"],
|
|
371
|
+
["fridge_close", 2, "shut_metal"]
|
|
372
|
+
]),
|
|
373
|
+
...entries("ambiente", [
|
|
374
|
+
["rain_loop", 2],
|
|
375
|
+
["wind_loop", 2],
|
|
376
|
+
["thunder_near", 2],
|
|
377
|
+
["thunder_far", 2],
|
|
378
|
+
["water_splash", 2]
|
|
379
|
+
])
|
|
380
|
+
];
|
|
381
|
+
var SFX_MATERIALS = [
|
|
382
|
+
["steel", "metal"],
|
|
383
|
+
["aluminium", "metal"],
|
|
384
|
+
["wood", "wood"],
|
|
385
|
+
["plywood", "wood"],
|
|
386
|
+
["mdf", "wood"],
|
|
387
|
+
["glass", "glass"],
|
|
388
|
+
["tempered_glass", "glass"],
|
|
389
|
+
["ceramic", "glass"],
|
|
390
|
+
["concrete", "masonry"],
|
|
391
|
+
["brick", "masonry"],
|
|
392
|
+
["plaster", "masonry"],
|
|
393
|
+
["plastic", "soft"],
|
|
394
|
+
["fabric", "soft"],
|
|
395
|
+
["paper", "soft"],
|
|
396
|
+
["foliage", "soft"],
|
|
397
|
+
["soil", "soft"],
|
|
398
|
+
["flesh", "soft"]
|
|
399
|
+
];
|
|
400
|
+
var SFX_BLOWS = ["bullet", "blunt", "blade", "break", "drag"];
|
|
401
|
+
var CURRENT_BY_GROUP = {
|
|
402
|
+
metal: { bullet: "clang", blunt: "clang", blade: "clang", break: "clang", drag: "drag_metal" },
|
|
403
|
+
wood: { bullet: "wood_hit", blunt: "wood_hit", blade: "wood_hit", break: "crack", drag: "drag_wood" },
|
|
404
|
+
glass: { bullet: "ping", blunt: "ping", break: "glass_shatter", drag: "drag_glass" },
|
|
405
|
+
masonry: { bullet: "chip", blunt: "chip", blade: "chip", break: "crumble", drag: "drag_masonry" },
|
|
406
|
+
soft: { bullet: "thud", blunt: "thud", blade: "thud", break: "thud", drag: "drag_soft" }
|
|
407
|
+
};
|
|
408
|
+
var impactSoundId = (material, blow) => `impact_${material}_${blow}`;
|
|
409
|
+
var SFX_IMPACTS = SFX_MATERIALS.flatMap(
|
|
410
|
+
([material, group]) => SFX_BLOWS.map((blow) => {
|
|
411
|
+
const current = CURRENT_BY_GROUP[group]?.[blow];
|
|
412
|
+
return { id: impactSoundId(material, blow), category: "impactos", priority: ["steel", "wood", "glass", "concrete", "brick", "soil", "flesh"].includes(material) && blow === "bullet" ? 1 : 2, ...current ? { current } : {} };
|
|
413
|
+
})
|
|
414
|
+
);
|
|
415
|
+
var CALIBRATION_ID = "calibration_shot";
|
|
416
|
+
var PREFIX = "calibration/";
|
|
417
|
+
var url = (name) => `${PREFIX}${name}`;
|
|
418
|
+
var CALIBRATION_SOUND = {
|
|
419
|
+
id: CALIBRATION_ID,
|
|
420
|
+
bus: "weapons",
|
|
421
|
+
close: ["close_1.wav", "close_2.wav", "close_3.wav", "close_4.wav"].map((name) => ({ url: url(name) })),
|
|
422
|
+
far: ["far_1.wav", "far_2.wav"].map((name) => ({ url: url(name) })),
|
|
423
|
+
tiers: [
|
|
424
|
+
{ name: "light", from: 0, close: ["light_1.wav", "light_2.wav"].map((name) => ({ url: url(name) })) },
|
|
425
|
+
{ name: "medium", from: 0.34, close: ["close_1.wav", "close_2.wav", "close_3.wav", "close_4.wav"].map((name) => ({ url: url(name) })) },
|
|
426
|
+
{ name: "heavy", from: 0.67, close: ["heavy_1.wav", "heavy_2.wav"].map((name) => ({ url: url(name) })) }
|
|
427
|
+
],
|
|
428
|
+
tail: { indoor: [{ url: url("tail_in.wav") }], outdoor: [{ url: url("tail_out.wav") }] },
|
|
429
|
+
pitch: 0.04,
|
|
430
|
+
choke: { voices: 2 },
|
|
431
|
+
fallback: "sfx_pistol",
|
|
432
|
+
sources: ["sdk: calibration takes synthesized by the harness (measure/calibration.ts), no file, no licence"]
|
|
433
|
+
};
|
|
434
|
+
var CALIBRATION_LOOP_ID = "calibration_loop";
|
|
435
|
+
var CALIBRATION_LOOP_SOUND = {
|
|
436
|
+
id: CALIBRATION_LOOP_ID,
|
|
437
|
+
bus: "ambience",
|
|
438
|
+
close: ["loop_1.wav", "loop_2.wav", "loop_3.wav"].map((name) => ({ url: url(name) })),
|
|
439
|
+
loop: { crossfade: 0.15 },
|
|
440
|
+
sources: ["sdk: calibration takes synthesized by the harness (measure/calibration.ts), no file, no licence"]
|
|
441
|
+
};
|
|
442
|
+
var CRITERIA_TARGETS = {
|
|
443
|
+
/** C1: event to the first sample, and onset to the peak (one 60 fps frame). */
|
|
444
|
+
syncMs: 20,
|
|
445
|
+
peakAfterOnsetMs: 1e3 / 60,
|
|
446
|
+
/** C3: distances measured, metres. */
|
|
447
|
+
distances: [1, 10, 50, 200],
|
|
448
|
+
/** C5: plays, distinct takes and the pitch range (fraction). */
|
|
449
|
+
plays: 10,
|
|
450
|
+
minTakes: 4,
|
|
451
|
+
pitch: [0.03, 0.05],
|
|
452
|
+
/** C6: the highest peak, dBFS. */
|
|
453
|
+
peakDb: -1,
|
|
454
|
+
/** C8: the end of each file against its peak, dB. */
|
|
455
|
+
endDropDb: -40,
|
|
456
|
+
/** C9: a burst of rapid fire. */
|
|
457
|
+
burst: 20,
|
|
458
|
+
burstSpacing: 0.06
|
|
459
|
+
};
|
|
460
|
+
var PT = {
|
|
461
|
+
group: "Som",
|
|
462
|
+
name: "Painel de som (arquivos e C1\u2013C10)",
|
|
463
|
+
controls: {
|
|
464
|
+
category: "1 \xB7 Categoria",
|
|
465
|
+
sound: "1 \xB7 Som",
|
|
466
|
+
play: "1 \xB7 \u25B6 Tocar",
|
|
467
|
+
material: "2 \xB7 Material",
|
|
468
|
+
blow: "2 \xB7 Golpe",
|
|
469
|
+
strike: "2 \xB7 \u25B6 Tocar golpe",
|
|
470
|
+
distance: "3 \xB7 Dist\xE2ncia",
|
|
471
|
+
bearing: "3 \xB7 Dire\xE7\xE3o",
|
|
472
|
+
environment: "3 \xB7 Lugar",
|
|
473
|
+
strength: "3 \xB7 For\xE7a",
|
|
474
|
+
wall: "3 \xB7 Atr\xE1s da parede",
|
|
475
|
+
burst: "3 \xB7 Rajada 20\xD7",
|
|
476
|
+
play_a: "4 \xB7 \u25B6 A (atual)",
|
|
477
|
+
play_b: "4 \xB7 \u25B6 B (novo)",
|
|
478
|
+
ab_cycle: "4 \xB7 Alternar A/B",
|
|
479
|
+
blind: "4 \xB7 \xC0s cegas (X)",
|
|
480
|
+
reveal: "4 \xB7 Revelar X",
|
|
481
|
+
prefer_a: "4 \xB7 Prefiro A",
|
|
482
|
+
prefer_b: "4 \xB7 Prefiro B",
|
|
483
|
+
measure: "5 \xB7 Medir C1\u2013C10",
|
|
484
|
+
record: "5 \xB7 Gravar 3 s",
|
|
485
|
+
approve: "5 \xB7 Aprovo (C10)"
|
|
486
|
+
},
|
|
487
|
+
hints: {
|
|
488
|
+
sound: "A = arquivo, S = sintetizado, F = faltando. O que tem arquivo toca o arquivo; o resto toca o som atual.",
|
|
489
|
+
strike: "Toca impact_<material>_<golpe>: o arquivo se existir, sen\xE3o o som atual daquele material.",
|
|
490
|
+
wall: "P\xF5e a parede de casa entre voc\xEA e a fonte: o som fica abafado (C4).",
|
|
491
|
+
burst: "Vinte vezes a cada 60 ms, como uma rajada (C9).",
|
|
492
|
+
ab_cycle: "A, B, A, B, um por segundo.",
|
|
493
|
+
blind: "Toca A ou B sem dizer qual; depois revele.",
|
|
494
|
+
measure: "Mede o som escolhido no motor real (contexto offline): sincronia, som certo, dist\xE2ncia, lado, varia\xE7\xE3o, volume, for\xE7a, cauda e rajada.",
|
|
495
|
+
record: "Grava 3 s da sa\xEDda com o som tocando e baixa o arquivo (C10).",
|
|
496
|
+
approve: "Marca o C10 do som escolhido como aprovado pelo seu ouvido."
|
|
497
|
+
},
|
|
498
|
+
categories: {
|
|
499
|
+
armas: "Armas",
|
|
500
|
+
impactos: "Impactos",
|
|
501
|
+
"explosoes-fogo": "Explos\xF5es e fogo",
|
|
502
|
+
personagem: "Personagem",
|
|
503
|
+
veiculos: "Ve\xEDculos",
|
|
504
|
+
"itens-portas": "Itens e portas",
|
|
505
|
+
ambiente: "Ambiente",
|
|
506
|
+
calibracao: "Calibra\xE7\xE3o (SDK)"
|
|
507
|
+
},
|
|
508
|
+
blows: { bullet: "tiro", blunt: "soco/chute", blade: "faca", break: "quebra", drag: "arrasto/queda" },
|
|
509
|
+
materials: {
|
|
510
|
+
steel: "a\xE7o",
|
|
511
|
+
aluminium: "alum\xEDnio",
|
|
512
|
+
wood: "madeira",
|
|
513
|
+
plywood: "compensado",
|
|
514
|
+
mdf: "MDF",
|
|
515
|
+
glass: "vidro",
|
|
516
|
+
tempered_glass: "vidro temperado",
|
|
517
|
+
ceramic: "cer\xE2mica",
|
|
518
|
+
concrete: "concreto",
|
|
519
|
+
brick: "tijolo",
|
|
520
|
+
plaster: "gesso",
|
|
521
|
+
plastic: "pl\xE1stico",
|
|
522
|
+
fabric: "tecido",
|
|
523
|
+
paper: "papel\xE3o",
|
|
524
|
+
foliage: "folhagem",
|
|
525
|
+
soil: "terra",
|
|
526
|
+
flesh: "carne"
|
|
527
|
+
},
|
|
528
|
+
environments: { indoor: "interior", outdoor: "exterior" },
|
|
529
|
+
strengths: { light: "leve", medium: "m\xE9dio", heavy: "forte" },
|
|
530
|
+
states: { file: "A", synth: "S", missing: "F" },
|
|
531
|
+
criteria: { C1: "C1 Sincronia", C2: "C2 Certo p/ a\xE7\xE3o", C3: "C3 Dist\xE2ncia", C4: "C4 Posi\xE7\xE3o", C5: "C5 Varia\xE7\xE3o", C6: "C6 Volume", C7: "C7 Intensidade", C8: "C8 Cauda", C9: "C9 Rajada", C10: "C10 Escuta" },
|
|
532
|
+
metrics: { chosen: "1 \xB7 Escolhido", matrix: "2 \xB7 Matriz", last: "\xDAltimo tocado", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Prefer\xEAncias", state: "5 \xB7 Medi\xE7\xE3o", count: "1 \xB7 Cat\xE1logo" },
|
|
533
|
+
run: { idle: "parada", measuring: "medindo\u2026", done: "pronta", failed: "falhou", recording: "gravando\u2026", recorded: "grava\xE7\xE3o baixada" },
|
|
534
|
+
words: { none: "\u2014", hidden: "? (revele)", prefers: "prefere", approved: "aprovado pelo dono" },
|
|
535
|
+
probe: "Fonte do som",
|
|
536
|
+
wall: "Parede (oclus\xE3o)",
|
|
537
|
+
scenarios: { pipeline: "Arquivo \u2192 decodifica \u2192 toca (round-robin, cauda)", criteria: "Crit\xE9rios C1\u2013C9 no som de calibra\xE7\xE3o", loop: "Loop de arquivo: emenda sem buraco (crossfade)", panel: "Painel: categorias, matriz, A/B e parede" }
|
|
538
|
+
};
|
|
539
|
+
var EN2 = {
|
|
540
|
+
...PT,
|
|
541
|
+
group: "Sound",
|
|
542
|
+
name: "Sound panel (files and C1\u2013C10)",
|
|
543
|
+
controls: {
|
|
544
|
+
category: "1 \xB7 Category",
|
|
545
|
+
sound: "1 \xB7 Sound",
|
|
546
|
+
play: "1 \xB7 \u25B6 Play",
|
|
547
|
+
material: "2 \xB7 Material",
|
|
548
|
+
blow: "2 \xB7 Blow",
|
|
549
|
+
strike: "2 \xB7 \u25B6 Play blow",
|
|
550
|
+
distance: "3 \xB7 Distance",
|
|
551
|
+
bearing: "3 \xB7 Bearing",
|
|
552
|
+
environment: "3 \xB7 Place",
|
|
553
|
+
strength: "3 \xB7 Strength",
|
|
554
|
+
wall: "3 \xB7 Behind the wall",
|
|
555
|
+
burst: "3 \xB7 Burst 20\xD7",
|
|
556
|
+
play_a: "4 \xB7 \u25B6 A (current)",
|
|
557
|
+
play_b: "4 \xB7 \u25B6 B (new)",
|
|
558
|
+
ab_cycle: "4 \xB7 Alternate A/B",
|
|
559
|
+
blind: "4 \xB7 Blind (X)",
|
|
560
|
+
reveal: "4 \xB7 Reveal X",
|
|
561
|
+
prefer_a: "4 \xB7 Prefer A",
|
|
562
|
+
prefer_b: "4 \xB7 Prefer B",
|
|
563
|
+
measure: "5 \xB7 Measure C1\u2013C10",
|
|
564
|
+
record: "5 \xB7 Record 3 s",
|
|
565
|
+
approve: "5 \xB7 Approve (C10)"
|
|
566
|
+
},
|
|
567
|
+
hints: {
|
|
568
|
+
sound: "A = file, S = synthesized, F = missing. A file plays the file; the rest plays the current sound.",
|
|
569
|
+
strike: "Plays impact_<material>_<blow>: the file if there is one, else the current sound of that material.",
|
|
570
|
+
wall: "Puts the house wall between you and the source: the sound is muffled (C4).",
|
|
571
|
+
burst: "Twenty times every 60 ms, like a burst (C9).",
|
|
572
|
+
ab_cycle: "A, B, A, B, one a second.",
|
|
573
|
+
blind: "Plays A or B without saying which; reveal it after.",
|
|
574
|
+
measure: "Measures the chosen sound through the real engine (offline context): sync, right sound, distance, side, variation, level, strength, tail and burst.",
|
|
575
|
+
record: "Records 3 s of the output with the sound playing and downloads it (C10).",
|
|
576
|
+
approve: "Marks C10 of the chosen sound as approved by your ear."
|
|
577
|
+
},
|
|
578
|
+
categories: { armas: "Weapons", impactos: "Impacts", "explosoes-fogo": "Explosions and fire", personagem: "Character", veiculos: "Vehicles", "itens-portas": "Items and doors", ambiente: "Ambience", calibracao: "Calibration (SDK)" },
|
|
579
|
+
blows: { bullet: "bullet", blunt: "punch/kick", blade: "knife", break: "break", drag: "drag/fall" },
|
|
580
|
+
materials: {
|
|
581
|
+
steel: "steel",
|
|
582
|
+
aluminium: "aluminium",
|
|
583
|
+
wood: "wood",
|
|
584
|
+
plywood: "plywood",
|
|
585
|
+
mdf: "MDF",
|
|
586
|
+
glass: "glass",
|
|
587
|
+
tempered_glass: "tempered glass",
|
|
588
|
+
ceramic: "ceramic",
|
|
589
|
+
concrete: "concrete",
|
|
590
|
+
brick: "brick",
|
|
591
|
+
plaster: "plaster",
|
|
592
|
+
plastic: "plastic",
|
|
593
|
+
fabric: "fabric",
|
|
594
|
+
paper: "cardboard",
|
|
595
|
+
foliage: "foliage",
|
|
596
|
+
soil: "soil",
|
|
597
|
+
flesh: "flesh"
|
|
598
|
+
},
|
|
599
|
+
environments: { indoor: "indoor", outdoor: "outdoor" },
|
|
600
|
+
strengths: { light: "light", medium: "medium", heavy: "heavy" },
|
|
601
|
+
criteria: { C1: "C1 Sync", C2: "C2 Right sound", C3: "C3 Distance", C4: "C4 Position", C5: "C5 Variation", C6: "C6 Level", C7: "C7 Strength", C8: "C8 Tail", C9: "C9 Burst", C10: "C10 Listening" },
|
|
602
|
+
metrics: { chosen: "1 \xB7 Chosen", matrix: "2 \xB7 Matrix", last: "Last played", ab: "4 \xB7 A \xD7 B", blind: "4 \xB7 X", verdicts: "4 \xB7 Preferences", state: "5 \xB7 Measurement", count: "1 \xB7 Catalogue" },
|
|
603
|
+
run: { idle: "idle", measuring: "measuring\u2026", done: "done", failed: "failed", recording: "recording\u2026", recorded: "recording downloaded" },
|
|
604
|
+
words: { none: "\u2014", hidden: "? (reveal)", prefers: "prefers", approved: "approved by the owner" },
|
|
605
|
+
probe: "Sound source",
|
|
606
|
+
wall: "Wall (occlusion)",
|
|
607
|
+
scenarios: { pipeline: "File \u2192 decode \u2192 play (round-robin, tail)", criteria: "Criteria C1\u2013C9 on the calibration sound", loop: "File loop: seamless joins (crossfade)", panel: "Panel: categories, matrix, A/B and wall" }
|
|
608
|
+
};
|
|
609
|
+
|
|
610
|
+
// ../game-audio/dist/index.js
|
|
611
|
+
var ATTACK = 2e-3;
|
|
612
|
+
function lengthOf(d, attack) {
|
|
613
|
+
if (typeof d === "number") return attack + d;
|
|
614
|
+
if (Array.isArray(d)) return [attack + d[0], attack + d[1]];
|
|
615
|
+
return { ...d, add: (d.add ?? 0) + attack };
|
|
616
|
+
}
|
|
617
|
+
var envelope = (attack) => [
|
|
618
|
+
[0, 1e-4, "set", "fixed"],
|
|
619
|
+
[attack, 1, "exp"],
|
|
620
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
621
|
+
];
|
|
622
|
+
function sceneNoise(o) {
|
|
623
|
+
const a = o.a ?? ATTACK;
|
|
624
|
+
const over = typeof o.d === "number" ? o.d : 0;
|
|
625
|
+
return {
|
|
626
|
+
filters: {
|
|
627
|
+
mode: "serial",
|
|
628
|
+
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 }]
|
|
629
|
+
},
|
|
630
|
+
duration: lengthOf(o.d, a),
|
|
631
|
+
gain: o.vol,
|
|
632
|
+
...o.delay === void 0 ? {} : { at: o.delay },
|
|
633
|
+
...o.wet === void 0 ? {} : { wet: o.wet },
|
|
634
|
+
source: { kind: "noise", offset: "random", offsetScale: 1.5, loop: true },
|
|
635
|
+
envelope: envelope(a)
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
function sceneTone(o) {
|
|
639
|
+
return {
|
|
640
|
+
source: { kind: "osc", wave: o.wave ?? "sine", frequency: { from: o.f, to: o.f2 ?? "from", curve: "exp", over: "duration" } },
|
|
641
|
+
duration: lengthOf(o.d, ATTACK),
|
|
642
|
+
gain: o.vol,
|
|
643
|
+
...o.delay === void 0 ? {} : { at: o.delay },
|
|
644
|
+
...o.wet === void 0 ? {} : { wet: o.wet },
|
|
645
|
+
envelope: envelope(ATTACK)
|
|
646
|
+
};
|
|
647
|
+
}
|
|
648
|
+
function sceneVoice(o) {
|
|
649
|
+
return {
|
|
650
|
+
duration: lengthOf(o.d, 0),
|
|
651
|
+
gain: o.vol,
|
|
652
|
+
wet: 0.45,
|
|
653
|
+
source: {
|
|
654
|
+
kind: "formant_voice",
|
|
655
|
+
wave: o.wave ?? "sawtooth",
|
|
656
|
+
frequency: { from: o.f0, to: o.f1, curve: "linear", over: "duration" },
|
|
657
|
+
vibrato: { rate: [4, 10], depth: 0.08 },
|
|
658
|
+
formants: [
|
|
659
|
+
{ frequency: o.fA, q: 4 },
|
|
660
|
+
{ frequency: o.fB, q: 6 }
|
|
661
|
+
],
|
|
662
|
+
breath: { frequency: o.fB, q: 1.1, gain: o.noise },
|
|
663
|
+
mix: 3.2
|
|
664
|
+
},
|
|
665
|
+
envelope: [
|
|
666
|
+
[0, 1e-4, "set", "fixed"],
|
|
667
|
+
[0.1, 1, "exp"],
|
|
668
|
+
["0.6d", 1, "set"],
|
|
669
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
670
|
+
]
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
var sceneMany = (count, make2) => Array.from({ length: count }, make2);
|
|
674
|
+
var FOLEY_FALLOFF = {
|
|
675
|
+
model: "inverse_square",
|
|
676
|
+
k: 0.02,
|
|
677
|
+
cutoffK: 0.04,
|
|
678
|
+
minGain: 4e-3
|
|
679
|
+
};
|
|
680
|
+
var vary = (f, pct = 0.04) => [Math.round(f * (1 - pct)), Math.round(f * (1 + pct))];
|
|
681
|
+
var foley = (id, layers, note) => ({
|
|
682
|
+
id,
|
|
683
|
+
bus: "world",
|
|
684
|
+
pan: true,
|
|
685
|
+
layers,
|
|
686
|
+
falloff: FOLEY_FALLOFF,
|
|
687
|
+
sources: [`sdk: ${note}`]
|
|
688
|
+
});
|
|
689
|
+
var click = (f, vol, delay = 0) => [
|
|
690
|
+
sceneNoise({
|
|
691
|
+
type: "bandpass",
|
|
692
|
+
f: vary(f, 0.08),
|
|
693
|
+
q: 4,
|
|
694
|
+
d: [0.018, 0.03],
|
|
695
|
+
vol: [vol * 0.85, vol * 1.1],
|
|
696
|
+
delay
|
|
697
|
+
}),
|
|
698
|
+
sceneTone({
|
|
699
|
+
f: vary(f * 0.8, 0.06),
|
|
700
|
+
f2: Math.round(f * 0.62),
|
|
701
|
+
d: [0.015, 0.025],
|
|
702
|
+
vol: vol * 0.18,
|
|
703
|
+
delay
|
|
704
|
+
})
|
|
705
|
+
];
|
|
706
|
+
var meet = (body, panel, vol, latch) => [
|
|
707
|
+
sceneTone({
|
|
708
|
+
f: vary(body),
|
|
709
|
+
f2: Math.round(body * 0.5),
|
|
710
|
+
d: [0.12, 0.16],
|
|
711
|
+
vol: [vol * 0.9, vol * 1.1]
|
|
712
|
+
}),
|
|
713
|
+
sceneNoise({
|
|
714
|
+
type: "bandpass",
|
|
715
|
+
f: vary(panel, 0.06),
|
|
716
|
+
q: 1.2,
|
|
717
|
+
d: [0.08, 0.12],
|
|
718
|
+
vol: [vol * 0.9, vol * 1.1],
|
|
719
|
+
wet: 0.25
|
|
720
|
+
}),
|
|
721
|
+
...click(latch, vol * 0.45, [0.012, 0.028])
|
|
722
|
+
];
|
|
723
|
+
var LEAF_FOLEY = [
|
|
724
|
+
// a wooden house door or wardrobe door: latch, a short creak, the leaf on the frame (the hard slam adds the frame rattling)
|
|
725
|
+
foley("door_wood_open", click(2400, 0.4), "the latch of a wooden door giving"),
|
|
726
|
+
foley(
|
|
727
|
+
"door_creak",
|
|
728
|
+
[
|
|
729
|
+
sceneTone({ f: [190, 240], f2: 310, d: [0.4, 0.55], vol: [0.04, 0.06] }),
|
|
730
|
+
sceneNoise({
|
|
731
|
+
type: "bandpass",
|
|
732
|
+
f: [480, 560],
|
|
733
|
+
q: 6,
|
|
734
|
+
a: 0.05,
|
|
735
|
+
d: [0.35, 0.5],
|
|
736
|
+
vol: [0.1, 0.14]
|
|
737
|
+
})
|
|
738
|
+
],
|
|
739
|
+
"a wooden hinge turning"
|
|
740
|
+
),
|
|
741
|
+
foley("door_wood_close", meet(120, 600, 0.55, 2400), "a wooden leaf meeting its frame"),
|
|
742
|
+
foley(
|
|
743
|
+
"door_wood_slam",
|
|
744
|
+
[
|
|
745
|
+
...meet(110, 560, 0.85, 2300),
|
|
746
|
+
...sceneMany(
|
|
747
|
+
3,
|
|
748
|
+
() => sceneNoise({
|
|
749
|
+
type: "bandpass",
|
|
750
|
+
f: [900, 1500],
|
|
751
|
+
q: 3,
|
|
752
|
+
d: 0.03,
|
|
753
|
+
vol: [0.08, 0.14],
|
|
754
|
+
delay: [0.05, 0.18]
|
|
755
|
+
})
|
|
756
|
+
)
|
|
757
|
+
],
|
|
758
|
+
"a wooden door slammed: the frame and the hinges rattle after the hit"
|
|
759
|
+
),
|
|
760
|
+
// a metal door or gate: a hollow panel that rings a little
|
|
761
|
+
foley("door_metal_open_close", [...meet(160, 900, 0.55, 2e3), sceneTone({ f: vary(1250), f2: 1150, d: [0.1, 0.16], vol: 0.06, wet: 0.3 })], "a metal door or gate meeting its frame"),
|
|
762
|
+
foley(
|
|
763
|
+
"door_creak_metal",
|
|
764
|
+
[
|
|
765
|
+
sceneTone({ f: [620, 760], f2: 900, d: [0.3, 0.4], vol: [0.03, 0.045] }),
|
|
766
|
+
sceneNoise({
|
|
767
|
+
type: "bandpass",
|
|
768
|
+
f: [1300, 1500],
|
|
769
|
+
q: 8,
|
|
770
|
+
a: 0.04,
|
|
771
|
+
d: [0.25, 0.35],
|
|
772
|
+
vol: [0.07, 0.09]
|
|
773
|
+
})
|
|
774
|
+
],
|
|
775
|
+
"a metal hinge turning"
|
|
776
|
+
),
|
|
777
|
+
// the handle of a locked door shaken: the latch knocking in its keeper, five to seven times in half a second
|
|
778
|
+
foley(
|
|
779
|
+
"door_locked_rattle",
|
|
780
|
+
[
|
|
781
|
+
...sceneMany(
|
|
782
|
+
6,
|
|
783
|
+
() => sceneNoise({
|
|
784
|
+
type: "bandpass",
|
|
785
|
+
f: [1600, 2600],
|
|
786
|
+
q: 3,
|
|
787
|
+
d: [0.025, 0.04],
|
|
788
|
+
vol: [0.22, 0.34],
|
|
789
|
+
delay: [0, 0.45]
|
|
790
|
+
})
|
|
791
|
+
),
|
|
792
|
+
...sceneMany(
|
|
793
|
+
3,
|
|
794
|
+
() => sceneTone({
|
|
795
|
+
f: [170, 210],
|
|
796
|
+
f2: 120,
|
|
797
|
+
d: 0.05,
|
|
798
|
+
vol: [0.12, 0.18],
|
|
799
|
+
delay: [0.02, 0.4]
|
|
800
|
+
})
|
|
801
|
+
)
|
|
802
|
+
],
|
|
803
|
+
"the handle of a locked door shaken: latch knocks and the leaf thumping in its frame"
|
|
804
|
+
),
|
|
805
|
+
// a fridge: the rubber seal lets go with a soft suck, the bottles in the door clink; closing it is a soft thump and the seal pulling shut
|
|
806
|
+
foley(
|
|
807
|
+
"fridge_open",
|
|
808
|
+
[
|
|
809
|
+
sceneNoise({
|
|
810
|
+
type: "lowpass",
|
|
811
|
+
f: [320, 380],
|
|
812
|
+
a: 0.03,
|
|
813
|
+
d: [0.14, 0.2],
|
|
814
|
+
vol: [0.32, 0.4]
|
|
815
|
+
}),
|
|
816
|
+
sceneNoise({
|
|
817
|
+
type: "bandpass",
|
|
818
|
+
f: [800, 950],
|
|
819
|
+
f2: 1400,
|
|
820
|
+
q: 2,
|
|
821
|
+
a: 0.02,
|
|
822
|
+
d: 0.12,
|
|
823
|
+
vol: [0.08, 0.12]
|
|
824
|
+
}),
|
|
825
|
+
...sceneMany(
|
|
826
|
+
2,
|
|
827
|
+
() => sceneTone({
|
|
828
|
+
f: [2600, 4200],
|
|
829
|
+
d: [0.04, 0.08],
|
|
830
|
+
vol: [0.015, 0.03],
|
|
831
|
+
delay: [0.08, 0.22]
|
|
832
|
+
})
|
|
833
|
+
)
|
|
834
|
+
],
|
|
835
|
+
"a fridge door: the seal letting go and the bottles in the door"
|
|
836
|
+
),
|
|
837
|
+
foley(
|
|
838
|
+
"fridge_close",
|
|
839
|
+
[
|
|
840
|
+
sceneTone({ f: vary(85), f2: 45, d: [0.1, 0.13], vol: [0.38, 0.46] }),
|
|
841
|
+
sceneNoise({
|
|
842
|
+
type: "lowpass",
|
|
843
|
+
f: [520, 620],
|
|
844
|
+
d: [0.08, 0.12],
|
|
845
|
+
vol: [0.3, 0.36]
|
|
846
|
+
}),
|
|
847
|
+
sceneNoise({
|
|
848
|
+
type: "lowpass",
|
|
849
|
+
f: [260, 320],
|
|
850
|
+
a: 0.02,
|
|
851
|
+
d: 0.1,
|
|
852
|
+
vol: [0.12, 0.18],
|
|
853
|
+
delay: [0.04, 0.07]
|
|
854
|
+
}),
|
|
855
|
+
...sceneMany(
|
|
856
|
+
2,
|
|
857
|
+
() => sceneTone({
|
|
858
|
+
f: [2600, 4200],
|
|
859
|
+
d: [0.04, 0.07],
|
|
860
|
+
vol: [0.015, 0.03],
|
|
861
|
+
delay: [0.03, 0.12]
|
|
862
|
+
})
|
|
863
|
+
)
|
|
864
|
+
],
|
|
865
|
+
"a fridge door shut: a soft thump, the seal pulling and the bottles"
|
|
866
|
+
),
|
|
867
|
+
// a microwave: the spring catch of the door, plastic on plastic
|
|
868
|
+
foley(
|
|
869
|
+
"microwave_open",
|
|
870
|
+
[
|
|
871
|
+
...click(1800, 0.34),
|
|
872
|
+
sceneTone({
|
|
873
|
+
f: [3e3, 3400],
|
|
874
|
+
f2: 2800,
|
|
875
|
+
d: 0.05,
|
|
876
|
+
vol: 0.025,
|
|
877
|
+
delay: [0.01, 0.02]
|
|
878
|
+
})
|
|
879
|
+
],
|
|
880
|
+
"the spring catch of a microwave door"
|
|
881
|
+
),
|
|
882
|
+
foley(
|
|
883
|
+
"microwave_close",
|
|
884
|
+
[
|
|
885
|
+
sceneNoise({
|
|
886
|
+
type: "bandpass",
|
|
887
|
+
f: [1200, 1450],
|
|
888
|
+
q: 2.5,
|
|
889
|
+
d: [0.04, 0.06],
|
|
890
|
+
vol: [0.36, 0.44]
|
|
891
|
+
}),
|
|
892
|
+
sceneTone({ f: vary(180), f2: 120, d: 0.05, vol: [0.16, 0.22] }),
|
|
893
|
+
...click(2200, 0.2, [8e-3, 0.016])
|
|
894
|
+
],
|
|
895
|
+
"a microwave door clacking shut"
|
|
896
|
+
),
|
|
897
|
+
foley("microwave_beep", [sceneTone({ wave: "square", f: 2e3, d: 0.12, vol: 0.05 })], "the beep of a microwave"),
|
|
898
|
+
// drawers and sliding leaves: the runners, then the stop
|
|
899
|
+
foley(
|
|
900
|
+
"drawer_open",
|
|
901
|
+
[
|
|
902
|
+
sceneNoise({
|
|
903
|
+
type: "bandpass",
|
|
904
|
+
f: [620, 780],
|
|
905
|
+
q: 2,
|
|
906
|
+
a: 0.04,
|
|
907
|
+
d: [0.28, 0.36],
|
|
908
|
+
vol: [0.18, 0.24]
|
|
909
|
+
}),
|
|
910
|
+
sceneNoise({ type: "bandpass", f: [2e3, 2400], q: 5, d: 0.28, vol: 0.04 }),
|
|
911
|
+
...click(1400, 0.16, [0.28, 0.34])
|
|
912
|
+
],
|
|
913
|
+
"a drawer on its runners and its stop"
|
|
914
|
+
),
|
|
915
|
+
foley(
|
|
916
|
+
"drawer_close",
|
|
917
|
+
[
|
|
918
|
+
sceneNoise({
|
|
919
|
+
type: "bandpass",
|
|
920
|
+
f: [620, 780],
|
|
921
|
+
q: 2,
|
|
922
|
+
a: 0.03,
|
|
923
|
+
d: [0.2, 0.28],
|
|
924
|
+
vol: [0.18, 0.24]
|
|
925
|
+
}),
|
|
926
|
+
sceneTone({
|
|
927
|
+
f: vary(150),
|
|
928
|
+
f2: 90,
|
|
929
|
+
d: 0.08,
|
|
930
|
+
vol: [0.22, 0.3],
|
|
931
|
+
delay: [0.2, 0.26]
|
|
932
|
+
})
|
|
933
|
+
],
|
|
934
|
+
"a drawer pushed home"
|
|
935
|
+
)
|
|
936
|
+
];
|
|
937
|
+
var ITEM_FOLEY = [
|
|
938
|
+
// the hand closing on the item: a touch of skin and cloth, then the item's own small sound
|
|
939
|
+
foley(
|
|
940
|
+
"item_pickup_metal",
|
|
941
|
+
[
|
|
942
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
|
|
943
|
+
sceneTone({
|
|
944
|
+
f: [1900, 2600],
|
|
945
|
+
f2: 1700,
|
|
946
|
+
d: [0.05, 0.08],
|
|
947
|
+
vol: [0.06, 0.09],
|
|
948
|
+
delay: [0.01, 0.03]
|
|
949
|
+
})
|
|
950
|
+
],
|
|
951
|
+
"picking up a metal thing"
|
|
952
|
+
),
|
|
953
|
+
foley(
|
|
954
|
+
"item_pickup_plastic",
|
|
955
|
+
[
|
|
956
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
|
|
957
|
+
sceneNoise({
|
|
958
|
+
type: "bandpass",
|
|
959
|
+
f: [1500, 1900],
|
|
960
|
+
q: 3,
|
|
961
|
+
d: 0.03,
|
|
962
|
+
vol: [0.15, 0.21],
|
|
963
|
+
delay: [0.01, 0.03]
|
|
964
|
+
})
|
|
965
|
+
],
|
|
966
|
+
"picking up a plastic thing"
|
|
967
|
+
),
|
|
968
|
+
foley(
|
|
969
|
+
"item_pickup_glass",
|
|
970
|
+
[
|
|
971
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.15 }),
|
|
972
|
+
sceneTone({
|
|
973
|
+
f: [3200, 4200],
|
|
974
|
+
d: [0.05, 0.08],
|
|
975
|
+
vol: [0.038, 0.06],
|
|
976
|
+
delay: [0.01, 0.03]
|
|
977
|
+
})
|
|
978
|
+
],
|
|
979
|
+
"picking up a glass thing"
|
|
980
|
+
),
|
|
981
|
+
foley(
|
|
982
|
+
"item_pickup_paper",
|
|
983
|
+
[
|
|
984
|
+
sceneNoise({
|
|
985
|
+
type: "highpass",
|
|
986
|
+
f: [2600, 3400],
|
|
987
|
+
a: 0.01,
|
|
988
|
+
d: [0.1, 0.14],
|
|
989
|
+
vol: [0.12, 0.18]
|
|
990
|
+
}),
|
|
991
|
+
sceneNoise({ type: "bandpass", f: [800, 1e3], q: 1, d: 0.05, vol: 0.12 })
|
|
992
|
+
],
|
|
993
|
+
"picking up paper or cardboard"
|
|
994
|
+
),
|
|
995
|
+
foley(
|
|
996
|
+
"item_pickup_fabric",
|
|
997
|
+
[
|
|
998
|
+
sceneNoise({
|
|
999
|
+
type: "bandpass",
|
|
1000
|
+
f: [900, 1300],
|
|
1001
|
+
q: 0.8,
|
|
1002
|
+
a: 0.02,
|
|
1003
|
+
d: [0.12, 0.16],
|
|
1004
|
+
vol: [0.15, 0.21]
|
|
1005
|
+
})
|
|
1006
|
+
],
|
|
1007
|
+
"picking up cloth"
|
|
1008
|
+
),
|
|
1009
|
+
foley(
|
|
1010
|
+
"item_pickup_wood",
|
|
1011
|
+
[
|
|
1012
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
|
|
1013
|
+
sceneNoise({
|
|
1014
|
+
type: "bandpass",
|
|
1015
|
+
f: [900, 1100],
|
|
1016
|
+
q: 2,
|
|
1017
|
+
d: 0.04,
|
|
1018
|
+
vol: [0.15, 0.21],
|
|
1019
|
+
delay: [0.01, 0.03]
|
|
1020
|
+
})
|
|
1021
|
+
],
|
|
1022
|
+
"picking up a wooden thing"
|
|
1023
|
+
),
|
|
1024
|
+
foley(
|
|
1025
|
+
"item_pickup_food",
|
|
1026
|
+
[
|
|
1027
|
+
sceneNoise({ type: "bandpass", f: [700, 900], q: 1, d: 0.06, vol: 0.18 }),
|
|
1028
|
+
sceneNoise({
|
|
1029
|
+
type: "lowpass",
|
|
1030
|
+
f: [500, 650],
|
|
1031
|
+
d: 0.05,
|
|
1032
|
+
vol: 0.12,
|
|
1033
|
+
delay: [0.01, 0.03]
|
|
1034
|
+
})
|
|
1035
|
+
],
|
|
1036
|
+
"picking up food"
|
|
1037
|
+
),
|
|
1038
|
+
foley(
|
|
1039
|
+
"item_throw",
|
|
1040
|
+
[
|
|
1041
|
+
sceneNoise({
|
|
1042
|
+
type: "bandpass",
|
|
1043
|
+
f: [450, 650],
|
|
1044
|
+
f2: 1400,
|
|
1045
|
+
q: 1.5,
|
|
1046
|
+
a: 0.05,
|
|
1047
|
+
d: 0.18,
|
|
1048
|
+
vol: [0.1, 0.14]
|
|
1049
|
+
})
|
|
1050
|
+
],
|
|
1051
|
+
"the arm throwing something: air"
|
|
1052
|
+
),
|
|
1053
|
+
// a can: the tab cracks, the gas hisses out; drinking is gulps; crushing it crumples the sheet
|
|
1054
|
+
foley(
|
|
1055
|
+
"can_open",
|
|
1056
|
+
[
|
|
1057
|
+
...click(3200, 0.36),
|
|
1058
|
+
sceneNoise({
|
|
1059
|
+
type: "highpass",
|
|
1060
|
+
f: [3600, 4400],
|
|
1061
|
+
a: 5e-3,
|
|
1062
|
+
d: [0.22, 0.3],
|
|
1063
|
+
vol: [0.16, 0.22],
|
|
1064
|
+
delay: [0.012, 0.02]
|
|
1065
|
+
}),
|
|
1066
|
+
...sceneMany(5, () => sceneTone({ f: [4e3, 7e3], d: 0.02, vol: 0.01, delay: [0.05, 0.4] }))
|
|
1067
|
+
],
|
|
1068
|
+
"the tab of a can and the gas hissing out"
|
|
1069
|
+
),
|
|
1070
|
+
foley(
|
|
1071
|
+
"can_crush",
|
|
1072
|
+
[
|
|
1073
|
+
sceneNoise({
|
|
1074
|
+
type: "bandpass",
|
|
1075
|
+
f: [1600, 2200],
|
|
1076
|
+
q: 1.2,
|
|
1077
|
+
d: [0.18, 0.25],
|
|
1078
|
+
vol: [0.3, 0.38]
|
|
1079
|
+
}),
|
|
1080
|
+
...sceneMany(
|
|
1081
|
+
6,
|
|
1082
|
+
() => sceneTone({
|
|
1083
|
+
f: [1200, 3400],
|
|
1084
|
+
f2: 900,
|
|
1085
|
+
d: 0.03,
|
|
1086
|
+
vol: [0.03, 0.06],
|
|
1087
|
+
delay: [0, 0.2]
|
|
1088
|
+
})
|
|
1089
|
+
)
|
|
1090
|
+
],
|
|
1091
|
+
"a can crushed in the hand"
|
|
1092
|
+
),
|
|
1093
|
+
foley(
|
|
1094
|
+
"can_puncture_spray",
|
|
1095
|
+
[
|
|
1096
|
+
sceneNoise({
|
|
1097
|
+
type: "highpass",
|
|
1098
|
+
f: [2400, 3e3],
|
|
1099
|
+
a: 5e-3,
|
|
1100
|
+
d: [0.5, 0.7],
|
|
1101
|
+
vol: [0.2, 0.26]
|
|
1102
|
+
}),
|
|
1103
|
+
sceneNoise({ type: "bandpass", f: [600, 800], q: 2, d: 0.4, vol: 0.06 })
|
|
1104
|
+
],
|
|
1105
|
+
"a can holed: the jet hissing out"
|
|
1106
|
+
),
|
|
1107
|
+
foley(
|
|
1108
|
+
"bottle_open",
|
|
1109
|
+
[
|
|
1110
|
+
...sceneMany(
|
|
1111
|
+
5,
|
|
1112
|
+
() => sceneNoise({
|
|
1113
|
+
type: "bandpass",
|
|
1114
|
+
f: [2200, 3e3],
|
|
1115
|
+
q: 4,
|
|
1116
|
+
d: 8e-3,
|
|
1117
|
+
vol: [0.1, 0.16],
|
|
1118
|
+
delay: [0, 0.18]
|
|
1119
|
+
})
|
|
1120
|
+
),
|
|
1121
|
+
sceneNoise({
|
|
1122
|
+
type: "highpass",
|
|
1123
|
+
f: 3800,
|
|
1124
|
+
a: 5e-3,
|
|
1125
|
+
d: 0.12,
|
|
1126
|
+
vol: [0.06, 0.1],
|
|
1127
|
+
delay: [0.18, 0.22]
|
|
1128
|
+
})
|
|
1129
|
+
],
|
|
1130
|
+
"the screw cap of a bottle turning off"
|
|
1131
|
+
),
|
|
1132
|
+
foley(
|
|
1133
|
+
"drink_gulp",
|
|
1134
|
+
[
|
|
1135
|
+
sceneNoise({
|
|
1136
|
+
type: "lowpass",
|
|
1137
|
+
f: [280, 360],
|
|
1138
|
+
a: 0.02,
|
|
1139
|
+
d: [0.1, 0.14],
|
|
1140
|
+
vol: [0.24, 0.3]
|
|
1141
|
+
}),
|
|
1142
|
+
sceneTone({ f: [140, 170], f2: 85, d: [0.08, 0.11], vol: [0.12, 0.16] })
|
|
1143
|
+
],
|
|
1144
|
+
"a gulp"
|
|
1145
|
+
),
|
|
1146
|
+
foley(
|
|
1147
|
+
"eat_crunch",
|
|
1148
|
+
[
|
|
1149
|
+
...sceneMany(
|
|
1150
|
+
4,
|
|
1151
|
+
() => sceneNoise({
|
|
1152
|
+
type: "bandpass",
|
|
1153
|
+
f: [1800, 3200],
|
|
1154
|
+
q: 1.5,
|
|
1155
|
+
d: [0.02, 0.04],
|
|
1156
|
+
vol: [0.12, 0.2],
|
|
1157
|
+
delay: [0, 0.12]
|
|
1158
|
+
})
|
|
1159
|
+
)
|
|
1160
|
+
],
|
|
1161
|
+
"a bite of something crunchy"
|
|
1162
|
+
),
|
|
1163
|
+
foley(
|
|
1164
|
+
"eat_chew",
|
|
1165
|
+
[
|
|
1166
|
+
sceneNoise({
|
|
1167
|
+
type: "lowpass",
|
|
1168
|
+
f: [450, 600],
|
|
1169
|
+
a: 0.03,
|
|
1170
|
+
d: [0.1, 0.14],
|
|
1171
|
+
vol: [0.12, 0.16]
|
|
1172
|
+
}),
|
|
1173
|
+
sceneNoise({
|
|
1174
|
+
type: "bandpass",
|
|
1175
|
+
f: [1100, 1400],
|
|
1176
|
+
q: 2,
|
|
1177
|
+
d: 0.04,
|
|
1178
|
+
vol: 0.04,
|
|
1179
|
+
delay: [0.03, 0.06]
|
|
1180
|
+
})
|
|
1181
|
+
],
|
|
1182
|
+
"chewing"
|
|
1183
|
+
),
|
|
1184
|
+
foley(
|
|
1185
|
+
"bandage_wrap",
|
|
1186
|
+
[
|
|
1187
|
+
sceneNoise({
|
|
1188
|
+
type: "bandpass",
|
|
1189
|
+
f: [1400, 1800],
|
|
1190
|
+
f2: 2400,
|
|
1191
|
+
q: 1,
|
|
1192
|
+
a: 0.04,
|
|
1193
|
+
d: [0.3, 0.4],
|
|
1194
|
+
vol: [0.12, 0.16]
|
|
1195
|
+
})
|
|
1196
|
+
],
|
|
1197
|
+
"a bandage unrolled round a limb"
|
|
1198
|
+
),
|
|
1199
|
+
foley(
|
|
1200
|
+
"pills_shake",
|
|
1201
|
+
[
|
|
1202
|
+
...sceneMany(
|
|
1203
|
+
8,
|
|
1204
|
+
() => sceneTone({
|
|
1205
|
+
f: [2400, 3600],
|
|
1206
|
+
d: 0.015,
|
|
1207
|
+
vol: [0.03, 0.05],
|
|
1208
|
+
delay: [0, 0.25]
|
|
1209
|
+
})
|
|
1210
|
+
),
|
|
1211
|
+
sceneNoise({ type: "bandpass", f: [1500, 1900], q: 2, d: 0.25, vol: 0.05 })
|
|
1212
|
+
],
|
|
1213
|
+
"pills shaken in their bottle"
|
|
1214
|
+
),
|
|
1215
|
+
foley(
|
|
1216
|
+
"medkit_use",
|
|
1217
|
+
[
|
|
1218
|
+
...click(1700, 0.24),
|
|
1219
|
+
sceneNoise({
|
|
1220
|
+
type: "bandpass",
|
|
1221
|
+
f: [1e3, 1400],
|
|
1222
|
+
q: 1,
|
|
1223
|
+
a: 0.03,
|
|
1224
|
+
d: [0.25, 0.32],
|
|
1225
|
+
vol: [0.08, 0.12],
|
|
1226
|
+
delay: [0.05, 0.08]
|
|
1227
|
+
})
|
|
1228
|
+
],
|
|
1229
|
+
"a first aid kit opened and rummaged"
|
|
1230
|
+
),
|
|
1231
|
+
foley("flashlight_click", click(2600, 0.3), "the switch of a flashlight")
|
|
1232
|
+
];
|
|
1233
|
+
var FOLEY_BANK = {
|
|
1234
|
+
id: "foley",
|
|
1235
|
+
sounds: [...LEAF_FOLEY, ...ITEM_FOLEY]
|
|
1236
|
+
};
|
|
1237
|
+
var TAKES = [
|
|
1238
|
+
{ f: 1, t: 1, v: 1 },
|
|
1239
|
+
{ f: 1.08, t: 0.9, v: 0.92 },
|
|
1240
|
+
{ f: 0.93, t: 1.12, v: 1.05 },
|
|
1241
|
+
{ f: 1.03, t: 1.05, v: 0.88 }
|
|
1242
|
+
];
|
|
1243
|
+
var FOOTSTEP_FALLOFF = { model: "inverse_square", k: 0.03, cutoffK: 0.03, minGain: 4e-3 };
|
|
1244
|
+
var BODY_FALLOFF = { model: "inverse_square", k: 0.012, cutoffK: 0.015, minGain: 4e-3 };
|
|
1245
|
+
var SURFACES = {
|
|
1246
|
+
concrete: { heel: { f: 95, d: 0.05, vol: 0.55 }, roll: { type: "bandpass", f: 2300, q: 1.1, d: 0.05, vol: 0.38 }, grains: { count: 2, f: 4200, q: 2, spread: 0.04, vol: 0.08 } },
|
|
1247
|
+
asphalt: { heel: { f: 90, d: 0.05, vol: 0.5 }, roll: { type: "bandpass", f: 1700, q: 0.9, d: 0.06, vol: 0.36 }, grains: { count: 4, f: 3600, q: 2.5, spread: 0.06, vol: 0.1 } },
|
|
1248
|
+
wood: { heel: { f: 130, d: 0.08, vol: 0.55 }, roll: { type: "lowpass", f: 1300, q: 0.8, d: 0.06, vol: 0.3 }, ring: [{ f: 210, d: 0.1, vol: 0.18 }, { f: 470, d: 0.06, vol: 0.06 }] },
|
|
1249
|
+
tile: { heel: { f: 110, d: 0.04, vol: 0.45 }, roll: { type: "bandpass", f: 3600, q: 2, d: 0.03, vol: 0.42 }, ring: [{ f: 1900, d: 0.03, vol: 0.05 }] },
|
|
1250
|
+
dirt: { heel: { f: 75, d: 0.06, vol: 0.45 }, roll: { type: "lowpass", f: 750, q: 0.7, d: 0.09, vol: 0.4 }, grains: { count: 3, f: 1800, q: 1.5, spread: 0.07, vol: 0.06 } },
|
|
1251
|
+
grass: { heel: { f: 70, d: 0.05, vol: 0.32 }, roll: { type: "highpass", f: 2600, q: 0.7, d: 0.13, vol: 0.28 }, grains: { count: 4, f: 5200, q: 1.2, spread: 0.1, vol: 0.07 } },
|
|
1252
|
+
gravel: { heel: { f: 80, d: 0.05, vol: 0.4 }, roll: { type: "lowpass", f: 950, q: 0.8, d: 0.1, vol: 0.3 }, grains: { count: 8, f: 2600, q: 3, spread: 0.13, vol: 0.2 } },
|
|
1253
|
+
sand: { heel: { f: 65, d: 0.06, vol: 0.3 }, roll: { type: "bandpass", f: 1500, q: 0.6, d: 0.16, vol: 0.3 }, grains: { count: 5, f: 4800, q: 1.5, spread: 0.12, vol: 0.05 } },
|
|
1254
|
+
metal: { heel: { f: 120, d: 0.05, vol: 0.5 }, roll: { type: "bandpass", f: 2800, q: 1.5, d: 0.03, vol: 0.25 }, ring: [{ f: 420, d: 0.25, vol: 0.16 }, { f: 1130, d: 0.18, vol: 0.09 }, { f: 2470, d: 0.1, vol: 0.04 }] },
|
|
1255
|
+
water: { heel: { f: 70, d: 0.04, vol: 0.25 }, roll: { type: "bandpass", f: 3e3, q: 1.2, d: 0.1, vol: 0.18 }, splash: { f: 1100, f2: 380, d: 0.22, vol: 0.55 }, grains: { count: 4, f: 2400, q: 6, spread: 0.18, vol: 0.12 } },
|
|
1256
|
+
glass: { heel: { f: 90, d: 0.04, vol: 0.4 }, roll: { type: "highpass", f: 4500, q: 0.8, d: 0.06, vol: 0.2 }, grains: { count: 9, f: 6200, q: 5, spread: 0.12, vol: 0.22 }, ring: [{ f: 3900, d: 0.04, vol: 0.04 }, { f: 5300, d: 0.03, vol: 0.03 }] },
|
|
1257
|
+
carpet: { heel: { f: 70, d: 0.05, vol: 0.32 }, roll: { type: "lowpass", f: 420, q: 0.7, d: 0.07, vol: 0.3 } }
|
|
1258
|
+
};
|
|
1259
|
+
var GAITS = {
|
|
1260
|
+
walk: { vol: 1, bright: 1, toe: 0.075, short: 1 },
|
|
1261
|
+
run: { vol: 1.35, bright: 1.25, toe: 0.035, short: 0.75 }
|
|
1262
|
+
};
|
|
1263
|
+
var grainLayers = (g, take, start, scale) => Array.from(
|
|
1264
|
+
{ length: g.count },
|
|
1265
|
+
(_, i) => sceneNoise({ type: "bandpass", f: [g.f * take.f * 0.85, g.f * take.f * 1.15], q: g.q, d: [8e-3, 0.02], vol: g.vol * scale * take.v, delay: start + (i + 0.5) / g.count * g.spread * take.t })
|
|
1266
|
+
);
|
|
1267
|
+
var ringLayers = (rings, take, scale, at = 0) => rings.map((r) => sceneTone({ f: r.f * take.f, d: r.d * take.t, vol: r.vol * scale * take.v, delay: at }));
|
|
1268
|
+
function footLayers(surface, take, gait, weight = 1) {
|
|
1269
|
+
const s = SURFACES[surface];
|
|
1270
|
+
const toe = gait.toe * take.t;
|
|
1271
|
+
return [
|
|
1272
|
+
sceneTone({ f: s.heel.f * take.f * weight ** -0.3, f2: s.heel.f * take.f * 0.6, d: s.heel.d * gait.short * take.t * weight ** 0.5, vol: s.heel.vol * gait.vol * take.v * weight ** 0.5 }),
|
|
1273
|
+
sceneNoise({ type: "lowpass", f: 500 * gait.bright, d: 0.02 * take.t, vol: 0.18 * gait.vol * take.v * weight ** 0.5 }),
|
|
1274
|
+
sceneNoise({ type: s.roll.type, f: [s.roll.f * take.f * gait.bright * 0.92, s.roll.f * take.f * gait.bright * 1.08], q: s.roll.q, d: s.roll.d * gait.short * take.t * weight ** 0.3, vol: s.roll.vol * gait.vol * take.v, delay: toe }),
|
|
1275
|
+
...s.grains ? grainLayers(s.grains, take, toe * 0.5, gait.vol * weight ** 0.5) : [],
|
|
1276
|
+
...s.ring ? ringLayers(s.ring, take, gait.vol * weight ** 0.5) : [],
|
|
1277
|
+
...s.splash ? [sceneNoise({ type: "bandpass", f: s.splash.f * take.f, f2: s.splash.f2 * take.f, q: 1.4, d: s.splash.d * take.t * weight ** 0.4, vol: s.splash.vol * gait.vol * take.v * weight ** 0.5 })] : []
|
|
1278
|
+
];
|
|
1279
|
+
}
|
|
1280
|
+
var quieter = (level, layers) => layers.map((layer) => {
|
|
1281
|
+
const gain = layer.gain ?? 1;
|
|
1282
|
+
if (typeof gain === "number") return { ...layer, gain: gain * level };
|
|
1283
|
+
if (Array.isArray(gain)) return { ...layer, gain: [gain[0] * level, gain[1] * level] };
|
|
1284
|
+
return layer;
|
|
1285
|
+
});
|
|
1286
|
+
var recipe = (id, layers, falloff, bus = "world") => ({ id, bus, pan: true, layers, falloff, sources: ["sdk"] });
|
|
1287
|
+
var takeId = (id, index) => `${id}_${String(index + 1).padStart(2, "0")}`;
|
|
1288
|
+
function takes(id, layersOf, falloff, rate = [0.96, 1.04], bus) {
|
|
1289
|
+
const sounds = TAKES.map((take, index) => recipe(takeId(id, index), layersOf(take, index), falloff, bus));
|
|
1290
|
+
return { sounds, set: { id, variants: sounds.map((sound) => sound.id), rate } };
|
|
1291
|
+
}
|
|
1292
|
+
var footstep = (surface, gait) => takes(footstepSoundId(surface, gait), (take) => footLayers(surface, take, GAITS[gait]), FOOTSTEP_FALLOFF);
|
|
1293
|
+
var LANDINGS = { light: { weight: 1.4, cloth: 0.12 }, heavy: { weight: 2.4, cloth: 0.22 } };
|
|
1294
|
+
var LANDING_LEVEL = 0.65;
|
|
1295
|
+
var landing = (surface, landing2) => takes(
|
|
1296
|
+
`land_${surface}_${landing2}`,
|
|
1297
|
+
(take) => quieter(LANDING_LEVEL, [
|
|
1298
|
+
// both feet, a hair apart, then the knees taking the weight (a low body thump) and the clothes settling
|
|
1299
|
+
...footLayers(surface, take, GAITS.run, LANDINGS[landing2].weight),
|
|
1300
|
+
...footLayers(surface, { ...take, v: take.v * 0.6 }, GAITS.run, LANDINGS[landing2].weight * 0.6).map((layer) => ({ ...layer, at: (typeof layer.at === "number" ? layer.at : 0) + 0.018 * take.t })),
|
|
1301
|
+
sceneTone({ f: 60 * take.f, f2: 38, d: 0.14 * LANDINGS[landing2].weight * take.t, vol: 0.22 * LANDINGS[landing2].weight ** 0.7 * take.v, delay: 0.02 }),
|
|
1302
|
+
sceneNoise({ type: "bandpass", f: [1800, 2600], q: 0.8, d: 0.18, vol: LANDINGS[landing2].cloth * take.v, delay: 0.04 })
|
|
1303
|
+
]),
|
|
1304
|
+
FOOTSTEP_FALLOFF
|
|
1305
|
+
);
|
|
1306
|
+
var whoosh = (blow, from, to, d, vol, q = 1.6) => (take) => [
|
|
1307
|
+
// the air: a band sweeping up as the limb speeds up; it peaks `SWING_LEAD_SECONDS` in, the moment before the contact, then dies away
|
|
1308
|
+
sceneNoise({ type: "bandpass", f: from * take.f, f2: to * take.f, q, a: SWING_LEAD_SECONDS[blow], d: d * take.t, vol: vol * take.v }),
|
|
1309
|
+
sceneNoise({ type: "lowpass", f: 600 * take.f, a: SWING_LEAD_SECONDS[blow], d: d * take.t * 0.8, vol: vol * 0.35 * take.v })
|
|
1310
|
+
];
|
|
1311
|
+
var fleshHit = (o) => (take) => [
|
|
1312
|
+
sceneNoise({ type: "bandpass", f: o.slapF * take.f, q: 1.2, d: 0.03 * take.t, vol: o.slap * take.v }),
|
|
1313
|
+
sceneNoise({ type: "highpass", f: 3500 * take.f, d: 0.012, vol: o.slap * 0.4 * take.v }),
|
|
1314
|
+
sceneTone({ f: o.thudF * take.f, f2: o.thudF * 0.5, d: o.thudD * take.t, vol: o.thud * take.v }),
|
|
1315
|
+
sceneNoise({ type: "lowpass", f: 600 * take.f, d: o.thudD * 1.2 * take.t, vol: o.thud * 0.5 * take.v }),
|
|
1316
|
+
...o.crack ? [sceneNoise({ type: "highpass", f: 2500, d: 0.015, vol: o.crack * take.v, delay: 6e-3 }), sceneTone({ wave: "square", f: 900 * take.f, f2: 300, d: 0.02, vol: o.crack * 0.15 * take.v, delay: 6e-3 })] : [],
|
|
1317
|
+
...o.wet ? [sceneNoise({ type: "bandpass", f: 1400 * take.f, f2: 500, q: 2.5, d: 0.12 * take.t, vol: o.wet * take.v, delay: 0.01 })] : []
|
|
1318
|
+
];
|
|
1319
|
+
var knock = (o) => (take) => [
|
|
1320
|
+
sceneNoise({ type: "bandpass", f: o.clickF * take.f, q: 1.5, d: 0.018, vol: o.click * take.v }),
|
|
1321
|
+
...o.tones.map(([f, d, vol]) => sceneTone({ f: f * take.f, d: d * take.t, vol: vol * take.v }))
|
|
1322
|
+
];
|
|
1323
|
+
var voice = (o) => (take) => [
|
|
1324
|
+
sceneVoice({ f0: o.f0 * take.f, f1: o.f1 * take.f, d: o.d * take.t, fA: o.fA * take.f, fB: o.fB * take.f, noise: o.noise, vol: o.vol * take.v })
|
|
1325
|
+
];
|
|
1326
|
+
var BODY = {
|
|
1327
|
+
jump: (take) => [
|
|
1328
|
+
sceneNoise({ type: "bandpass", f: 900 * take.f, f2: 1700 * take.f, q: 1, a: 0.03, d: 0.12, vol: 0.18 * take.v }),
|
|
1329
|
+
sceneNoise({ type: "bandpass", f: 2200 * take.f, q: 0.8, d: 0.04, vol: 0.12 * take.v }),
|
|
1330
|
+
sceneTone({ f: 85 * take.f, f2: 60, d: 0.04, vol: 0.2 * take.v })
|
|
1331
|
+
],
|
|
1332
|
+
cloth_rustle: (take) => [
|
|
1333
|
+
{ ...sceneNoise({ type: "bandpass", f: 2400 * take.f, q: 0.8, a: 0.06, d: 0.22 * take.t, vol: 0.12 * take.v }), modulators: [{ target: "gain", wave: "triangle", rate: [9, 14], depth: 0.5 }] }
|
|
1334
|
+
],
|
|
1335
|
+
body_fall: (take) => [
|
|
1336
|
+
sceneTone({ f: 58 * take.f, f2: 35, d: 0.28 * take.t, vol: 0.9 * take.v }),
|
|
1337
|
+
sceneNoise({ type: "lowpass", f: 480 * take.f, d: 0.3 * take.t, vol: 0.55 * take.v }),
|
|
1338
|
+
sceneNoise({ type: "bandpass", f: 1300 * take.f, q: 1, d: 0.05, vol: 0.3 * take.v }),
|
|
1339
|
+
// the limbs a moment later, and the clothes
|
|
1340
|
+
sceneTone({ f: 75 * take.f, f2: 45, d: 0.12, vol: 0.4 * take.v, delay: 0.13 * take.t }),
|
|
1341
|
+
sceneNoise({ type: "bandpass", f: 2200, q: 0.8, d: 0.2, vol: 0.12 * take.v, delay: 0.05 })
|
|
1342
|
+
],
|
|
1343
|
+
fall_damage: (take) => [
|
|
1344
|
+
...BODY.body_fall(take),
|
|
1345
|
+
sceneNoise({ type: "highpass", f: 2800, d: 0.02, vol: 0.35 * take.v, delay: 0.01 }),
|
|
1346
|
+
...voice({ f0: 170, f1: 110, d: 0.32, fA: 650, fB: 1150, noise: 0.25, vol: 0.32 })(take).map((layer) => ({ ...layer, at: 0.08 }))
|
|
1347
|
+
],
|
|
1348
|
+
player_hurt: voice({ f0: 150, f1: 105, d: 0.26, fA: 620, fB: 1100, noise: 0.3, vol: 0.35 }),
|
|
1349
|
+
player_breath_run: (take) => [
|
|
1350
|
+
sceneNoise({ type: "bandpass", f: 1200 * take.f, q: 1, a: 0.08, d: 0.22 * take.t, vol: 0.25 * take.v }),
|
|
1351
|
+
sceneNoise({ type: "bandpass", f: 900 * take.f, q: 1, a: 0.06, d: 0.26 * take.t, vol: 0.3 * take.v, delay: 0.3 * take.t })
|
|
1352
|
+
],
|
|
1353
|
+
player_death: voice({ f0: 135, f1: 68, d: 1, fA: 560, fB: 980, noise: 0.35, vol: 0.4 }),
|
|
1354
|
+
bite: (take) => [
|
|
1355
|
+
sceneNoise({ type: "highpass", f: 2600, d: 0.015, vol: 0.4 * take.v }),
|
|
1356
|
+
sceneNoise({ type: "bandpass", f: 1600 * take.f, f2: 450, q: 2.2, d: 0.16 * take.t, vol: 0.55 * take.v, delay: 0.01 }),
|
|
1357
|
+
sceneNoise({ type: "bandpass", f: 3200 * take.f, f2: 1800, q: 1.2, d: 0.22 * take.t, vol: 0.25 * take.v, delay: 0.09 }),
|
|
1358
|
+
sceneTone({ f: 120 * take.f, f2: 70, d: 0.06, vol: 0.3 * take.v })
|
|
1359
|
+
],
|
|
1360
|
+
grab: (take) => [
|
|
1361
|
+
sceneNoise({ type: "bandpass", f: 1900 * take.f, q: 0.9, a: 4e-3, d: 0.13 * take.t, vol: 0.32 * take.v }),
|
|
1362
|
+
sceneTone({ f: 95 * take.f, f2: 60, d: 0.07, vol: 0.3 * take.v }),
|
|
1363
|
+
sceneNoise({ type: "lowpass", f: 700, d: 0.08, vol: 0.2 * take.v })
|
|
1364
|
+
],
|
|
1365
|
+
punch_swing: whoosh("punch", 450, 1500, 0.16, 0.9),
|
|
1366
|
+
punch_hit_body: fleshHit({ slap: 0.55, slapF: 1500, thud: 0.6, thudF: 115, thudD: 0.09 }),
|
|
1367
|
+
punch_hit_face: fleshHit({ slap: 0.75, slapF: 2300, thud: 0.45, thudF: 150, thudD: 0.07, crack: 0.25 }),
|
|
1368
|
+
punch_hit_object: knock({ clickF: 1800, click: 0.3, tones: [[210, 0.04, 0.25]] }),
|
|
1369
|
+
kick_swing: whoosh("kick", 280, 950, 0.22, 1, 1.3),
|
|
1370
|
+
kick_hit: fleshHit({ slap: 0.45, slapF: 1100, thud: 0.85, thudF: 82, thudD: 0.14 }),
|
|
1371
|
+
kick_hit_object: knock({ clickF: 1e3, click: 0.3, tones: [[92, 0.08, 0.5]] }),
|
|
1372
|
+
shove_two_hands: (take) => [
|
|
1373
|
+
sceneNoise({ type: "bandpass", f: 950 * take.f, q: 0.9, a: 0.01, d: 0.13 * take.t, vol: 0.38 * take.v }),
|
|
1374
|
+
sceneTone({ f: 100 * take.f, f2: 60, d: 0.1 * take.t, vol: 0.45 * take.v }),
|
|
1375
|
+
sceneNoise({ type: "bandpass", f: 2300, q: 0.8, d: 0.16, vol: 0.12 * take.v, delay: 0.03 })
|
|
1376
|
+
],
|
|
1377
|
+
knife_swing: whoosh("blade", 1900, 4600, 0.12, 1.1, 2.2),
|
|
1378
|
+
knife_stab: fleshHit({ slap: 0.2, slapF: 1200, thud: 0.4, thudF: 160, thudD: 0.06, wet: 0.5 }),
|
|
1379
|
+
knife_slash: (take) => [
|
|
1380
|
+
sceneNoise({ type: "highpass", f: 3200 * take.f, f2: 1800, d: 0.13 * take.t, vol: 0.35 * take.v }),
|
|
1381
|
+
sceneNoise({ type: "bandpass", f: 1300 * take.f, f2: 600, q: 2.5, d: 0.12 * take.t, vol: 0.35 * take.v, delay: 0.02 })
|
|
1382
|
+
],
|
|
1383
|
+
knife_hit_object: knock({ clickF: 3200, click: 0.25, tones: [[2800, 0.08, 0.07], [4150, 0.06, 0.05]] }),
|
|
1384
|
+
blunt_swing: whoosh("blunt", 220, 760, 0.28, 1.1, 1.5),
|
|
1385
|
+
blunt_hit: fleshHit({ slap: 0.35, slapF: 900, thud: 1, thudF: 70, thudD: 0.18, crack: 0.3 }),
|
|
1386
|
+
blunt_hit_object: knock({ clickF: 1400, click: 0.35, tones: [[300, 0.12, 0.25], [760, 0.08, 0.12]] }),
|
|
1387
|
+
axe_swing: whoosh("chop", 190, 620, 0.3, 1.2, 1.4),
|
|
1388
|
+
axe_chop: fleshHit({ slap: 0.3, slapF: 1400, thud: 0.75, thudF: 140, thudD: 0.1, crack: 0.35, wet: 0.45 }),
|
|
1389
|
+
axe_hit_object: knock({ clickF: 2200, click: 0.4, tones: [[1500, 0.15, 0.1], [2300, 0.1, 0.06], [140, 0.1, 0.35]] })
|
|
1390
|
+
};
|
|
1391
|
+
var BODY_BUS = { player_hurt: "voices", player_death: "voices", player_breath_run: "voices", fall_damage: "voices" };
|
|
1392
|
+
var built = [
|
|
1393
|
+
...SURFACE_IDS.flatMap((surface) => GAIT_IDS.map((gait) => footstep(surface, gait))),
|
|
1394
|
+
...SURFACE_IDS.flatMap((surface) => LANDING_IDS.map((l) => landing(surface, l))),
|
|
1395
|
+
...BODY_SOUND_IDS.map((id) => takes(id, BODY[id], BODY_FALLOFF, id.endsWith("_swing") ? [0.94, 1.06] : [0.96, 1.04], BODY_BUS[id]))
|
|
1396
|
+
];
|
|
1397
|
+
var BODY_FOLEY_BANK = {
|
|
1398
|
+
id: "body_foley",
|
|
1399
|
+
sounds: built.flatMap((entry) => entry.sounds),
|
|
1400
|
+
sets: built.map((entry) => entry.set)
|
|
1401
|
+
};
|
|
1402
|
+
var BODY_FOLEY_SET_IDS = [...FOOTSTEP_SOUND_IDS, ...LAND_SOUND_IDS, ...BODY_SOUND_IDS];
|
|
1403
|
+
|
|
1404
|
+
// src/audio/recipes.ts
|
|
1405
|
+
var call = (o) => ({
|
|
1406
|
+
id: o.id,
|
|
1407
|
+
bus: "world",
|
|
1408
|
+
order: "calls",
|
|
1409
|
+
duration: o.seconds,
|
|
1410
|
+
tail: 0.02,
|
|
1411
|
+
// the page makes its gain and filter before it looks at the level
|
|
1412
|
+
keepSilent: true,
|
|
1413
|
+
layers: [
|
|
1414
|
+
{
|
|
1415
|
+
repeat: { count: o.count, spacing: o.spacing },
|
|
1416
|
+
source: { kind: "osc", wave: o.wave, frequency: { from: o.frequency, to: o.frequency * o.drop, curve: "exp", over: "duration" } },
|
|
1417
|
+
filters: { mode: "serial", bank: [{ type: "bandpass", frequency: { set: o.frequency * 1.2 }, q: 3 }] },
|
|
1418
|
+
envelope: [
|
|
1419
|
+
[0, 1e-4, "set", "fixed"],
|
|
1420
|
+
[0.015, 1, "exp"],
|
|
1421
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
1422
|
+
]
|
|
1423
|
+
}
|
|
1424
|
+
],
|
|
1425
|
+
falloff: DISTANCE_CURVES.animals,
|
|
1426
|
+
sources: [`jogo:L66625-66639 bichoSom('${o.team}')`]
|
|
1427
|
+
});
|
|
1428
|
+
var DOG_BARK = call({ id: "dog_bark", team: "latido", count: 2, spacing: 0.22, seconds: 0.12, wave: "square", frequency: 520, drop: 0.6 });
|
|
1429
|
+
var LAPWING_CALL = call({ id: "lapwing_call", team: "queroquero", count: 3, spacing: 0.14, seconds: 0.09, wave: "square", frequency: 2400, drop: 0.6 });
|
|
1430
|
+
var HEN_CLUCK = call({ id: "hen_cluck", team: "cacarejo", count: 4, spacing: 0.14, seconds: 0.09, wave: "square", frequency: 900, drop: 0.6 });
|
|
1431
|
+
var COW_MOO = call({ id: "cow_moo", team: "mugido", count: 1, spacing: 0.14, seconds: 1.2, wave: "sawtooth", frequency: 140, drop: 0.8 });
|
|
1432
|
+
var ANIMAL_SOUNDS = [DOG_BARK, LAPWING_CALL, HEN_CLUCK, COW_MOO];
|
|
1433
|
+
var ANIMAL_SOUND_BANK = { id: "animals_three", sounds: ANIMAL_SOUNDS };
|
|
1434
|
+
|
|
1435
|
+
// src/audio/calls.json
|
|
1436
|
+
var calls_default = {
|
|
1437
|
+
sources: [
|
|
1438
|
+
"jogo:L66677 galinha: cacarejo, 6 s between calls, noise 30 m",
|
|
1439
|
+
"jogo:L66680 quero-quero: queroquero when the player is near (alarme), 8 s, noise 40 m",
|
|
1440
|
+
"jogo:L66681 vaca: mugido, 30 s, noise 80 m",
|
|
1441
|
+
"jogo:L66683 cachorro: latido when a zombie is within 12 m, 3 s, noise 60 m"
|
|
1442
|
+
],
|
|
1443
|
+
species: {
|
|
1444
|
+
chicken: { sound: "hen_cluck", cooldown: 6, noiseMetres: 30 },
|
|
1445
|
+
southern_lapwing: { sound: "lapwing_call", cooldown: 8, noiseMetres: 40 },
|
|
1446
|
+
cow: { sound: "cow_moo", cooldown: 30, noiseMetres: 80 },
|
|
1447
|
+
dog: { sound: "dog_bark", cooldown: 3, noiseMetres: 60 }
|
|
1448
|
+
}
|
|
1449
|
+
};
|
|
1450
|
+
|
|
1451
|
+
// src/audio/sound.ts
|
|
1452
|
+
var DATA = calls_default;
|
|
1453
|
+
var ANIMAL_CALLS = DATA.species;
|
|
1454
|
+
var ANIMAL_CALL_SOURCES = DATA.sources;
|
|
1455
|
+
function createAnimalSound(sink, options = {}) {
|
|
1456
|
+
sink.register?.(ANIMAL_SOUND_BANK);
|
|
1457
|
+
const calls = { ...ANIMAL_CALLS, ...options.calls };
|
|
1458
|
+
const waiting = /* @__PURE__ */ new Map();
|
|
1459
|
+
const callOf = (speciesId) => calls[speciesId] ?? void 0;
|
|
1460
|
+
return {
|
|
1461
|
+
callOf,
|
|
1462
|
+
call(speciesId, position, o = {}) {
|
|
1463
|
+
const found = callOf(speciesId);
|
|
1464
|
+
if (!found) return false;
|
|
1465
|
+
const key = o.key ?? speciesId;
|
|
1466
|
+
if ((waiting.get(key) ?? 0) > 0) return false;
|
|
1467
|
+
waiting.set(key, found.cooldown);
|
|
1468
|
+
sink.play({ sound: found.sound, position, ...o.volume === void 0 ? {} : { volume: o.volume } });
|
|
1469
|
+
return true;
|
|
1470
|
+
},
|
|
1471
|
+
update(dt) {
|
|
1472
|
+
for (const [key, seconds] of waiting) {
|
|
1473
|
+
if (seconds - dt <= 0) waiting.delete(key);
|
|
1474
|
+
else waiting.set(key, seconds - dt);
|
|
1475
|
+
}
|
|
1476
|
+
},
|
|
1477
|
+
dispose: () => waiting.clear()
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
// src/context.ts
|
|
1482
|
+
var createStream = (seed) => {
|
|
1483
|
+
let state = seed;
|
|
1484
|
+
return () => {
|
|
1485
|
+
state |= 0;
|
|
1486
|
+
state = state + 1831565813 | 0;
|
|
1487
|
+
let t = Math.imul(state ^ state >>> 15, 1 | state);
|
|
1488
|
+
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
|
|
1489
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
1490
|
+
};
|
|
1491
|
+
};
|
|
1492
|
+
var addMesh = (THREE, parent, geometry, material, x, y, z, rx, ry, rz) => {
|
|
1493
|
+
const mesh2 = new THREE.Mesh(geometry, material);
|
|
1494
|
+
mesh2.position.set(x || 0, y || 0, z || 0);
|
|
1495
|
+
if (rx || ry || rz) mesh2.rotation.set(rx || 0, ry || 0, rz || 0);
|
|
1496
|
+
mesh2.castShadow = true;
|
|
1497
|
+
mesh2.receiveShadow = true;
|
|
1498
|
+
parent.add(mesh2);
|
|
1499
|
+
return mesh2;
|
|
1500
|
+
};
|
|
1501
|
+
var createRigTools = (THREE, rig) => {
|
|
1502
|
+
const tools = {
|
|
1503
|
+
material(color2, extras) {
|
|
1504
|
+
const material = new THREE.MeshStandardMaterial(Object.assign({ color: color2, roughness: 0.8, metalness: 0, flatShading: false }, extras || {}));
|
|
1505
|
+
material.userData.base = material.color.clone();
|
|
1506
|
+
rig.materials.push(material);
|
|
1507
|
+
return material;
|
|
1508
|
+
},
|
|
1509
|
+
ball(parent, radius, material, x, y, z, sx, sy, sz) {
|
|
1510
|
+
const mesh2 = addMesh(THREE, parent, new THREE.SphereGeometry(radius, 16, 12), material, x, y, z);
|
|
1511
|
+
if (sx) mesh2.scale.set(sx, sy, sz);
|
|
1512
|
+
return mesh2;
|
|
1513
|
+
},
|
|
1514
|
+
limb: (parent, radius1, radius2, length, material) => addMesh(THREE, parent, new THREE.CylinderGeometry(radius2, radius1, length, 14, 1).translate(0, -length / 2, 0), material),
|
|
1515
|
+
joint(parent, radius, material, x, y, z) {
|
|
1516
|
+
const joint = tools.ball(parent, radius, material, x, y, z);
|
|
1517
|
+
joint.userData.joint = 1;
|
|
1518
|
+
rig.joints.push(joint);
|
|
1519
|
+
return joint;
|
|
1520
|
+
},
|
|
1521
|
+
pivot(parent, x, y, z, offset) {
|
|
1522
|
+
const group = new THREE.Group();
|
|
1523
|
+
group.position.set(x, y, z);
|
|
1524
|
+
parent.add(group);
|
|
1525
|
+
rig.pivots.push({ group, rest: group.position.clone(), offset: offset || new THREE.Vector3() });
|
|
1526
|
+
return group;
|
|
1527
|
+
},
|
|
1528
|
+
eyes(head, radius, x, y, z) {
|
|
1529
|
+
const eyeMaterial = tools.material(1118481, { roughness: 0.25 });
|
|
1530
|
+
rig.eyeMaterial = eyeMaterial;
|
|
1531
|
+
for (const side of [-1, 1]) rig.eyes.push(tools.ball(head, radius, eyeMaterial, side * x, y, z));
|
|
1532
|
+
}
|
|
1533
|
+
};
|
|
1534
|
+
return tools;
|
|
1535
|
+
};
|
|
1536
|
+
var createRig = (THREE, species, options) => {
|
|
1537
|
+
const rig = {
|
|
1538
|
+
species,
|
|
1539
|
+
root: new THREE.Group(),
|
|
1540
|
+
trunk: new THREE.Group(),
|
|
1541
|
+
materials: [],
|
|
1542
|
+
joints: [],
|
|
1543
|
+
pivots: [],
|
|
1544
|
+
legs: [],
|
|
1545
|
+
tail: [],
|
|
1546
|
+
ears: [],
|
|
1547
|
+
infectionParts: [],
|
|
1548
|
+
eyes: [],
|
|
1549
|
+
wings: [],
|
|
1550
|
+
segments: [],
|
|
1551
|
+
phase: options.phase,
|
|
1552
|
+
size: 1,
|
|
1553
|
+
segmentLength: 0,
|
|
1554
|
+
segmentCount: 0,
|
|
1555
|
+
home: new THREE.Vector3(),
|
|
1556
|
+
infected: false,
|
|
1557
|
+
dead: false,
|
|
1558
|
+
neckAngle: 0,
|
|
1559
|
+
headAngle: 0,
|
|
1560
|
+
triangles: 0
|
|
1561
|
+
};
|
|
1562
|
+
rig.root.add(rig.trunk);
|
|
1563
|
+
return rig;
|
|
1564
|
+
};
|
|
1565
|
+
|
|
1566
|
+
// src/extras.ts
|
|
1567
|
+
var cow = ({ THREE, tools }, k) => {
|
|
1568
|
+
tools.ball(k.bodyGroup, 0.2, k.main, 0, k.Rb * 1.1, k.L * 0.33, 0.95, 1.1, 1.1);
|
|
1569
|
+
tools.ball(k.neck, 0.13, k.main, 0, 0.12, 0.08, 0.55, 1.4, 1.05);
|
|
1570
|
+
for (const side of [-1, 1]) addMesh(THREE, k.head, new THREE.ConeGeometry(0.025, 0.13, 8), tools.material(13616808), side * 0.12, k.hd.r * 1.05, k.hd.r * 0.05, 0, 0, side * -0.9);
|
|
1571
|
+
};
|
|
1572
|
+
var horse = ({ THREE, rig, tools }, k) => {
|
|
1573
|
+
for (let index = 0; index < 9; index++) addMesh(THREE, k.neck, new THREE.BoxGeometry(0.035, 0.16, 0.08), k.dark, 0, 0.06 + index * 0.065, -0.12 + index * 4e-3, -0.25, 0, 0);
|
|
1574
|
+
addMesh(THREE, k.head, new THREE.BoxGeometry(0.03, 0.12, 0.06), k.dark, 0, k.hd.r * 1.05, k.hd.r * 0.3, 0.6, 0, 0);
|
|
1575
|
+
const last = rig.tail[rig.tail.length - 1];
|
|
1576
|
+
tools.ball(last, 0.08, k.dark, 0, -0.42, 0, 0.7, 4.5, 0.7);
|
|
1577
|
+
};
|
|
1578
|
+
var wildBoar = ({ THREE, tools }, k) => {
|
|
1579
|
+
for (let index = 0; index < 12; index++) addMesh(THREE, k.bodyGroup, new THREE.BoxGeometry(0.03, 0.1, 0.06), k.dark, 0, k.Rb * 1.12 - index * 4e-3, k.L * 0.38 - index * 0.06, -0.2, 0, 0);
|
|
1580
|
+
for (const side of [-1, 1])
|
|
1581
|
+
addMesh(THREE, k.head, new THREE.ConeGeometry(0.012, 0.09, 6), tools.material(15261900), side * 0.07, k.hd.r * -0.25 + 0.03, k.hd.r * 0.25 + k.hd.r * k.hd.s[2] * 0.55 + 0.13, -0.6, 0, side * 0.5);
|
|
1582
|
+
};
|
|
1583
|
+
var chicken = ({ tools }, k) => {
|
|
1584
|
+
const red = tools.material(12593182);
|
|
1585
|
+
for (let index = 0; index < 4; index++) tools.ball(k.head, 0.014, red, 0, 0.045, -0.012 + index * 0.014, 0.5, 1, 0.8);
|
|
1586
|
+
tools.ball(k.head, 0.012, red, 0, -0.04, 0.04, 0.5, 1.3, 0.7);
|
|
1587
|
+
};
|
|
1588
|
+
var southernLapwing = ({ THREE, tools }, k) => {
|
|
1589
|
+
const black = tools.material(1447446);
|
|
1590
|
+
tools.ball(k.bodyGroup, 0.05, black, 0, 0.03, 0.08, 1.1, 0.9, 0.6);
|
|
1591
|
+
addMesh(THREE, k.head, new THREE.BoxGeometry(6e-3, 6e-3, 0.06).translate(0, 0, -0.03), black, 0, 0.025, -0.01, 0.5, 0, 0);
|
|
1592
|
+
tools.ball(k.head, 0.026, black, 0, -5e-3, 0.02, 1.05, 0.7, 0.9);
|
|
1593
|
+
};
|
|
1594
|
+
var QUADRUPED_EXTRAS = { cow, horse, wild_boar: wildBoar };
|
|
1595
|
+
var BIRD_EXTRAS = { chicken, southern_lapwing: southernLapwing };
|
|
1596
|
+
|
|
48
1597
|
// ../game-animals/dist/index.js
|
|
49
1598
|
var gaits_default = {
|
|
50
1599
|
walk: [
|
|
@@ -92,16 +1641,27 @@ var GameAnimalsThree = (() => {
|
|
|
92
1641
|
return outcome === "dies" ? "dead" : "alive";
|
|
93
1642
|
};
|
|
94
1643
|
|
|
95
|
-
//
|
|
96
|
-
var
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
1644
|
+
// src/line-up.ts
|
|
1645
|
+
var lineUpAnimals = (rigs, options = {}) => {
|
|
1646
|
+
const start = options.start ?? -19;
|
|
1647
|
+
const gap = options.gap ?? 0.85;
|
|
1648
|
+
let cursor = start;
|
|
1649
|
+
for (const rig of rigs) {
|
|
1650
|
+
const length = lineUpLength(rig.species.body);
|
|
1651
|
+
cursor += length / 2;
|
|
1652
|
+
rig.root.position.set(cursor, 0, 0);
|
|
1653
|
+
rig.home = rig.root.position.clone();
|
|
1654
|
+
rig.root.rotation.y = rig.species.body.kind === "snake" ? options.snakeYaw ?? 2.2 : options.yaw ?? 1.1;
|
|
1655
|
+
cursor += length / 2 + gap;
|
|
1656
|
+
}
|
|
1657
|
+
const offset = -(cursor - gap + start) / 2;
|
|
1658
|
+
for (const rig of rigs) {
|
|
1659
|
+
rig.root.position.x += offset;
|
|
1660
|
+
rig.home.x += offset;
|
|
1661
|
+
}
|
|
1662
|
+
};
|
|
1663
|
+
|
|
1664
|
+
// ../game-shapes/dist/chunk-M5N2SHNL.js
|
|
105
1665
|
function canonicalJson(value) {
|
|
106
1666
|
if (value === null) return "null";
|
|
107
1667
|
if (typeof value === "number") return Object.is(value, -0) ? "-0" : Number.isFinite(value) ? String(value) : JSON.stringify(String(value));
|
|
@@ -1348,8 +2908,8 @@ var GameAnimalsThree = (() => {
|
|
|
1348
2908
|
groups: []
|
|
1349
2909
|
};
|
|
1350
2910
|
}
|
|
1351
|
-
function make(
|
|
1352
|
-
switch (kind) {
|
|
2911
|
+
function make(p) {
|
|
2912
|
+
switch (p.kind) {
|
|
1353
2913
|
case "box": {
|
|
1354
2914
|
const size = p.size ?? [1, 1, 1];
|
|
1355
2915
|
const segments = p.segments ?? [1, 1, 1];
|
|
@@ -1378,7 +2938,7 @@ var GameAnimalsThree = (() => {
|
|
|
1378
2938
|
case "mesh":
|
|
1379
2939
|
return mesh(p);
|
|
1380
2940
|
default:
|
|
1381
|
-
throw new Error(`game-shapes: unknown primitive kind "${String(kind)}"`);
|
|
2941
|
+
throw new Error(`game-shapes: unknown primitive kind "${String(p.kind)}"`);
|
|
1382
2942
|
}
|
|
1383
2943
|
}
|
|
1384
2944
|
var templates = /* @__PURE__ */ new Map();
|
|
@@ -1386,7 +2946,7 @@ var GameAnimalsThree = (() => {
|
|
|
1386
2946
|
var stats = { hits: 0, misses: 0 };
|
|
1387
2947
|
function buildPrimitive(node, options = {}) {
|
|
1388
2948
|
const parameters = primitiveParameters(node, options);
|
|
1389
|
-
if (node.kind === "mesh" || templateLimit === 0) return make(node
|
|
2949
|
+
if (node.kind === "mesh" || templateLimit === 0) return make({ ...node, ...parameters });
|
|
1390
2950
|
const key = `${node.kind}:${canonicalJson(parameters)}`;
|
|
1391
2951
|
const cached = templates.get(key);
|
|
1392
2952
|
if (cached) {
|
|
@@ -1396,10 +2956,10 @@ var GameAnimalsThree = (() => {
|
|
|
1396
2956
|
return cached;
|
|
1397
2957
|
}
|
|
1398
2958
|
stats.misses++;
|
|
1399
|
-
const
|
|
1400
|
-
templates.set(key,
|
|
2959
|
+
const built2 = make({ ...node, ...parameters });
|
|
2960
|
+
templates.set(key, built2);
|
|
1401
2961
|
if (templates.size > templateLimit) templates.delete(templates.keys().next().value);
|
|
1402
|
-
return
|
|
2962
|
+
return built2;
|
|
1403
2963
|
}
|
|
1404
2964
|
var num = (v) => typeof v === "number" && Number.isFinite(v) ? null : "expected a finite number";
|
|
1405
2965
|
var bool = (v) => typeof v === "boolean" ? null : "expected a boolean";
|
|
@@ -1702,6 +3262,134 @@ var GameAnimalsThree = (() => {
|
|
|
1702
3262
|
return releaseObject3D(list2, { keep });
|
|
1703
3263
|
}
|
|
1704
3264
|
|
|
3265
|
+
// src/profile.ts
|
|
3266
|
+
var profileGeometry = (THREE, length, profile, segments) => {
|
|
3267
|
+
const points = profile.map((radius, index) => new THREE.Vector2(index / (profile.length - 1), radius));
|
|
3268
|
+
const curve = new THREE.SplineCurve(points);
|
|
3269
|
+
const outline = [];
|
|
3270
|
+
outline.push(new THREE.Vector2(1e-3, -length / 2 - 0));
|
|
3271
|
+
for (let step = 0; step <= 30; step++) {
|
|
3272
|
+
const point = curve.getPoint(step / 30);
|
|
3273
|
+
outline.push(new THREE.Vector2(Math.max(1e-3, point.y), -length / 2 + point.x * length));
|
|
3274
|
+
}
|
|
3275
|
+
outline.push(new THREE.Vector2(1e-3, length / 2));
|
|
3276
|
+
return new (shapeGeometries(THREE)).LatheGeometry(outline, segments || 22).rotateX(Math.PI / 2);
|
|
3277
|
+
};
|
|
3278
|
+
|
|
3279
|
+
// src/textures.ts
|
|
3280
|
+
var canvasTexture = (THREE, document2, width, height, draw) => {
|
|
3281
|
+
const canvas = document2.createElement("canvas");
|
|
3282
|
+
canvas.width = width;
|
|
3283
|
+
canvas.height = height;
|
|
3284
|
+
draw(canvas.getContext("2d"), width, height);
|
|
3285
|
+
const texture = new THREE.CanvasTexture(canvas);
|
|
3286
|
+
texture.colorSpace = THREE.SRGBColorSpace;
|
|
3287
|
+
return texture;
|
|
3288
|
+
};
|
|
3289
|
+
var spotsTexture = (THREE, document2, base, spot) => canvasTexture(THREE, document2, 256, 256, (painter, width, height) => {
|
|
3290
|
+
painter.fillStyle = base;
|
|
3291
|
+
painter.fillRect(0, 0, width, height);
|
|
3292
|
+
const next = createStream(11);
|
|
3293
|
+
for (let index = 0; index < 70; index++) {
|
|
3294
|
+
const x = next() * width;
|
|
3295
|
+
const y = next() * height;
|
|
3296
|
+
const radius = 5 + next() * 7;
|
|
3297
|
+
painter.strokeStyle = spot;
|
|
3298
|
+
painter.lineWidth = 3;
|
|
3299
|
+
painter.beginPath();
|
|
3300
|
+
painter.arc(x, y, radius, 0, 7);
|
|
3301
|
+
painter.stroke();
|
|
3302
|
+
painter.fillStyle = "rgba(120,70,20,.45)";
|
|
3303
|
+
painter.beginPath();
|
|
3304
|
+
painter.arc(x, y, radius * 0.6, 0, 7);
|
|
3305
|
+
painter.fill();
|
|
3306
|
+
}
|
|
3307
|
+
for (let index = 0; index < 60; index++) {
|
|
3308
|
+
painter.fillStyle = spot;
|
|
3309
|
+
painter.beginPath();
|
|
3310
|
+
painter.arc(next() * width, next() * height, 1.5 + next() * 2.5, 0, 7);
|
|
3311
|
+
painter.fill();
|
|
3312
|
+
}
|
|
3313
|
+
});
|
|
3314
|
+
var stripesTexture = (THREE, document2, base, stripe) => canvasTexture(THREE, document2, 128, 128, (painter, width) => {
|
|
3315
|
+
painter.fillStyle = base;
|
|
3316
|
+
painter.fillRect(0, 0, width, 128);
|
|
3317
|
+
painter.fillStyle = stripe;
|
|
3318
|
+
for (let index = 0; index < 9; index++) painter.fillRect(0, index * 14 + index % 2 * 3, width, 4);
|
|
3319
|
+
});
|
|
3320
|
+
var createCoatTexture = (THREE, document2, marker) => marker.kind === "stripes" ? stripesTexture(THREE, document2, marker.base, marker.stripe) : spotsTexture(THREE, document2, marker.base, marker.spot);
|
|
3321
|
+
|
|
3322
|
+
// src/visual-state.ts
|
|
3323
|
+
var INFECTED_TINT = 8227430;
|
|
3324
|
+
var POOL_COLOR = 3803142;
|
|
3325
|
+
var applyVisualState = (THREE, rig, state) => {
|
|
3326
|
+
rig.infected = state === "infected";
|
|
3327
|
+
rig.dead = state === "dead";
|
|
3328
|
+
const tint = new THREE.Color(INFECTED_TINT);
|
|
3329
|
+
rig.materials.forEach((material) => {
|
|
3330
|
+
if (material === rig.eyeMaterial || material === rig.woundMaterial) return;
|
|
3331
|
+
material.color.copy(material.userData.base);
|
|
3332
|
+
if (rig.infected) material.color.lerp(tint, 0.45).multiplyScalar(0.72);
|
|
3333
|
+
});
|
|
3334
|
+
const eye = rig.eyeMaterial;
|
|
3335
|
+
if (eye) {
|
|
3336
|
+
if (rig.infected) {
|
|
3337
|
+
eye.color.set(14473392);
|
|
3338
|
+
eye.emissive = new THREE.Color(9078368);
|
|
3339
|
+
eye.emissiveIntensity = 0.8;
|
|
3340
|
+
} else {
|
|
3341
|
+
eye.color.copy(eye.userData.base);
|
|
3342
|
+
eye.emissive = new THREE.Color(0);
|
|
3343
|
+
}
|
|
3344
|
+
}
|
|
3345
|
+
rig.infectionParts.forEach((part) => part.visible = rig.infected);
|
|
3346
|
+
const firstEar = rig.ears[0];
|
|
3347
|
+
if (firstEar) firstEar.visible = !rig.infected;
|
|
3348
|
+
if (!rig.dead) {
|
|
3349
|
+
rig.root.rotation.z = 0;
|
|
3350
|
+
rig.root.position.y = 0;
|
|
3351
|
+
}
|
|
3352
|
+
if (rig.pool) {
|
|
3353
|
+
rig.pool.visible = rig.dead;
|
|
3354
|
+
return;
|
|
3355
|
+
}
|
|
3356
|
+
if (!rig.dead) return;
|
|
3357
|
+
const pool = new THREE.Mesh(new THREE.CircleGeometry(1, 22).rotateX(-Math.PI / 2), new THREE.MeshStandardMaterial({ color: POOL_COLOR, roughness: 0.25 }));
|
|
3358
|
+
pool.position.set(rig.home.x, 5e-3, rig.home.z + 0.1);
|
|
3359
|
+
pool.receiveShadow = true;
|
|
3360
|
+
pool.scale.setScalar(rig.size * 0.45);
|
|
3361
|
+
rig.root.parent?.add(pool);
|
|
3362
|
+
rig.pool = pool;
|
|
3363
|
+
};
|
|
3364
|
+
|
|
3365
|
+
// src/views.ts
|
|
3366
|
+
var setJointView = (rig, on, jointMaterial) => {
|
|
3367
|
+
rig.materials.forEach((material) => {
|
|
3368
|
+
if (material === rig.eyeMaterial) return;
|
|
3369
|
+
material.transparent = on;
|
|
3370
|
+
material.opacity = on ? 0.28 : 1;
|
|
3371
|
+
material.depthWrite = !on;
|
|
3372
|
+
material.needsUpdate = true;
|
|
3373
|
+
});
|
|
3374
|
+
rig.joints.forEach((joint) => {
|
|
3375
|
+
var _a;
|
|
3376
|
+
if (on) (_a = joint.userData).restMaterial ?? (_a.restMaterial = joint.material);
|
|
3377
|
+
joint.material = on ? jointMaterial : joint.userData.restMaterial;
|
|
3378
|
+
joint.renderOrder = on ? 2 : 0;
|
|
3379
|
+
});
|
|
3380
|
+
};
|
|
3381
|
+
var setSplit = (rig, on) => {
|
|
3382
|
+
rig.pivots.forEach((pivot) => {
|
|
3383
|
+
pivot.group.userData.target = on ? pivot.rest.clone().add(pivot.offset) : pivot.rest.clone();
|
|
3384
|
+
});
|
|
3385
|
+
};
|
|
3386
|
+
var updateSplit = (rig, delta) => {
|
|
3387
|
+
rig.pivots.forEach((pivot) => {
|
|
3388
|
+
const target = pivot.group.userData.target;
|
|
3389
|
+
if (target) pivot.group.position.lerp(target, Math.min(1, delta * 5));
|
|
3390
|
+
});
|
|
3391
|
+
};
|
|
3392
|
+
|
|
1705
3393
|
// ../game-props3d/dist/index.js
|
|
1706
3394
|
var T = (id, interior, w, d, h, y, solid, group) => ({ id, interior, w, d, h, y, solid, group });
|
|
1707
3395
|
var TYPE_DEFS = [
|
|
@@ -2062,112 +3750,27 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
2062
3750
|
};
|
|
2063
3751
|
var animateSnake = (THREE, rig, params) => {
|
|
2064
3752
|
const { time: t, delta: dt, clip } = params;
|
|
2065
|
-
const spacing = rig.segmentLength * (params.split ? 1.5 : 1);
|
|
2066
|
-
if (clip === "walk") rig.phase += dt * 2.4;
|
|
2067
|
-
const points = bodyPath(THREE, rig, params, spacing);
|
|
2068
|
-
const at = (index) => points[index];
|
|
2069
|
-
for (let index = 0; index < rig.segmentCount; index++) {
|
|
2070
|
-
const group = rig.segments[index].group;
|
|
2071
|
-
group.position.copy(at(index));
|
|
2072
|
-
const direction = index === 0 ? at(0).clone().sub(at(1)) : at(index - 1).clone().sub(at(index));
|
|
2073
|
-
group.rotation.set(0, Math.atan2(direction.x, direction.z), 0);
|
|
2074
|
-
group.rotateX(-Math.atan2(direction.y, Math.hypot(direction.x, direction.z)));
|
|
2075
|
-
}
|
|
2076
|
-
const head = rig.head;
|
|
2077
|
-
const headDirection = at(0).clone().sub(at(1)).normalize();
|
|
2078
|
-
head.position.copy(at(0)).addScaledVector(headDirection, 0.02);
|
|
2079
|
-
head.rotation.set(0, Math.atan2(headDirection.x, headDirection.z), 0);
|
|
2080
|
-
head.rotateX(-Math.atan2(headDirection.y, Math.hypot(headDirection.x, headDirection.z)) * 0.5);
|
|
2081
|
-
const jaw = rig.jaw;
|
|
2082
|
-
jaw.rotation.x = clip === "run" ? Math.max(0, Math.sin(t * 2.2)) ** 6 * 0.9 : 0;
|
|
2083
|
-
const tongue = rig.tongue;
|
|
2084
|
-
tongue.visible = Math.sin(t * 5) > 0.3;
|
|
2085
|
-
tongue.scale.z = 1 + Math.sin(t * 20) * 0.3;
|
|
2086
|
-
};
|
|
2087
|
-
|
|
2088
|
-
// src/context.ts
|
|
2089
|
-
var createStream = (seed) => {
|
|
2090
|
-
let state = seed;
|
|
2091
|
-
return () => {
|
|
2092
|
-
state |= 0;
|
|
2093
|
-
state = state + 1831565813 | 0;
|
|
2094
|
-
let t = Math.imul(state ^ state >>> 15, 1 | state);
|
|
2095
|
-
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
|
|
2096
|
-
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
2097
|
-
};
|
|
2098
|
-
};
|
|
2099
|
-
var addMesh = (THREE, parent, geometry, material, x, y, z, rx, ry, rz) => {
|
|
2100
|
-
const mesh2 = new THREE.Mesh(geometry, material);
|
|
2101
|
-
mesh2.position.set(x || 0, y || 0, z || 0);
|
|
2102
|
-
if (rx || ry || rz) mesh2.rotation.set(rx || 0, ry || 0, rz || 0);
|
|
2103
|
-
mesh2.castShadow = true;
|
|
2104
|
-
mesh2.receiveShadow = true;
|
|
2105
|
-
parent.add(mesh2);
|
|
2106
|
-
return mesh2;
|
|
2107
|
-
};
|
|
2108
|
-
var createRigTools = (THREE, rig) => {
|
|
2109
|
-
const tools = {
|
|
2110
|
-
material(color2, extras) {
|
|
2111
|
-
const material = new THREE.MeshStandardMaterial(Object.assign({ color: color2, roughness: 0.8, metalness: 0, flatShading: false }, extras || {}));
|
|
2112
|
-
material.userData.base = material.color.clone();
|
|
2113
|
-
rig.materials.push(material);
|
|
2114
|
-
return material;
|
|
2115
|
-
},
|
|
2116
|
-
ball(parent, radius, material, x, y, z, sx, sy, sz) {
|
|
2117
|
-
const mesh2 = addMesh(THREE, parent, new THREE.SphereGeometry(radius, 16, 12), material, x, y, z);
|
|
2118
|
-
if (sx) mesh2.scale.set(sx, sy, sz);
|
|
2119
|
-
return mesh2;
|
|
2120
|
-
},
|
|
2121
|
-
limb: (parent, radius1, radius2, length, material) => addMesh(THREE, parent, new THREE.CylinderGeometry(radius2, radius1, length, 14, 1).translate(0, -length / 2, 0), material),
|
|
2122
|
-
joint(parent, radius, material, x, y, z) {
|
|
2123
|
-
const joint = tools.ball(parent, radius, material, x, y, z);
|
|
2124
|
-
joint.userData.joint = 1;
|
|
2125
|
-
rig.joints.push(joint);
|
|
2126
|
-
return joint;
|
|
2127
|
-
},
|
|
2128
|
-
pivot(parent, x, y, z, offset) {
|
|
2129
|
-
const group = new THREE.Group();
|
|
2130
|
-
group.position.set(x, y, z);
|
|
2131
|
-
parent.add(group);
|
|
2132
|
-
rig.pivots.push({ group, rest: group.position.clone(), offset: offset || new THREE.Vector3() });
|
|
2133
|
-
return group;
|
|
2134
|
-
},
|
|
2135
|
-
eyes(head, radius, x, y, z) {
|
|
2136
|
-
const eyeMaterial = tools.material(1118481, { roughness: 0.25 });
|
|
2137
|
-
rig.eyeMaterial = eyeMaterial;
|
|
2138
|
-
for (const side of [-1, 1]) rig.eyes.push(tools.ball(head, radius, eyeMaterial, side * x, y, z));
|
|
2139
|
-
}
|
|
2140
|
-
};
|
|
2141
|
-
return tools;
|
|
2142
|
-
};
|
|
2143
|
-
var createRig = (THREE, species, options) => {
|
|
2144
|
-
const rig = {
|
|
2145
|
-
species,
|
|
2146
|
-
root: new THREE.Group(),
|
|
2147
|
-
trunk: new THREE.Group(),
|
|
2148
|
-
materials: [],
|
|
2149
|
-
joints: [],
|
|
2150
|
-
pivots: [],
|
|
2151
|
-
legs: [],
|
|
2152
|
-
tail: [],
|
|
2153
|
-
ears: [],
|
|
2154
|
-
infectionParts: [],
|
|
2155
|
-
eyes: [],
|
|
2156
|
-
wings: [],
|
|
2157
|
-
segments: [],
|
|
2158
|
-
phase: options.phase,
|
|
2159
|
-
size: 1,
|
|
2160
|
-
segmentLength: 0,
|
|
2161
|
-
segmentCount: 0,
|
|
2162
|
-
home: new THREE.Vector3(),
|
|
2163
|
-
infected: false,
|
|
2164
|
-
dead: false,
|
|
2165
|
-
neckAngle: 0,
|
|
2166
|
-
headAngle: 0,
|
|
2167
|
-
triangles: 0
|
|
2168
|
-
};
|
|
2169
|
-
rig.root.add(rig.trunk);
|
|
2170
|
-
return rig;
|
|
3753
|
+
const spacing = rig.segmentLength * (params.split ? 1.5 : 1);
|
|
3754
|
+
if (clip === "walk") rig.phase += dt * 2.4;
|
|
3755
|
+
const points = bodyPath(THREE, rig, params, spacing);
|
|
3756
|
+
const at = (index) => points[index];
|
|
3757
|
+
for (let index = 0; index < rig.segmentCount; index++) {
|
|
3758
|
+
const group = rig.segments[index].group;
|
|
3759
|
+
group.position.copy(at(index));
|
|
3760
|
+
const direction = index === 0 ? at(0).clone().sub(at(1)) : at(index - 1).clone().sub(at(index));
|
|
3761
|
+
group.rotation.set(0, Math.atan2(direction.x, direction.z), 0);
|
|
3762
|
+
group.rotateX(-Math.atan2(direction.y, Math.hypot(direction.x, direction.z)));
|
|
3763
|
+
}
|
|
3764
|
+
const head = rig.head;
|
|
3765
|
+
const headDirection = at(0).clone().sub(at(1)).normalize();
|
|
3766
|
+
head.position.copy(at(0)).addScaledVector(headDirection, 0.02);
|
|
3767
|
+
head.rotation.set(0, Math.atan2(headDirection.x, headDirection.z), 0);
|
|
3768
|
+
head.rotateX(-Math.atan2(headDirection.y, Math.hypot(headDirection.x, headDirection.z)) * 0.5);
|
|
3769
|
+
const jaw = rig.jaw;
|
|
3770
|
+
jaw.rotation.x = clip === "run" ? Math.max(0, Math.sin(t * 2.2)) ** 6 * 0.9 : 0;
|
|
3771
|
+
const tongue = rig.tongue;
|
|
3772
|
+
tongue.visible = Math.sin(t * 5) > 0.3;
|
|
3773
|
+
tongue.scale.z = 1 + Math.sin(t * 20) * 0.3;
|
|
2171
3774
|
};
|
|
2172
3775
|
|
|
2173
3776
|
// src/bird.ts
|
|
@@ -2254,94 +3857,6 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
2254
3857
|
return rig;
|
|
2255
3858
|
};
|
|
2256
3859
|
|
|
2257
|
-
// src/extras.ts
|
|
2258
|
-
var cow = ({ THREE, tools }, k) => {
|
|
2259
|
-
tools.ball(k.bodyGroup, 0.2, k.main, 0, k.Rb * 1.1, k.L * 0.33, 0.95, 1.1, 1.1);
|
|
2260
|
-
tools.ball(k.neck, 0.13, k.main, 0, 0.12, 0.08, 0.55, 1.4, 1.05);
|
|
2261
|
-
for (const side of [-1, 1]) addMesh(THREE, k.head, new THREE.ConeGeometry(0.025, 0.13, 8), tools.material(13616808), side * 0.12, k.hd.r * 1.05, k.hd.r * 0.05, 0, 0, side * -0.9);
|
|
2262
|
-
};
|
|
2263
|
-
var horse = ({ THREE, rig, tools }, k) => {
|
|
2264
|
-
for (let index = 0; index < 9; index++) addMesh(THREE, k.neck, new THREE.BoxGeometry(0.035, 0.16, 0.08), k.dark, 0, 0.06 + index * 0.065, -0.12 + index * 4e-3, -0.25, 0, 0);
|
|
2265
|
-
addMesh(THREE, k.head, new THREE.BoxGeometry(0.03, 0.12, 0.06), k.dark, 0, k.hd.r * 1.05, k.hd.r * 0.3, 0.6, 0, 0);
|
|
2266
|
-
const last = rig.tail[rig.tail.length - 1];
|
|
2267
|
-
tools.ball(last, 0.08, k.dark, 0, -0.42, 0, 0.7, 4.5, 0.7);
|
|
2268
|
-
};
|
|
2269
|
-
var wildBoar = ({ THREE, tools }, k) => {
|
|
2270
|
-
for (let index = 0; index < 12; index++) addMesh(THREE, k.bodyGroup, new THREE.BoxGeometry(0.03, 0.1, 0.06), k.dark, 0, k.Rb * 1.12 - index * 4e-3, k.L * 0.38 - index * 0.06, -0.2, 0, 0);
|
|
2271
|
-
for (const side of [-1, 1])
|
|
2272
|
-
addMesh(THREE, k.head, new THREE.ConeGeometry(0.012, 0.09, 6), tools.material(15261900), side * 0.07, k.hd.r * -0.25 + 0.03, k.hd.r * 0.25 + k.hd.r * k.hd.s[2] * 0.55 + 0.13, -0.6, 0, side * 0.5);
|
|
2273
|
-
};
|
|
2274
|
-
var chicken = ({ tools }, k) => {
|
|
2275
|
-
const red = tools.material(12593182);
|
|
2276
|
-
for (let index = 0; index < 4; index++) tools.ball(k.head, 0.014, red, 0, 0.045, -0.012 + index * 0.014, 0.5, 1, 0.8);
|
|
2277
|
-
tools.ball(k.head, 0.012, red, 0, -0.04, 0.04, 0.5, 1.3, 0.7);
|
|
2278
|
-
};
|
|
2279
|
-
var southernLapwing = ({ THREE, tools }, k) => {
|
|
2280
|
-
const black = tools.material(1447446);
|
|
2281
|
-
tools.ball(k.bodyGroup, 0.05, black, 0, 0.03, 0.08, 1.1, 0.9, 0.6);
|
|
2282
|
-
addMesh(THREE, k.head, new THREE.BoxGeometry(6e-3, 6e-3, 0.06).translate(0, 0, -0.03), black, 0, 0.025, -0.01, 0.5, 0, 0);
|
|
2283
|
-
tools.ball(k.head, 0.026, black, 0, -5e-3, 0.02, 1.05, 0.7, 0.9);
|
|
2284
|
-
};
|
|
2285
|
-
var QUADRUPED_EXTRAS = { cow, horse, wild_boar: wildBoar };
|
|
2286
|
-
var BIRD_EXTRAS = { chicken, southern_lapwing: southernLapwing };
|
|
2287
|
-
|
|
2288
|
-
// src/textures.ts
|
|
2289
|
-
var canvasTexture = (THREE, document2, width, height, draw) => {
|
|
2290
|
-
const canvas = document2.createElement("canvas");
|
|
2291
|
-
canvas.width = width;
|
|
2292
|
-
canvas.height = height;
|
|
2293
|
-
draw(canvas.getContext("2d"), width, height);
|
|
2294
|
-
const texture = new THREE.CanvasTexture(canvas);
|
|
2295
|
-
texture.colorSpace = THREE.SRGBColorSpace;
|
|
2296
|
-
return texture;
|
|
2297
|
-
};
|
|
2298
|
-
var spotsTexture = (THREE, document2, base, spot) => canvasTexture(THREE, document2, 256, 256, (painter, width, height) => {
|
|
2299
|
-
painter.fillStyle = base;
|
|
2300
|
-
painter.fillRect(0, 0, width, height);
|
|
2301
|
-
const next = createStream(11);
|
|
2302
|
-
for (let index = 0; index < 70; index++) {
|
|
2303
|
-
const x = next() * width;
|
|
2304
|
-
const y = next() * height;
|
|
2305
|
-
const radius = 5 + next() * 7;
|
|
2306
|
-
painter.strokeStyle = spot;
|
|
2307
|
-
painter.lineWidth = 3;
|
|
2308
|
-
painter.beginPath();
|
|
2309
|
-
painter.arc(x, y, radius, 0, 7);
|
|
2310
|
-
painter.stroke();
|
|
2311
|
-
painter.fillStyle = "rgba(120,70,20,.45)";
|
|
2312
|
-
painter.beginPath();
|
|
2313
|
-
painter.arc(x, y, radius * 0.6, 0, 7);
|
|
2314
|
-
painter.fill();
|
|
2315
|
-
}
|
|
2316
|
-
for (let index = 0; index < 60; index++) {
|
|
2317
|
-
painter.fillStyle = spot;
|
|
2318
|
-
painter.beginPath();
|
|
2319
|
-
painter.arc(next() * width, next() * height, 1.5 + next() * 2.5, 0, 7);
|
|
2320
|
-
painter.fill();
|
|
2321
|
-
}
|
|
2322
|
-
});
|
|
2323
|
-
var stripesTexture = (THREE, document2, base, stripe) => canvasTexture(THREE, document2, 128, 128, (painter, width) => {
|
|
2324
|
-
painter.fillStyle = base;
|
|
2325
|
-
painter.fillRect(0, 0, width, 128);
|
|
2326
|
-
painter.fillStyle = stripe;
|
|
2327
|
-
for (let index = 0; index < 9; index++) painter.fillRect(0, index * 14 + index % 2 * 3, width, 4);
|
|
2328
|
-
});
|
|
2329
|
-
var createCoatTexture = (THREE, document2, marker) => marker.kind === "stripes" ? stripesTexture(THREE, document2, marker.base, marker.stripe) : spotsTexture(THREE, document2, marker.base, marker.spot);
|
|
2330
|
-
|
|
2331
|
-
// src/profile.ts
|
|
2332
|
-
var profileGeometry = (THREE, length, profile, segments) => {
|
|
2333
|
-
const points = profile.map((radius, index) => new THREE.Vector2(index / (profile.length - 1), radius));
|
|
2334
|
-
const curve = new THREE.SplineCurve(points);
|
|
2335
|
-
const outline = [];
|
|
2336
|
-
outline.push(new THREE.Vector2(1e-3, -length / 2 - 0));
|
|
2337
|
-
for (let step = 0; step <= 30; step++) {
|
|
2338
|
-
const point = curve.getPoint(step / 30);
|
|
2339
|
-
outline.push(new THREE.Vector2(Math.max(1e-3, point.y), -length / 2 + point.x * length));
|
|
2340
|
-
}
|
|
2341
|
-
outline.push(new THREE.Vector2(1e-3, length / 2));
|
|
2342
|
-
return new (shapeGeometries(THREE)).LatheGeometry(outline, segments || 22).rotateX(Math.PI / 2);
|
|
2343
|
-
};
|
|
2344
|
-
|
|
2345
3860
|
// src/quadruped.ts
|
|
2346
3861
|
var RIB_COUNT = 4;
|
|
2347
3862
|
var LEG_DEFINITIONS = [
|
|
@@ -2537,303 +4052,261 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
2537
4052
|
return rig;
|
|
2538
4053
|
};
|
|
2539
4054
|
|
|
2540
|
-
// src/
|
|
2541
|
-
var
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
const
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
} else {
|
|
2559
|
-
eye.color.copy(eye.userData.base);
|
|
2560
|
-
eye.emissive = new THREE.Color(0);
|
|
2561
|
-
}
|
|
2562
|
-
}
|
|
2563
|
-
rig.infectionParts.forEach((part) => part.visible = rig.infected);
|
|
2564
|
-
const firstEar = rig.ears[0];
|
|
2565
|
-
if (firstEar) firstEar.visible = !rig.infected;
|
|
2566
|
-
if (!rig.dead) {
|
|
2567
|
-
rig.root.rotation.z = 0;
|
|
2568
|
-
rig.root.position.y = 0;
|
|
2569
|
-
}
|
|
2570
|
-
if (rig.pool) {
|
|
2571
|
-
rig.pool.visible = rig.dead;
|
|
2572
|
-
return;
|
|
2573
|
-
}
|
|
2574
|
-
if (!rig.dead) return;
|
|
2575
|
-
const pool = new THREE.Mesh(new THREE.CircleGeometry(1, 22).rotateX(-Math.PI / 2), new THREE.MeshStandardMaterial({ color: POOL_COLOR, roughness: 0.25 }));
|
|
2576
|
-
pool.position.set(rig.home.x, 5e-3, rig.home.z + 0.1);
|
|
2577
|
-
pool.receiveShadow = true;
|
|
2578
|
-
pool.scale.setScalar(rig.size * 0.45);
|
|
2579
|
-
rig.root.parent?.add(pool);
|
|
2580
|
-
rig.pool = pool;
|
|
2581
|
-
};
|
|
2582
|
-
|
|
2583
|
-
// src/views.ts
|
|
2584
|
-
var setJointView = (rig, on, jointMaterial) => {
|
|
2585
|
-
rig.materials.forEach((material) => {
|
|
2586
|
-
if (material === rig.eyeMaterial) return;
|
|
2587
|
-
material.transparent = on;
|
|
2588
|
-
material.opacity = on ? 0.28 : 1;
|
|
2589
|
-
material.depthWrite = !on;
|
|
2590
|
-
material.needsUpdate = true;
|
|
2591
|
-
});
|
|
2592
|
-
rig.joints.forEach((joint) => {
|
|
2593
|
-
var _a;
|
|
2594
|
-
if (on) (_a = joint.userData).restMaterial ?? (_a.restMaterial = joint.material);
|
|
2595
|
-
joint.material = on ? jointMaterial : joint.userData.restMaterial;
|
|
2596
|
-
joint.renderOrder = on ? 2 : 0;
|
|
2597
|
-
});
|
|
2598
|
-
};
|
|
2599
|
-
var setSplit = (rig, on) => {
|
|
2600
|
-
rig.pivots.forEach((pivot) => {
|
|
2601
|
-
pivot.group.userData.target = on ? pivot.rest.clone().add(pivot.offset) : pivot.rest.clone();
|
|
2602
|
-
});
|
|
2603
|
-
};
|
|
2604
|
-
var updateSplit = (rig, delta) => {
|
|
2605
|
-
rig.pivots.forEach((pivot) => {
|
|
2606
|
-
const target = pivot.group.userData.target;
|
|
2607
|
-
if (target) pivot.group.position.lerp(target, Math.min(1, delta * 5));
|
|
2608
|
-
});
|
|
2609
|
-
};
|
|
2610
|
-
|
|
2611
|
-
// ../game-audio/dist/index.js
|
|
2612
|
-
var DISTANCE_CURVES = {
|
|
2613
|
-
/** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
|
|
2614
|
-
game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
|
|
2615
|
-
/** The game's `grito`: `1 / (1 + d² × 0.006)`, silent below 0.02 (jogo L62129–62130). */
|
|
2616
|
-
game_scream: { model: "inverse_square", k: 6e-3, minGain: 0.02 },
|
|
2617
|
-
/** The game's `voz`: `1 / (1 + d² × 0.01)`, silent below 0.02 (jogo L62146–62147). */
|
|
2618
|
-
game_voice: { model: "inverse_square", k: 0.01, minGain: 0.02 },
|
|
2619
|
-
/** The game's `boom`: `1.4 / (1 + d² × 0.002)`, never silent (jogo L68280). */
|
|
2620
|
-
game_boom: { model: "inverse_square", k: 2e-3, scale: 1.4 },
|
|
2621
|
-
/** The art scene's `outAt`: `vol / (1 + d² × 0.008)` (cena L1320). */
|
|
2622
|
-
art_scene: { model: "inverse_square", k: 8e-3 },
|
|
2623
|
-
/** The game's animal calls: `max(0, 1 − d / 70) × 0.25`, silent at or below 0.005 (jogo L66627–66628). */
|
|
2624
|
-
animals: { model: "linear", range: 70, scale: 0.25, minGain: 5e-3 }
|
|
2625
|
-
};
|
|
2626
|
-
var mix_profiles_default = [
|
|
2627
|
-
{
|
|
2628
|
-
id: "game",
|
|
2629
|
-
master: 0.5,
|
|
2630
|
-
noise: { seconds: 1.5, create: "lazy" },
|
|
2631
|
-
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"]
|
|
2632
|
-
},
|
|
2633
|
-
{
|
|
2634
|
-
id: "art_scene",
|
|
2635
|
-
master: 0.85,
|
|
2636
|
-
compressor: { threshold: -12, ratio: 5 },
|
|
2637
|
-
reverb: { seconds: 2.2, decay: 3.4, wet: 0.4 },
|
|
2638
|
-
noise: { seconds: 2, create: "eager" },
|
|
2639
|
-
sources: [
|
|
2640
|
-
"cena:L1308 compressor -12 dB, ratio 5",
|
|
2641
|
-
"cena:L1309 master 0.85",
|
|
2642
|
-
"cena:L1310 convolver, impulse 2.2 s of (1 - i/len)^3.4",
|
|
2643
|
-
"cena:L1311 wet 0.4",
|
|
2644
|
-
"cena:L1312 noise 2 s made with the chain"
|
|
2645
|
-
]
|
|
2646
|
-
}
|
|
2647
|
-
];
|
|
2648
|
-
var MIX_PROFILES = Object.fromEntries(
|
|
2649
|
-
mix_profiles_default.map((profile) => [profile.id, profile])
|
|
2650
|
-
);
|
|
2651
|
-
var game_sfx_default = {
|
|
2652
|
-
sources: ["jogo:L62089-62107"],
|
|
2653
|
-
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`.",
|
|
2654
|
-
classes: [
|
|
2655
|
-
{ id: "pistol", team: "pistola", bus: "weapons", cutoff: 1800, gain: 0.9, seconds: 0.18 },
|
|
2656
|
-
{ id: "shotgun", team: "escopeta", bus: "weapons", cutoff: 900, gain: 1.2, seconds: 0.35 },
|
|
2657
|
-
{ id: "rifle", team: "fuzil", bus: "weapons", cutoff: 1400, gain: 1.1, seconds: 0.28 },
|
|
2658
|
-
{ id: "long_rifle", team: "rifle", bus: "weapons", cutoff: 1100, gain: 1.3, seconds: 0.45 },
|
|
2659
|
-
{ id: "impact", team: "impacto", bus: "world", cutoff: 2500, gain: 0.25, seconds: 0.05 },
|
|
2660
|
-
{ id: "flesh", team: "carne", bus: "world", cutoff: 600, gain: 0.35, seconds: 0.08 },
|
|
2661
|
-
{ id: "step", team: "passo", bus: "world", cutoff: 400, gain: 0.08, seconds: 0.05 },
|
|
2662
|
-
{ id: "glass", team: "vidro", bus: "world", cutoff: 5e3, gain: 0.5, seconds: 0.3 },
|
|
2663
|
-
{ id: "wood", team: "madeira", bus: "world", cutoff: 700, gain: 0.5, seconds: 0.2 },
|
|
2664
|
-
{ id: "reload", team: "recarga", bus: "weapons", cutoff: 3e3, gain: 0.15, seconds: 0.06 },
|
|
2665
|
-
{ id: "empty", team: "vazio", bus: "weapons", cutoff: 4e3, gain: 0.12, seconds: 0.03 },
|
|
2666
|
-
{ id: "explosion", team: "explosao", bus: "world", cutoff: 200, gain: 1.6, seconds: 1.4 }
|
|
2667
|
-
],
|
|
2668
|
-
fallback: { id: "unknown", team: "(any other name)", bus: "world", cutoff: 1e3, gain: 0.5, seconds: 0.1 }
|
|
2669
|
-
};
|
|
2670
|
-
var GAME_SFX = game_sfx_default;
|
|
2671
|
-
var GAME_SFX_CLASSES = GAME_SFX.classes;
|
|
2672
|
-
var GAME_SFX_FALLBACK = GAME_SFX.fallback;
|
|
2673
|
-
function noiseClassRecipe(row, id = `sfx_${row.id}`) {
|
|
2674
|
-
return {
|
|
2675
|
-
id,
|
|
2676
|
-
bus: row.bus,
|
|
2677
|
-
order: "burst",
|
|
2678
|
-
duration: row.seconds,
|
|
2679
|
-
tail: 0.05,
|
|
2680
|
-
layers: [
|
|
2681
|
-
{
|
|
2682
|
-
source: { kind: "noise", offset: "random" },
|
|
2683
|
-
filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: row.cutoff } }] },
|
|
2684
|
-
envelope: [
|
|
2685
|
-
[0, row.gain, "set"],
|
|
2686
|
-
["1d", 1e-3, "exp", "fixed"]
|
|
2687
|
-
]
|
|
2688
|
-
}
|
|
2689
|
-
],
|
|
2690
|
-
falloff: DISTANCE_CURVES.game_sfx,
|
|
2691
|
-
sources: [...GAME_SFX.sources.map((source) => `${source} ${row.team}`)]
|
|
4055
|
+
// src/animals-three.ts
|
|
4056
|
+
var countTriangles = (root) => {
|
|
4057
|
+
let triangles = 0;
|
|
4058
|
+
root.traverse((object2) => {
|
|
4059
|
+
const mesh2 = object2;
|
|
4060
|
+
if (!mesh2.isMesh) return;
|
|
4061
|
+
const geometry = mesh2.geometry;
|
|
4062
|
+
triangles += geometry.index ? geometry.index.count / 3 : geometry.attributes.position.count / 3;
|
|
4063
|
+
});
|
|
4064
|
+
return Math.round(triangles);
|
|
4065
|
+
};
|
|
4066
|
+
var createAnimalsThree = (host, options = {}) => {
|
|
4067
|
+
const THREE = shapeGeometries(host);
|
|
4068
|
+
const random = options.random ?? createStream(options.seed ?? 7);
|
|
4069
|
+
const documentOf = () => {
|
|
4070
|
+
const found = options.document ?? globalThis.document;
|
|
4071
|
+
if (!found) throw new Error("game-animals-three: a species with a coat texture needs `options.document` (no global document found)");
|
|
4072
|
+
return found;
|
|
2692
4073
|
};
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
envelope: [
|
|
2709
|
-
[0, 1e-4, "set", "fixed"],
|
|
2710
|
-
[2e-3, 1, "exp"],
|
|
2711
|
-
["1d", 1e-4, "exp", "fixed"]
|
|
2712
|
-
]
|
|
2713
|
-
}
|
|
2714
|
-
],
|
|
2715
|
-
falloff: DISTANCE_CURVES.art_scene,
|
|
2716
|
-
sources: ["sdk: bench probe, a 880 Hz ping through the art scene output stage"]
|
|
4074
|
+
const jointMaterial = new THREE.MeshStandardMaterial({ color: 14722376, emissive: 14722376, emissiveIntensity: 0.8, roughness: 0.4 });
|
|
4075
|
+
const gaits = GAIT_PHASES;
|
|
4076
|
+
return {
|
|
4077
|
+
jointMaterial,
|
|
4078
|
+
build(species, buildOptions = {}) {
|
|
4079
|
+
const rig = createRig(THREE, species, { phase: buildOptions.phase ?? random() * 6 });
|
|
4080
|
+
if (species.body.kind === "snake") buildSnake(THREE, rig);
|
|
4081
|
+
else if (species.body.kind === "bird") buildBird(THREE, rig, { extra: BIRD_EXTRAS[species.id] });
|
|
4082
|
+
else buildQuadruped(THREE, rig, { document: species.body.texture ? documentOf() : void 0, extra: QUADRUPED_EXTRAS[species.id] });
|
|
4083
|
+
rig.triangles = countTriangles(rig.root);
|
|
4084
|
+
markKitOrigin(rig.root, { owner: "game-animals-three", kind: "animal", id: species.id });
|
|
4085
|
+
rig.root.traverse((object2) => {
|
|
4086
|
+
if (object2.isMesh) object2.userData.speciesId = species.id;
|
|
4087
|
+
});
|
|
4088
|
+
return rig;
|
|
2717
4089
|
},
|
|
2718
|
-
{
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
[2e-3, 1, "exp"],
|
|
2731
|
-
["1d", 1e-4, "exp", "fixed"]
|
|
2732
|
-
]
|
|
2733
|
-
}
|
|
2734
|
-
],
|
|
2735
|
-
falloff: DISTANCE_CURVES.art_scene,
|
|
2736
|
-
sources: ["sdk: bench probe, a highpass hiss of random length"]
|
|
2737
|
-
}
|
|
2738
|
-
]
|
|
4090
|
+
animate(rig, params) {
|
|
4091
|
+
const kind = rig.species.body.kind;
|
|
4092
|
+
if (kind === "snake") animateSnake(THREE, rig, params);
|
|
4093
|
+
else if (kind === "bird") animateBird(rig, params);
|
|
4094
|
+
else animateQuadruped(rig, params, gaits);
|
|
4095
|
+
},
|
|
4096
|
+
setVisualState: (rig, state) => applyVisualState(THREE, rig, state),
|
|
4097
|
+
setJointView: (rig, on) => setJointView(rig, on, jointMaterial),
|
|
4098
|
+
setSplit,
|
|
4099
|
+
updateSplit,
|
|
4100
|
+
createSkin: (rig) => createNodeSkin(THREE, rig.root, { nodes: collectReferencedNodes(rig, ["species"]) })
|
|
4101
|
+
};
|
|
2739
4102
|
};
|
|
2740
4103
|
|
|
2741
|
-
//
|
|
2742
|
-
var
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
{
|
|
2752
|
-
repeat: { count: o.count, spacing: o.spacing },
|
|
2753
|
-
source: { kind: "osc", wave: o.wave, frequency: { from: o.frequency, to: o.frequency * o.drop, curve: "exp", over: "duration" } },
|
|
2754
|
-
filters: { mode: "serial", bank: [{ type: "bandpass", frequency: { set: o.frequency * 1.2 }, q: 3 }] },
|
|
2755
|
-
envelope: [
|
|
2756
|
-
[0, 1e-4, "set", "fixed"],
|
|
2757
|
-
[0.015, 1, "exp"],
|
|
2758
|
-
["1d", 1e-4, "exp", "fixed"]
|
|
2759
|
-
]
|
|
2760
|
-
}
|
|
2761
|
-
],
|
|
2762
|
-
falloff: DISTANCE_CURVES.animals,
|
|
2763
|
-
sources: [`jogo:L66625-66639 bichoSom('${o.team}')`]
|
|
2764
|
-
});
|
|
2765
|
-
var DOG_BARK = call({ id: "dog_bark", team: "latido", count: 2, spacing: 0.22, seconds: 0.12, wave: "square", frequency: 520, drop: 0.6 });
|
|
2766
|
-
var LAPWING_CALL = call({ id: "lapwing_call", team: "queroquero", count: 3, spacing: 0.14, seconds: 0.09, wave: "square", frequency: 2400, drop: 0.6 });
|
|
2767
|
-
var HEN_CLUCK = call({ id: "hen_cluck", team: "cacarejo", count: 4, spacing: 0.14, seconds: 0.09, wave: "square", frequency: 900, drop: 0.6 });
|
|
2768
|
-
var COW_MOO = call({ id: "cow_moo", team: "mugido", count: 1, spacing: 0.14, seconds: 1.2, wave: "sawtooth", frequency: 140, drop: 0.8 });
|
|
2769
|
-
var ANIMAL_SOUNDS = [DOG_BARK, LAPWING_CALL, HEN_CLUCK, COW_MOO];
|
|
2770
|
-
var ANIMAL_SOUND_BANK = { id: "animals_three", sounds: ANIMAL_SOUNDS };
|
|
2771
|
-
|
|
2772
|
-
// src/audio/calls.json
|
|
2773
|
-
var calls_default = {
|
|
2774
|
-
sources: [
|
|
2775
|
-
"jogo:L66677 galinha: cacarejo, 6 s between calls, noise 30 m",
|
|
2776
|
-
"jogo:L66680 quero-quero: queroquero when the player is near (alarme), 8 s, noise 40 m",
|
|
2777
|
-
"jogo:L66681 vaca: mugido, 30 s, noise 80 m",
|
|
2778
|
-
"jogo:L66683 cachorro: latido when a zombie is within 12 m, 3 s, noise 60 m"
|
|
2779
|
-
],
|
|
2780
|
-
species: {
|
|
2781
|
-
chicken: { sound: "hen_cluck", cooldown: 6, noiseMetres: 30 },
|
|
2782
|
-
southern_lapwing: { sound: "lapwing_call", cooldown: 8, noiseMetres: 40 },
|
|
2783
|
-
cow: { sound: "cow_moo", cooldown: 30, noiseMetres: 80 },
|
|
2784
|
-
dog: { sound: "dog_bark", cooldown: 3, noiseMetres: 60 }
|
|
4104
|
+
// ../game-render-three/dist/index.js
|
|
4105
|
+
var DEFAULT_ANGLE = Math.PI / 3;
|
|
4106
|
+
var EFFECT_STEP_SECONDS = 1 / 50;
|
|
4107
|
+
var BATCHED_LAYER = 30;
|
|
4108
|
+
var MATRIX_EPSILON = 1e-6;
|
|
4109
|
+
var ATTRIBUTES = ["position", "normal", "uv", "color"];
|
|
4110
|
+
var isShown = (object2, root) => {
|
|
4111
|
+
for (let node = object2; node; node = node.parent) {
|
|
4112
|
+
if (node === root) return true;
|
|
4113
|
+
if (!node.visible) return false;
|
|
2785
4114
|
}
|
|
4115
|
+
return false;
|
|
2786
4116
|
};
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
const
|
|
2795
|
-
const
|
|
2796
|
-
|
|
4117
|
+
var isBatchable = (mesh2) => {
|
|
4118
|
+
const flags = mesh2;
|
|
4119
|
+
if (flags.isInstancedMesh === true || flags.isSkinnedMesh === true || Array.isArray(mesh2.material)) return false;
|
|
4120
|
+
const geometry = mesh2.geometry;
|
|
4121
|
+
return geometry.attributes.position !== void 0 && Object.keys(geometry.morphAttributes).length === 0;
|
|
4122
|
+
};
|
|
4123
|
+
var signatureOf = (mesh2) => {
|
|
4124
|
+
const { attributes } = mesh2.geometry;
|
|
4125
|
+
const present = ATTRIBUTES.filter((name) => attributes[name] !== void 0).map((name) => `${name}${attributes[name].itemSize}`);
|
|
4126
|
+
return `${mesh2.material.uuid}|${present.join(",")}|${mesh2.castShadow ? 1 : 0}${mesh2.receiveShadow ? 1 : 0}`;
|
|
4127
|
+
};
|
|
4128
|
+
var sameMatrix = (a, b) => a.elements.every((value, index) => Math.abs(value - b.elements[index]) < MATRIX_EPSILON);
|
|
4129
|
+
function createStaticBatcher(THREE, root, options = {}) {
|
|
4130
|
+
const include = options.include ?? (() => true);
|
|
4131
|
+
const follow = options.followMeshes === true;
|
|
4132
|
+
root.updateMatrixWorld(true);
|
|
4133
|
+
const inverse = new THREE.Matrix4().copy(root.matrixWorld).invert();
|
|
4134
|
+
const groups = /* @__PURE__ */ new Map();
|
|
4135
|
+
root.traverse((object2) => {
|
|
4136
|
+
const mesh2 = object2;
|
|
4137
|
+
if (!mesh2.isMesh || !isShown(mesh2, root) || !isBatchable(mesh2) || !include(mesh2)) return;
|
|
4138
|
+
const key = signatureOf(mesh2);
|
|
4139
|
+
groups.set(key, [...groups.get(key) ?? [], mesh2]);
|
|
4140
|
+
});
|
|
4141
|
+
const group = new THREE.Group();
|
|
4142
|
+
group.name = "static-batches";
|
|
4143
|
+
const sources = [];
|
|
4144
|
+
const pending = [...groups.values()].filter((meshes) => meshes.length >= 2);
|
|
4145
|
+
const mergeSome = (deadline) => {
|
|
4146
|
+
while (pending.length > 0) {
|
|
4147
|
+
const meshes = pending.shift();
|
|
4148
|
+
if (meshes.every((mesh2) => isShown(mesh2, root))) sources.push(...mergeGroup(THREE, { meshes, inverse: new THREE.Matrix4().copy(root.matrixWorld).invert(), group, follow }));
|
|
4149
|
+
if (performance.now() >= deadline) return;
|
|
4150
|
+
}
|
|
4151
|
+
};
|
|
4152
|
+
if (options.budgetMs === void 0) mergeSome(Number.POSITIVE_INFINITY);
|
|
4153
|
+
root.add(group);
|
|
4154
|
+
const scratch = new THREE.Matrix4();
|
|
4155
|
+
let released = 0;
|
|
4156
|
+
const release = (source) => {
|
|
4157
|
+
source.released = true;
|
|
4158
|
+
source.mesh.layers.mask = source.mask;
|
|
4159
|
+
const { index } = source.batch;
|
|
4160
|
+
const first = index.array[source.start];
|
|
4161
|
+
for (let at = source.start; at < source.start + source.count; at++) index.array[at] = first;
|
|
4162
|
+
index.needsUpdate = true;
|
|
4163
|
+
if (--source.batch.live === 0) source.batch.mesh.visible = false;
|
|
4164
|
+
released++;
|
|
4165
|
+
};
|
|
4166
|
+
const hasChanged = (source) => {
|
|
4167
|
+
const { mesh: mesh2 } = source;
|
|
4168
|
+
if (mesh2.geometry !== source.geometry || mesh2.material !== source.material || !isShown(mesh2, root)) return true;
|
|
4169
|
+
if (mesh2.geometry.attributes.position.version !== source.version) return true;
|
|
4170
|
+
if (follow || sameMatrix(mesh2.matrixWorld, source.world)) return false;
|
|
4171
|
+
if (!sameMatrix(scratch.multiplyMatrices(inverse, mesh2.matrixWorld), source.local)) return true;
|
|
4172
|
+
source.world.copy(mesh2.matrixWorld);
|
|
4173
|
+
return false;
|
|
4174
|
+
};
|
|
2797
4175
|
return {
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
if (
|
|
2804
|
-
|
|
2805
|
-
sink.play({ sound: found.sound, position, ...o.volume === void 0 ? {} : { volume: o.volume } });
|
|
2806
|
-
return true;
|
|
4176
|
+
group,
|
|
4177
|
+
update() {
|
|
4178
|
+
if (pending.length > 0) mergeSome(performance.now() + (options.budgetMs ?? Number.POSITIVE_INFINITY));
|
|
4179
|
+
const before = released;
|
|
4180
|
+
inverse.copy(root.matrixWorld).invert();
|
|
4181
|
+
for (const source of sources) if (!source.released && hasChanged(source)) release(source);
|
|
4182
|
+
return released - before;
|
|
2807
4183
|
},
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
4184
|
+
stats: () => ({ batches: group.children.length, batched: sources.filter((source) => !source.released).length, released }),
|
|
4185
|
+
dispose() {
|
|
4186
|
+
for (const source of sources) if (!source.released) source.mesh.layers.mask = source.mask;
|
|
4187
|
+
group.removeFromParent();
|
|
4188
|
+
for (const child of group.children) {
|
|
4189
|
+
;
|
|
4190
|
+
child.geometry.dispose();
|
|
4191
|
+
child.skeleton?.dispose();
|
|
2812
4192
|
}
|
|
2813
|
-
}
|
|
2814
|
-
dispose: () => waiting.clear()
|
|
4193
|
+
}
|
|
2815
4194
|
};
|
|
2816
4195
|
}
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
const
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
cursor += length / 2;
|
|
2826
|
-
rig.root.position.set(cursor, 0, 0);
|
|
2827
|
-
rig.home = rig.root.position.clone();
|
|
2828
|
-
rig.root.rotation.y = rig.species.body.kind === "snake" ? options.snakeYaw ?? 2.2 : options.yaw ?? 1.1;
|
|
2829
|
-
cursor += length / 2 + gap;
|
|
4196
|
+
function copyAttribute(name, attribute, target, offset, matrix, normalMatrix2) {
|
|
4197
|
+
const size = attribute.itemSize;
|
|
4198
|
+
const source = attribute.array;
|
|
4199
|
+
const flat = !attribute.isInterleavedBufferAttribute && source.length === attribute.count * size;
|
|
4200
|
+
if (name !== "position" && name !== "normal") {
|
|
4201
|
+
if (flat) target.set(source, offset * size);
|
|
4202
|
+
else for (let at = 0; at < attribute.count; at++) for (let k = 0; k < size; k++) target[(offset + at) * size + k] = attribute.getComponent(at, k);
|
|
4203
|
+
return;
|
|
2830
4204
|
}
|
|
2831
|
-
const
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
4205
|
+
const e = (name === "position" ? matrix : normalMatrix2).elements;
|
|
4206
|
+
const isNormal = name === "normal";
|
|
4207
|
+
for (let at = 0; at < attribute.count; at++) {
|
|
4208
|
+
const x = attribute.getX(at);
|
|
4209
|
+
const y = attribute.getY(at);
|
|
4210
|
+
const z = attribute.getZ(at);
|
|
4211
|
+
const out = (offset + at) * 3;
|
|
4212
|
+
if (isNormal) {
|
|
4213
|
+
const nx = e[0] * x + e[3] * y + e[6] * z;
|
|
4214
|
+
const ny = e[1] * x + e[4] * y + e[7] * z;
|
|
4215
|
+
const nz = e[2] * x + e[5] * y + e[8] * z;
|
|
4216
|
+
const length = Math.hypot(nx, ny, nz) || 1;
|
|
4217
|
+
target[out] = nx / length;
|
|
4218
|
+
target[out + 1] = ny / length;
|
|
4219
|
+
target[out + 2] = nz / length;
|
|
4220
|
+
} else {
|
|
4221
|
+
target[out] = e[0] * x + e[4] * y + e[8] * z + e[12];
|
|
4222
|
+
target[out + 1] = e[1] * x + e[5] * y + e[9] * z + e[13];
|
|
4223
|
+
target[out + 2] = e[2] * x + e[6] * y + e[10] * z + e[14];
|
|
4224
|
+
}
|
|
2835
4225
|
}
|
|
2836
|
-
}
|
|
4226
|
+
}
|
|
4227
|
+
function skinnedBatch(THREE, merged, material, meshes) {
|
|
4228
|
+
const vertices = merged.attributes.position.count;
|
|
4229
|
+
const skinIndex = new Uint16Array(vertices * 4);
|
|
4230
|
+
const skinWeight = new Float32Array(vertices * 4);
|
|
4231
|
+
let at = 0;
|
|
4232
|
+
meshes.forEach((mesh22, bone) => {
|
|
4233
|
+
for (let k = 0; k < mesh22.geometry.attributes.position.count; k++, at++) {
|
|
4234
|
+
skinIndex[at * 4] = bone;
|
|
4235
|
+
skinWeight[at * 4] = 1;
|
|
4236
|
+
}
|
|
4237
|
+
});
|
|
4238
|
+
merged.setAttribute("skinIndex", new THREE.BufferAttribute(skinIndex, 4));
|
|
4239
|
+
merged.setAttribute("skinWeight", new THREE.BufferAttribute(skinWeight, 4));
|
|
4240
|
+
const mesh2 = new THREE.SkinnedMesh(merged, material);
|
|
4241
|
+
const identities = meshes.map(() => new THREE.Matrix4());
|
|
4242
|
+
mesh2.bind(new THREE.Skeleton(meshes, identities), new THREE.Matrix4());
|
|
4243
|
+
mesh2.frustumCulled = false;
|
|
4244
|
+
return mesh2;
|
|
4245
|
+
}
|
|
4246
|
+
function mergeGroup(THREE, { meshes, inverse: rootInverse, group, follow }) {
|
|
4247
|
+
const identity = new THREE.Matrix4();
|
|
4248
|
+
const inverse = follow ? identity : rootInverse;
|
|
4249
|
+
const first = meshes[0];
|
|
4250
|
+
const names = ATTRIBUTES.filter((name) => first.geometry.attributes[name] !== void 0);
|
|
4251
|
+
const pieces = meshes.map((mesh22) => {
|
|
4252
|
+
const local = new THREE.Matrix4().multiplyMatrices(inverse, mesh22.matrixWorld);
|
|
4253
|
+
const vertices = mesh22.geometry.attributes.position.count;
|
|
4254
|
+
const indexCount = mesh22.geometry.index ? mesh22.geometry.index.count : vertices;
|
|
4255
|
+
return { mesh: mesh22, local, vertices, indexCount };
|
|
4256
|
+
});
|
|
4257
|
+
const totalVertices = pieces.reduce((sum, piece) => sum + piece.vertices, 0);
|
|
4258
|
+
const totalIndices = pieces.reduce((sum, piece) => sum + piece.indexCount, 0);
|
|
4259
|
+
const merged = new THREE.BufferGeometry();
|
|
4260
|
+
const normalMatrix2 = new THREE.Matrix3();
|
|
4261
|
+
for (const name of names) {
|
|
4262
|
+
const size = first.geometry.attributes[name].itemSize;
|
|
4263
|
+
const array = new Float32Array(totalVertices * size);
|
|
4264
|
+
let offset = 0;
|
|
4265
|
+
for (const piece of pieces) {
|
|
4266
|
+
const matrix = follow ? identity : piece.local;
|
|
4267
|
+
copyAttribute(name, piece.mesh.geometry.attributes[name], array, offset, matrix, normalMatrix2.getNormalMatrix(matrix));
|
|
4268
|
+
offset += piece.vertices;
|
|
4269
|
+
}
|
|
4270
|
+
merged.setAttribute(name, new THREE.BufferAttribute(array, size));
|
|
4271
|
+
}
|
|
4272
|
+
const indexArray2 = totalVertices > 65535 ? new Uint32Array(totalIndices) : new Uint16Array(totalIndices);
|
|
4273
|
+
const indexAttribute = new THREE.BufferAttribute(indexArray2, 1);
|
|
4274
|
+
merged.setIndex(indexAttribute);
|
|
4275
|
+
const mesh2 = follow ? skinnedBatch(THREE, merged, first.material, meshes) : new THREE.Mesh(merged, first.material);
|
|
4276
|
+
mesh2.name = `batch:${first.material.name || first.material.type}`;
|
|
4277
|
+
mesh2.castShadow = first.castShadow;
|
|
4278
|
+
mesh2.receiveShadow = first.receiveShadow;
|
|
4279
|
+
mesh2.raycast = () => void 0;
|
|
4280
|
+
merged.computeBoundingBox();
|
|
4281
|
+
merged.computeBoundingSphere();
|
|
4282
|
+
group.add(mesh2);
|
|
4283
|
+
const batch = { mesh: mesh2, live: pieces.length, index: indexAttribute };
|
|
4284
|
+
const sources = [];
|
|
4285
|
+
let vertexOffset = 0;
|
|
4286
|
+
let indexOffset = 0;
|
|
4287
|
+
for (const piece of pieces) {
|
|
4288
|
+
const index = piece.mesh.geometry.index;
|
|
4289
|
+
if (index) for (let at = 0; at < piece.indexCount; at++) indexArray2[indexOffset + at] = index.getX(at) + vertexOffset;
|
|
4290
|
+
else for (let at = 0; at < piece.indexCount; at++) indexArray2[indexOffset + at] = at + vertexOffset;
|
|
4291
|
+
sources.push({
|
|
4292
|
+
mesh: piece.mesh,
|
|
4293
|
+
geometry: piece.mesh.geometry,
|
|
4294
|
+
material: piece.mesh.material,
|
|
4295
|
+
version: piece.mesh.geometry.attributes.position.version,
|
|
4296
|
+
local: piece.local,
|
|
4297
|
+
world: piece.mesh.matrixWorld.clone(),
|
|
4298
|
+
mask: piece.mesh.layers.mask,
|
|
4299
|
+
batch,
|
|
4300
|
+
start: indexOffset,
|
|
4301
|
+
count: piece.indexCount,
|
|
4302
|
+
released: false
|
|
4303
|
+
});
|
|
4304
|
+
piece.mesh.layers.set(BATCHED_LAYER);
|
|
4305
|
+
vertexOffset += piece.vertices;
|
|
4306
|
+
indexOffset += piece.indexCount;
|
|
4307
|
+
}
|
|
4308
|
+
return sources;
|
|
4309
|
+
}
|
|
2837
4310
|
|
|
2838
4311
|
// src/test-area/scenarios.ts
|
|
2839
4312
|
var SKIN_COUNT = 40;
|
|
@@ -2960,6 +4433,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
2960
4433
|
var SKIN_COUNT2 = 40;
|
|
2961
4434
|
var SKIN_FIELD = { x0: -18, z0: -10, columns: 8, gap: 4.5 };
|
|
2962
4435
|
var DEFAULT_TIME_SCALE = 60;
|
|
4436
|
+
var BATCH_BUDGET_MS = 1;
|
|
2963
4437
|
function createAnimalsTestModule(options = {}) {
|
|
2964
4438
|
const locale = options.locale ?? "pt-BR";
|
|
2965
4439
|
const text = TEXT[locale] ?? TEXT["pt-BR"];
|
|
@@ -2988,14 +4462,24 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
2988
4462
|
outbreak = options.createOutbreak ? options.createOutbreak({ species, enabled: settings.outbreak, timeScale: settings.timeScale }) : null;
|
|
2989
4463
|
};
|
|
2990
4464
|
rebuildOutbreak();
|
|
4465
|
+
const batch = (entry) => {
|
|
4466
|
+
entry.batcher?.dispose();
|
|
4467
|
+
if (three) entry.batcher = createStaticBatcher(three, entry.rig.root, { followMeshes: true, budgetMs: BATCH_BUDGET_MS });
|
|
4468
|
+
};
|
|
4469
|
+
const look = (entry, state) => {
|
|
4470
|
+
animals?.setVisualState(entry.rig, state);
|
|
4471
|
+
batch(entry);
|
|
4472
|
+
};
|
|
2991
4473
|
const item = (animal) => ({
|
|
2992
4474
|
id: `${ANIMAL_ITEM_PREFIX}${animal.id}`,
|
|
2993
4475
|
name: animal.name[locale] ?? animal.id,
|
|
2994
4476
|
movable: false,
|
|
2995
4477
|
build: (THREE) => {
|
|
2996
4478
|
const rig = ensure(THREE).build(animal);
|
|
2997
|
-
|
|
4479
|
+
const entry = { id: rig.root.uuid, rig };
|
|
4480
|
+
placed.set(rig.root.uuid, entry);
|
|
2998
4481
|
if (settings.visual !== "alive") animals?.setVisualState(rig, settings.visual);
|
|
4482
|
+
batch(entry);
|
|
2999
4483
|
return rig.root;
|
|
3000
4484
|
}
|
|
3001
4485
|
});
|
|
@@ -3004,7 +4488,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
3004
4488
|
const state = outbreak.stateOf(entry.fate, clock);
|
|
3005
4489
|
if (state === "incubating") return;
|
|
3006
4490
|
entry.counted = state === "turned" ? "turned" : "dead";
|
|
3007
|
-
|
|
4491
|
+
look(entry, visualStateOf(entry.rig.species.outcome, true, state === "dead"));
|
|
3008
4492
|
};
|
|
3009
4493
|
const clearRings = () => {
|
|
3010
4494
|
discardObject3D(rings);
|
|
@@ -3055,7 +4539,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
3055
4539
|
const applyVisual = () => {
|
|
3056
4540
|
for (const entry of placed.values()) {
|
|
3057
4541
|
if (entry.fate) continue;
|
|
3058
|
-
|
|
4542
|
+
look(entry, settings.visual);
|
|
3059
4543
|
}
|
|
3060
4544
|
};
|
|
3061
4545
|
const onChange = (change) => {
|
|
@@ -3064,13 +4548,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
3064
4548
|
if (change.id === "bite_all") {
|
|
3065
4549
|
for (const entry of placed.values()) {
|
|
3066
4550
|
entry.fate = outbreak?.bite(entry.rig.species.id, random, clock);
|
|
3067
|
-
if (entry.fate)
|
|
4551
|
+
if (entry.fate) look(entry, visualStateOf(entry.rig.species.outcome, true));
|
|
3068
4552
|
}
|
|
3069
4553
|
} else if (change.id === "recover") {
|
|
3070
4554
|
for (const entry of placed.values()) {
|
|
3071
4555
|
delete entry.fate;
|
|
3072
4556
|
delete entry.counted;
|
|
3073
|
-
|
|
4557
|
+
look(entry, settings.visual);
|
|
3074
4558
|
}
|
|
3075
4559
|
} else if (change.id === "call" && sound) {
|
|
3076
4560
|
for (const [id, entry] of placed) {
|
|
@@ -3110,12 +4594,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
3110
4594
|
sound?.update(dt);
|
|
3111
4595
|
for (const [id, entry] of placed) {
|
|
3112
4596
|
if (!entry.rig.root.parent) {
|
|
4597
|
+
entry.batcher?.dispose();
|
|
3113
4598
|
placed.delete(id);
|
|
3114
4599
|
continue;
|
|
3115
4600
|
}
|
|
3116
4601
|
statusOf(entry);
|
|
3117
4602
|
animals?.animate(entry.rig, { time, delta: dt * settings.speed, clip: settings.gait, split: host?.bench?.layer("split") ?? false });
|
|
3118
4603
|
animals?.updateSplit(entry.rig, dt);
|
|
4604
|
+
entry.batcher?.update();
|
|
3119
4605
|
}
|
|
3120
4606
|
for (const { rig, skin } of skins) {
|
|
3121
4607
|
animals?.animate(rig, { time, delta: dt * settings.speed, clip: settings.gait });
|
|
@@ -3219,55 +4705,6 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
3219
4705
|
}
|
|
3220
4706
|
};
|
|
3221
4707
|
}
|
|
3222
|
-
|
|
3223
|
-
// src/index.ts
|
|
3224
|
-
var countTriangles = (root) => {
|
|
3225
|
-
let triangles = 0;
|
|
3226
|
-
root.traverse((object2) => {
|
|
3227
|
-
const mesh2 = object2;
|
|
3228
|
-
if (!mesh2.isMesh) return;
|
|
3229
|
-
const geometry = mesh2.geometry;
|
|
3230
|
-
triangles += geometry.index ? geometry.index.count / 3 : geometry.attributes.position.count / 3;
|
|
3231
|
-
});
|
|
3232
|
-
return Math.round(triangles);
|
|
3233
|
-
};
|
|
3234
|
-
var createAnimalsThree = (host, options = {}) => {
|
|
3235
|
-
const THREE = shapeGeometries(host);
|
|
3236
|
-
const random = options.random ?? createStream(options.seed ?? 7);
|
|
3237
|
-
const documentOf = () => {
|
|
3238
|
-
const found = options.document ?? globalThis.document;
|
|
3239
|
-
if (!found) throw new Error("game-animals-three: a species with a coat texture needs `options.document` (no global document found)");
|
|
3240
|
-
return found;
|
|
3241
|
-
};
|
|
3242
|
-
const jointMaterial = new THREE.MeshStandardMaterial({ color: 14722376, emissive: 14722376, emissiveIntensity: 0.8, roughness: 0.4 });
|
|
3243
|
-
const gaits = GAIT_PHASES;
|
|
3244
|
-
return {
|
|
3245
|
-
jointMaterial,
|
|
3246
|
-
build(species, buildOptions = {}) {
|
|
3247
|
-
const rig = createRig(THREE, species, { phase: buildOptions.phase ?? random() * 6 });
|
|
3248
|
-
if (species.body.kind === "snake") buildSnake(THREE, rig);
|
|
3249
|
-
else if (species.body.kind === "bird") buildBird(THREE, rig, { extra: BIRD_EXTRAS[species.id] });
|
|
3250
|
-
else buildQuadruped(THREE, rig, { document: species.body.texture ? documentOf() : void 0, extra: QUADRUPED_EXTRAS[species.id] });
|
|
3251
|
-
rig.triangles = countTriangles(rig.root);
|
|
3252
|
-
markKitOrigin(rig.root, { owner: "game-animals-three", kind: "animal", id: species.id });
|
|
3253
|
-
rig.root.traverse((object2) => {
|
|
3254
|
-
if (object2.isMesh) object2.userData.speciesId = species.id;
|
|
3255
|
-
});
|
|
3256
|
-
return rig;
|
|
3257
|
-
},
|
|
3258
|
-
animate(rig, params) {
|
|
3259
|
-
const kind = rig.species.body.kind;
|
|
3260
|
-
if (kind === "snake") animateSnake(THREE, rig, params);
|
|
3261
|
-
else if (kind === "bird") animateBird(rig, params);
|
|
3262
|
-
else animateQuadruped(rig, params, gaits);
|
|
3263
|
-
},
|
|
3264
|
-
setVisualState: (rig, state) => applyVisualState(THREE, rig, state),
|
|
3265
|
-
setJointView: (rig, on) => setJointView(rig, on, jointMaterial),
|
|
3266
|
-
setSplit,
|
|
3267
|
-
updateSplit,
|
|
3268
|
-
createSkin: (rig) => createNodeSkin(THREE, rig.root, { nodes: collectReferencedNodes(rig, ["species"]) })
|
|
3269
|
-
};
|
|
3270
|
-
};
|
|
3271
4708
|
return __toCommonJS(index_exports);
|
|
3272
4709
|
})();
|
|
3273
4710
|
//# sourceMappingURL=index.global.js.map
|