@adatechnology/game-test-room 0.22.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +7 -0
- package/dist/index.global.js +350 -179
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +33 -8
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.global.js
CHANGED
|
@@ -6657,7 +6657,7 @@ var GameTestRoom = (() => {
|
|
|
6657
6657
|
};
|
|
6658
6658
|
var resolveStrings = (locale) => locales[locale ?? "en"] ?? locales.en;
|
|
6659
6659
|
|
|
6660
|
-
// ../game-audio/dist/chunk-
|
|
6660
|
+
// ../game-audio/dist/chunk-KBTUANNG.js
|
|
6661
6661
|
var DISTANCE_CURVES = {
|
|
6662
6662
|
/** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
|
|
6663
6663
|
game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
|
|
@@ -8526,10 +8526,12 @@ var GameTestRoom = (() => {
|
|
|
8526
8526
|
noise: () => noiseBuffer(store, audio, mix.noise.seconds),
|
|
8527
8527
|
time
|
|
8528
8528
|
});
|
|
8529
|
+
const recipeBank = registry.bankOf(plan.id);
|
|
8529
8530
|
announce({
|
|
8530
8531
|
id: plan.id,
|
|
8531
8532
|
kind: "recipe",
|
|
8532
8533
|
...fallbackOf ? { fallbackOf } : {},
|
|
8534
|
+
...recipeBank ? { bank: recipeBank } : {},
|
|
8533
8535
|
requestedAt,
|
|
8534
8536
|
startAt: time,
|
|
8535
8537
|
outputLatency: latencyOf(audio),
|
|
@@ -8631,9 +8633,11 @@ var GameTestRoom = (() => {
|
|
|
8631
8633
|
const time = requestedAt + (playOptions.delay ?? 0);
|
|
8632
8634
|
const chokeList = sample.choke ? choked(sample.id) : void 0;
|
|
8633
8635
|
const realized = realizeSample(plan, { context: audio, output: sampleOutput(plan.bus), buffer: (url2) => sampleStore.buffer(url2), time });
|
|
8636
|
+
const sampleBank = registry.bankOf(plan.id);
|
|
8634
8637
|
announce({
|
|
8635
8638
|
id: plan.id,
|
|
8636
8639
|
kind: "sample",
|
|
8640
|
+
...sampleBank ? { bank: sampleBank } : {},
|
|
8637
8641
|
requestedAt,
|
|
8638
8642
|
startAt: time,
|
|
8639
8643
|
outputLatency: latencyOf(audio),
|
|
@@ -8954,7 +8958,11 @@ var GameTestRoom = (() => {
|
|
|
8954
8958
|
["casing_drop_terra_pistol", 1],
|
|
8955
8959
|
["casing_drop_terra_rifle", 1],
|
|
8956
8960
|
["casing_drop_terra_shell", 1],
|
|
8957
|
-
["rocket_fire", 2]
|
|
8961
|
+
["rocket_fire", 2],
|
|
8962
|
+
["smg_45_auto", 2, "sfx_pistol"],
|
|
8963
|
+
["weapon_draw", 2],
|
|
8964
|
+
["suppressor_attach", 3],
|
|
8965
|
+
["suppressor_detach", 3]
|
|
8958
8966
|
]),
|
|
8959
8967
|
...entries("explosoes-fogo", [
|
|
8960
8968
|
["explosion_grenade", 1, "boom"],
|
|
@@ -8968,7 +8976,11 @@ var GameTestRoom = (() => {
|
|
|
8968
8976
|
["fire_loop_large", 1],
|
|
8969
8977
|
["fire_extinguish", 2, "hiss"],
|
|
8970
8978
|
["gas_leak_hiss", 2],
|
|
8971
|
-
["structure_collapse", 2, "crumble"]
|
|
8979
|
+
["structure_collapse", 2, "crumble"],
|
|
8980
|
+
["grenade_bounce", 1],
|
|
8981
|
+
["c4_plant", 2],
|
|
8982
|
+
["c4_beep", 2],
|
|
8983
|
+
["c4_disarm", 2]
|
|
8972
8984
|
]),
|
|
8973
8985
|
...entries("personagem", [
|
|
8974
8986
|
["footstep_concrete_walk", 1, "sfx_step"],
|
|
@@ -8984,7 +8996,19 @@ var GameTestRoom = (() => {
|
|
|
8984
8996
|
["blunt_hit", 1],
|
|
8985
8997
|
["bite", 1, "sfx_flesh"],
|
|
8986
8998
|
["body_fall", 1],
|
|
8987
|
-
["player_hurt", 2]
|
|
8999
|
+
["player_hurt", 2],
|
|
9000
|
+
["footstep_tile_walk", 1, "sfx_step"],
|
|
9001
|
+
["footstep_water_walk", 1, "sfx_step"],
|
|
9002
|
+
["footstep_grate_walk", 2, "sfx_step"],
|
|
9003
|
+
["footstep_duct_walk", 3, "sfx_step"],
|
|
9004
|
+
["ladder_climb", 2],
|
|
9005
|
+
["swim", 2],
|
|
9006
|
+
["zombie_groan", 1],
|
|
9007
|
+
["zombie_alert", 1],
|
|
9008
|
+
["zombie_attack", 1],
|
|
9009
|
+
["zombie_pain", 1],
|
|
9010
|
+
["zombie_claw_hit", 1, "sfx_flesh"],
|
|
9011
|
+
["zombie_claw_miss", 2]
|
|
8988
9012
|
]),
|
|
8989
9013
|
...entries("veiculos", [
|
|
8990
9014
|
["engine_loop_car", 1],
|
|
@@ -9012,7 +9036,8 @@ var GameTestRoom = (() => {
|
|
|
9012
9036
|
["wind_loop", 2],
|
|
9013
9037
|
["thunder_near", 2],
|
|
9014
9038
|
["thunder_far", 2],
|
|
9015
|
-
["water_splash", 2]
|
|
9039
|
+
["water_splash", 2],
|
|
9040
|
+
["helicopter_loop", 3]
|
|
9016
9041
|
])
|
|
9017
9042
|
];
|
|
9018
9043
|
var SFX_MATERIALS = [
|
|
@@ -9094,6 +9119,175 @@ var GameTestRoom = (() => {
|
|
|
9094
9119
|
burst: 20,
|
|
9095
9120
|
burstSpacing: 0.06
|
|
9096
9121
|
};
|
|
9122
|
+
var SFX_TIERS = { light: 0, medium: 0.34, heavy: 0.67 };
|
|
9123
|
+
function splitTier(id) {
|
|
9124
|
+
const match = /^(.*)_(light|medium|heavy)$/.exec(id);
|
|
9125
|
+
return match ? { base: match[1], tier: match[2] } : { base: id };
|
|
9126
|
+
}
|
|
9127
|
+
var refsOf = (entries2, baseUrl) => (entries2 ?? []).map((entry) => ({ url: `${baseUrl}${entry.file}` }));
|
|
9128
|
+
function sampleBankFromManifest(manifest, options) {
|
|
9129
|
+
const baseUrl = options.baseUrl ?? "";
|
|
9130
|
+
const samples = [];
|
|
9131
|
+
const tiersOf = /* @__PURE__ */ new Map();
|
|
9132
|
+
for (const sound of manifest.sounds) {
|
|
9133
|
+
const { base, tier } = splitTier(sound.id);
|
|
9134
|
+
if (tier) tiersOf.set(base, [...tiersOf.get(base) ?? [], sound]);
|
|
9135
|
+
}
|
|
9136
|
+
const bases = /* @__PURE__ */ new Map();
|
|
9137
|
+
for (const sound of manifest.sounds) {
|
|
9138
|
+
if (!splitTier(sound.id).tier) bases.set(sound.id, sound);
|
|
9139
|
+
}
|
|
9140
|
+
for (const [base, tiers] of tiersOf) {
|
|
9141
|
+
if (!bases.has(base)) bases.set(base, { id: base, category: tiers[0]?.category ?? "", layers: { close: tiers[0]?.layers.close ?? [] } });
|
|
9142
|
+
}
|
|
9143
|
+
for (const sound of bases.values()) {
|
|
9144
|
+
const numbers = options.sounds?.[sound.id] ?? options.defaults?.(sound);
|
|
9145
|
+
const close = refsOf(sound.layers.close, baseUrl);
|
|
9146
|
+
if (!numbers || close.length === 0) continue;
|
|
9147
|
+
const tiers = (tiersOf.get(sound.id) ?? []).map((tier) => {
|
|
9148
|
+
const name = splitTier(tier.id).tier;
|
|
9149
|
+
const tierFar = refsOf(tier.layers.far, baseUrl);
|
|
9150
|
+
return { name, from: SFX_TIERS[name] ?? 0, close: refsOf(tier.layers.close, baseUrl), ...tierFar.length > 0 ? { far: tierFar } : {} };
|
|
9151
|
+
}).sort((a, b) => a.from - b.from);
|
|
9152
|
+
const far = refsOf(sound.layers.far, baseUrl);
|
|
9153
|
+
const indoor = refsOf(sound.layers.tail_in, baseUrl);
|
|
9154
|
+
const outdoor = refsOf(sound.layers.tail_out, baseUrl);
|
|
9155
|
+
const files = [sound, ...tiersOf.get(sound.id) ?? []].flatMap((entry) => Object.values(entry.layers).flatMap((entries2) => entries2 ?? []));
|
|
9156
|
+
samples.push({
|
|
9157
|
+
id: sound.id,
|
|
9158
|
+
bus: numbers.bus,
|
|
9159
|
+
close,
|
|
9160
|
+
...far.length > 0 ? { far } : {},
|
|
9161
|
+
...tiers.length > 0 ? { tiers } : {},
|
|
9162
|
+
...numbers.crossover ? { crossover: numbers.crossover } : {},
|
|
9163
|
+
...indoor.length > 0 || outdoor.length > 0 ? { tail: { ...indoor.length > 0 ? { indoor } : {}, ...outdoor.length > 0 ? { outdoor } : {}, ...numbers.tailGain === void 0 ? {} : { gain: numbers.tailGain } } } : {},
|
|
9164
|
+
...numbers.pitch === void 0 ? {} : { pitch: numbers.pitch },
|
|
9165
|
+
...numbers.gain === void 0 ? {} : { gain: numbers.gain },
|
|
9166
|
+
...numbers.falloff ? { falloff: numbers.falloff } : {},
|
|
9167
|
+
...numbers.cutoffK === void 0 ? {} : { cutoffK: numbers.cutoffK },
|
|
9168
|
+
...numbers.group ? { group: numbers.group } : {},
|
|
9169
|
+
...numbers.priority === void 0 ? {} : { priority: numbers.priority },
|
|
9170
|
+
...numbers.fallback ? { fallback: numbers.fallback } : {},
|
|
9171
|
+
sources: files.map((file) => `${file.file}: ${file.source} ${file.author} ${file.license}`)
|
|
9172
|
+
});
|
|
9173
|
+
}
|
|
9174
|
+
return { id: options.id, samples };
|
|
9175
|
+
}
|
|
9176
|
+
var KIT_CATEGORY_BUS = {
|
|
9177
|
+
armas: "weapons",
|
|
9178
|
+
impactos: "world",
|
|
9179
|
+
"explosoes-fogo": "world",
|
|
9180
|
+
personagem: "world",
|
|
9181
|
+
veiculos: "world",
|
|
9182
|
+
"itens-portas": "world",
|
|
9183
|
+
ambiente: "ambience"
|
|
9184
|
+
};
|
|
9185
|
+
var VOICE_IDS = /^(player_(hurt|death|effort|breath)|scream|zombie_)/;
|
|
9186
|
+
var KIT_SAMPLE_ALIASES = {
|
|
9187
|
+
// a house door: the latch giving, the hinge, the leaf meeting the frame, a locked one shaken; a drawer on its runners
|
|
9188
|
+
latch: "metal_latch",
|
|
9189
|
+
creak_wood: "door_creak",
|
|
9190
|
+
shut_wood: "door_wood_shut",
|
|
9191
|
+
rattle: "door_locked_rattle",
|
|
9192
|
+
// a drawer stays on its recipe: the recorded runs (1 to 1.9 s) outlast a drawer's pull
|
|
9193
|
+
// an item taken in the hand (game-destruction-three grab_* keys)
|
|
9194
|
+
grab_hard: "item_pickup_generic",
|
|
9195
|
+
grab_soft: "item_pickup_leather"
|
|
9196
|
+
};
|
|
9197
|
+
function kitSampleDefaults(sound) {
|
|
9198
|
+
const bus = VOICE_IDS.test(sound.id) ? "voices" : KIT_CATEGORY_BUS[sound.category];
|
|
9199
|
+
if (!bus) return void 0;
|
|
9200
|
+
return { bus, pitch: sound.category === "ambiente" || /_loop/.test(sound.id) ? 0 : 0.04 };
|
|
9201
|
+
}
|
|
9202
|
+
function withAliases(manifest, aliases) {
|
|
9203
|
+
const byId = new Map(manifest.sounds.map((sound) => [sound.id, sound]));
|
|
9204
|
+
const extra = [];
|
|
9205
|
+
for (const [alias, target] of Object.entries(aliases)) {
|
|
9206
|
+
const sound = byId.get(target);
|
|
9207
|
+
if (sound && !byId.has(alias)) extra.push({ ...sound, id: alias });
|
|
9208
|
+
}
|
|
9209
|
+
return { ...manifest, sounds: [...manifest.sounds, ...extra] };
|
|
9210
|
+
}
|
|
9211
|
+
function kitSampleBank(manifest, options = {}) {
|
|
9212
|
+
return sampleBankFromManifest(withAliases(manifest, options.aliases ?? KIT_SAMPLE_ALIASES), {
|
|
9213
|
+
id: options.id ?? "kit_samples",
|
|
9214
|
+
baseUrl: options.baseUrl ?? "",
|
|
9215
|
+
defaults: kitSampleDefaults
|
|
9216
|
+
});
|
|
9217
|
+
}
|
|
9218
|
+
var isFileUrl = (url2) => {
|
|
9219
|
+
const page = globalThis.location?.href;
|
|
9220
|
+
try {
|
|
9221
|
+
return new URL(url2, page).protocol === "file:";
|
|
9222
|
+
} catch {
|
|
9223
|
+
return false;
|
|
9224
|
+
}
|
|
9225
|
+
};
|
|
9226
|
+
var fetchJson = async (url2) => {
|
|
9227
|
+
if (isFileUrl(url2)) throw new Error(`${url2}: file:// is not fetched`);
|
|
9228
|
+
const response = await fetch(url2);
|
|
9229
|
+
if (!response.ok) throw new Error(`${url2}: ${response.status}`);
|
|
9230
|
+
return await response.json();
|
|
9231
|
+
};
|
|
9232
|
+
async function loadKitSamples(engine, options = {}) {
|
|
9233
|
+
const baseUrl = options.baseUrl ?? "";
|
|
9234
|
+
let manifest;
|
|
9235
|
+
try {
|
|
9236
|
+
manifest = await (options.fetchManifest ?? fetchJson)(`${baseUrl}manifest.json`);
|
|
9237
|
+
} catch {
|
|
9238
|
+
return null;
|
|
9239
|
+
}
|
|
9240
|
+
const bank = kitSampleBank(manifest, options);
|
|
9241
|
+
engine.register(bank);
|
|
9242
|
+
if (options.preload && engine.loadSamples) void engine.loadSamples(options.preload).catch(() => void 0);
|
|
9243
|
+
return bank;
|
|
9244
|
+
}
|
|
9245
|
+
var USER_SAMPLES_BANK = "user_samples";
|
|
9246
|
+
var USER_SOUND_PREFIX = "user:";
|
|
9247
|
+
function userSampleBank(manifest, options = {}) {
|
|
9248
|
+
const playing = [];
|
|
9249
|
+
const behindKit = [];
|
|
9250
|
+
const sounds = [];
|
|
9251
|
+
for (const picked of manifest.sounds) {
|
|
9252
|
+
const sound = { ...picked, id: splitTier(picked.id).base };
|
|
9253
|
+
sounds.push({ ...sound, id: `${USER_SOUND_PREFIX}${sound.id}` });
|
|
9254
|
+
if (sound.role === "fallback" && options.kitHas?.(sound.id)) {
|
|
9255
|
+
behindKit.push(sound.id);
|
|
9256
|
+
continue;
|
|
9257
|
+
}
|
|
9258
|
+
sounds.push(sound);
|
|
9259
|
+
playing.push(sound.id);
|
|
9260
|
+
}
|
|
9261
|
+
const bank = sampleBankFromManifest(
|
|
9262
|
+
{ sounds },
|
|
9263
|
+
{
|
|
9264
|
+
id: USER_SAMPLES_BANK,
|
|
9265
|
+
baseUrl: options.baseUrl ?? "",
|
|
9266
|
+
defaults: (sound) => kitSampleDefaults({ id: sound.id.replace(USER_SOUND_PREFIX, ""), category: sound.category })
|
|
9267
|
+
}
|
|
9268
|
+
);
|
|
9269
|
+
return { bank, playing, behindKit };
|
|
9270
|
+
}
|
|
9271
|
+
var fetchManifestJson = async (url2) => {
|
|
9272
|
+
const page = globalThis.location?.href;
|
|
9273
|
+
if (new URL(url2, page ?? "http://localhost/").protocol === "file:") throw new Error(`${url2}: file:// is not fetched`);
|
|
9274
|
+
const response = await fetch(url2);
|
|
9275
|
+
if (!response.ok) throw new Error(`${url2}: ${response.status}`);
|
|
9276
|
+
return await response.json();
|
|
9277
|
+
};
|
|
9278
|
+
async function loadUserSamples(engine, options = {}) {
|
|
9279
|
+
const baseUrl = options.baseUrl ?? "./sfx-local/";
|
|
9280
|
+
let manifest;
|
|
9281
|
+
try {
|
|
9282
|
+
manifest = await (options.fetchManifest ?? fetchManifestJson)(`${baseUrl}manifest.json`);
|
|
9283
|
+
} catch {
|
|
9284
|
+
return null;
|
|
9285
|
+
}
|
|
9286
|
+
const kitHas = options.kitHas ?? ((id) => Boolean(engine.registry?.sample(id)));
|
|
9287
|
+
const result2 = userSampleBank(manifest, { baseUrl, kitHas });
|
|
9288
|
+
engine.register(result2.bank);
|
|
9289
|
+
return result2;
|
|
9290
|
+
}
|
|
9097
9291
|
var PT = {
|
|
9098
9292
|
group: "Som",
|
|
9099
9293
|
name: "Painel de som (arquivos e C1\u2013C10)",
|
|
@@ -9101,6 +9295,7 @@ var GameTestRoom = (() => {
|
|
|
9101
9295
|
category: "1 \xB7 Categoria",
|
|
9102
9296
|
sound: "1 \xB7 Som",
|
|
9103
9297
|
play: "1 \xB7 \u25B6 Tocar",
|
|
9298
|
+
play_user: "1 \xB7 \u25B6 Tocar o seu",
|
|
9104
9299
|
material: "2 \xB7 Material",
|
|
9105
9300
|
blow: "2 \xB7 Golpe",
|
|
9106
9301
|
strike: "2 \xB7 \u25B6 Tocar golpe",
|
|
@@ -9122,6 +9317,7 @@ var GameTestRoom = (() => {
|
|
|
9122
9317
|
approve: "5 \xB7 Aprovo (C10)"
|
|
9123
9318
|
},
|
|
9124
9319
|
hints: {
|
|
9320
|
+
play_user: "Toca a sua grava\xE7\xE3o deste som (dos seus pacotes, fora do git), mesmo quando o SDK tem uma melhor e toca na frente.",
|
|
9125
9321
|
sound: "A = arquivo, S = sintetizado, F = faltando. O que tem arquivo toca o arquivo; o resto toca o som atual.",
|
|
9126
9322
|
strike: "Toca impact_<material>_<golpe>: o arquivo se existir, sen\xE3o o som atual daquele material.",
|
|
9127
9323
|
wall: "P\xF5e a parede de casa entre voc\xEA e a fonte: o som fica abafado (C4).",
|
|
@@ -9166,9 +9362,10 @@ var GameTestRoom = (() => {
|
|
|
9166
9362
|
strengths: { light: "leve", medium: "m\xE9dio", heavy: "forte" },
|
|
9167
9363
|
states: { file: "A", synth: "S", missing: "F" },
|
|
9168
9364
|
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" },
|
|
9169
|
-
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" },
|
|
9365
|
+
metrics: { source: "1 \xB7 Fonte do que tocou", 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" },
|
|
9170
9366
|
run: { idle: "parada", measuring: "medindo\u2026", done: "pronta", failed: "falhou", recording: "gravando\u2026", recorded: "grava\xE7\xE3o baixada" },
|
|
9171
9367
|
words: { none: "\u2014", hidden: "? (revele)", prefers: "prefere", approved: "aprovado pelo dono" },
|
|
9368
|
+
sources: { sdk: "SDK", user: "seu som", synth: "sintetizado" },
|
|
9172
9369
|
probe: "Fonte do som",
|
|
9173
9370
|
wall: "Parede (oclus\xE3o)",
|
|
9174
9371
|
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" }
|
|
@@ -9181,6 +9378,7 @@ var GameTestRoom = (() => {
|
|
|
9181
9378
|
category: "1 \xB7 Category",
|
|
9182
9379
|
sound: "1 \xB7 Sound",
|
|
9183
9380
|
play: "1 \xB7 \u25B6 Play",
|
|
9381
|
+
play_user: "1 \xB7 \u25B6 Play yours",
|
|
9184
9382
|
material: "2 \xB7 Material",
|
|
9185
9383
|
blow: "2 \xB7 Blow",
|
|
9186
9384
|
strike: "2 \xB7 \u25B6 Play blow",
|
|
@@ -9202,6 +9400,7 @@ var GameTestRoom = (() => {
|
|
|
9202
9400
|
approve: "5 \xB7 Approve (C10)"
|
|
9203
9401
|
},
|
|
9204
9402
|
hints: {
|
|
9403
|
+
play_user: "Plays your own take of this sound (from your packs, kept out of git), even where the SDK has a better one that plays first.",
|
|
9205
9404
|
sound: "A = file, S = synthesized, F = missing. A file plays the file; the rest plays the current sound.",
|
|
9206
9405
|
strike: "Plays impact_<material>_<blow>: the file if there is one, else the current sound of that material.",
|
|
9207
9406
|
wall: "Puts the house wall between you and the source: the sound is muffled (C4).",
|
|
@@ -9236,138 +9435,16 @@ var GameTestRoom = (() => {
|
|
|
9236
9435
|
environments: { indoor: "indoor", outdoor: "outdoor" },
|
|
9237
9436
|
strengths: { light: "light", medium: "medium", heavy: "heavy" },
|
|
9238
9437
|
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" },
|
|
9239
|
-
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" },
|
|
9438
|
+
metrics: { source: "1 \xB7 Source of what played", 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" },
|
|
9240
9439
|
run: { idle: "idle", measuring: "measuring\u2026", done: "done", failed: "failed", recording: "recording\u2026", recorded: "recording downloaded" },
|
|
9241
9440
|
words: { none: "\u2014", hidden: "? (reveal)", prefers: "prefers", approved: "approved by the owner" },
|
|
9441
|
+
sources: { sdk: "SDK", user: "your sound", synth: "synthesized" },
|
|
9242
9442
|
probe: "Sound source",
|
|
9243
9443
|
wall: "Wall (occlusion)",
|
|
9244
9444
|
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" }
|
|
9245
9445
|
};
|
|
9246
9446
|
|
|
9247
9447
|
// ../game-audio/dist/index.js
|
|
9248
|
-
var SFX_TIERS = { light: 0, medium: 0.34, heavy: 0.67 };
|
|
9249
|
-
function splitTier(id) {
|
|
9250
|
-
const match = /^(.*)_(light|medium|heavy)$/.exec(id);
|
|
9251
|
-
return match ? { base: match[1], tier: match[2] } : { base: id };
|
|
9252
|
-
}
|
|
9253
|
-
var refsOf = (entries2, baseUrl) => (entries2 ?? []).map((entry) => ({ url: `${baseUrl}${entry.file}` }));
|
|
9254
|
-
function sampleBankFromManifest(manifest, options) {
|
|
9255
|
-
const baseUrl = options.baseUrl ?? "";
|
|
9256
|
-
const samples = [];
|
|
9257
|
-
const tiersOf = /* @__PURE__ */ new Map();
|
|
9258
|
-
for (const sound of manifest.sounds) {
|
|
9259
|
-
const { base, tier } = splitTier(sound.id);
|
|
9260
|
-
if (tier) tiersOf.set(base, [...tiersOf.get(base) ?? [], sound]);
|
|
9261
|
-
}
|
|
9262
|
-
const bases = /* @__PURE__ */ new Map();
|
|
9263
|
-
for (const sound of manifest.sounds) {
|
|
9264
|
-
if (!splitTier(sound.id).tier) bases.set(sound.id, sound);
|
|
9265
|
-
}
|
|
9266
|
-
for (const [base, tiers] of tiersOf) {
|
|
9267
|
-
if (!bases.has(base)) bases.set(base, { id: base, category: tiers[0]?.category ?? "", layers: { close: tiers[0]?.layers.close ?? [] } });
|
|
9268
|
-
}
|
|
9269
|
-
for (const sound of bases.values()) {
|
|
9270
|
-
const numbers = options.sounds?.[sound.id] ?? options.defaults?.(sound);
|
|
9271
|
-
const close = refsOf(sound.layers.close, baseUrl);
|
|
9272
|
-
if (!numbers || close.length === 0) continue;
|
|
9273
|
-
const tiers = (tiersOf.get(sound.id) ?? []).map((tier) => {
|
|
9274
|
-
const name = splitTier(tier.id).tier;
|
|
9275
|
-
const tierFar = refsOf(tier.layers.far, baseUrl);
|
|
9276
|
-
return { name, from: SFX_TIERS[name] ?? 0, close: refsOf(tier.layers.close, baseUrl), ...tierFar.length > 0 ? { far: tierFar } : {} };
|
|
9277
|
-
}).sort((a, b) => a.from - b.from);
|
|
9278
|
-
const far = refsOf(sound.layers.far, baseUrl);
|
|
9279
|
-
const indoor = refsOf(sound.layers.tail_in, baseUrl);
|
|
9280
|
-
const outdoor = refsOf(sound.layers.tail_out, baseUrl);
|
|
9281
|
-
const files = [sound, ...tiersOf.get(sound.id) ?? []].flatMap((entry) => Object.values(entry.layers).flatMap((entries2) => entries2 ?? []));
|
|
9282
|
-
samples.push({
|
|
9283
|
-
id: sound.id,
|
|
9284
|
-
bus: numbers.bus,
|
|
9285
|
-
close,
|
|
9286
|
-
...far.length > 0 ? { far } : {},
|
|
9287
|
-
...tiers.length > 0 ? { tiers } : {},
|
|
9288
|
-
...numbers.crossover ? { crossover: numbers.crossover } : {},
|
|
9289
|
-
...indoor.length > 0 || outdoor.length > 0 ? { tail: { ...indoor.length > 0 ? { indoor } : {}, ...outdoor.length > 0 ? { outdoor } : {}, ...numbers.tailGain === void 0 ? {} : { gain: numbers.tailGain } } } : {},
|
|
9290
|
-
...numbers.pitch === void 0 ? {} : { pitch: numbers.pitch },
|
|
9291
|
-
...numbers.gain === void 0 ? {} : { gain: numbers.gain },
|
|
9292
|
-
...numbers.falloff ? { falloff: numbers.falloff } : {},
|
|
9293
|
-
...numbers.cutoffK === void 0 ? {} : { cutoffK: numbers.cutoffK },
|
|
9294
|
-
...numbers.group ? { group: numbers.group } : {},
|
|
9295
|
-
...numbers.priority === void 0 ? {} : { priority: numbers.priority },
|
|
9296
|
-
...numbers.fallback ? { fallback: numbers.fallback } : {},
|
|
9297
|
-
sources: files.map((file) => `${file.file}: ${file.source} ${file.author} ${file.license}`)
|
|
9298
|
-
});
|
|
9299
|
-
}
|
|
9300
|
-
return { id: options.id, samples };
|
|
9301
|
-
}
|
|
9302
|
-
var KIT_CATEGORY_BUS = {
|
|
9303
|
-
armas: "weapons",
|
|
9304
|
-
impactos: "world",
|
|
9305
|
-
"explosoes-fogo": "world",
|
|
9306
|
-
personagem: "world",
|
|
9307
|
-
veiculos: "world",
|
|
9308
|
-
"itens-portas": "world",
|
|
9309
|
-
ambiente: "ambience"
|
|
9310
|
-
};
|
|
9311
|
-
var VOICE_IDS = /^(player_(hurt|death|effort|breath)|scream|zombie_)/;
|
|
9312
|
-
var KIT_SAMPLE_ALIASES = {
|
|
9313
|
-
// a house door: the latch giving, the hinge, the leaf meeting the frame, a locked one shaken; a drawer on its runners
|
|
9314
|
-
latch: "metal_latch",
|
|
9315
|
-
creak_wood: "door_creak",
|
|
9316
|
-
shut_wood: "door_wood_shut",
|
|
9317
|
-
rattle: "door_locked_rattle",
|
|
9318
|
-
// a drawer stays on its recipe: the recorded runs (1 to 1.9 s) outlast a drawer's pull
|
|
9319
|
-
// an item taken in the hand (game-destruction-three grab_* keys)
|
|
9320
|
-
grab_hard: "item_pickup_generic",
|
|
9321
|
-
grab_soft: "item_pickup_leather"
|
|
9322
|
-
};
|
|
9323
|
-
function kitSampleDefaults(sound) {
|
|
9324
|
-
const bus = VOICE_IDS.test(sound.id) ? "voices" : KIT_CATEGORY_BUS[sound.category];
|
|
9325
|
-
if (!bus) return void 0;
|
|
9326
|
-
return { bus, pitch: sound.category === "ambiente" || /_loop/.test(sound.id) ? 0 : 0.04 };
|
|
9327
|
-
}
|
|
9328
|
-
function withAliases(manifest, aliases) {
|
|
9329
|
-
const byId = new Map(manifest.sounds.map((sound) => [sound.id, sound]));
|
|
9330
|
-
const extra = [];
|
|
9331
|
-
for (const [alias, target] of Object.entries(aliases)) {
|
|
9332
|
-
const sound = byId.get(target);
|
|
9333
|
-
if (sound && !byId.has(alias)) extra.push({ ...sound, id: alias });
|
|
9334
|
-
}
|
|
9335
|
-
return { ...manifest, sounds: [...manifest.sounds, ...extra] };
|
|
9336
|
-
}
|
|
9337
|
-
function kitSampleBank(manifest, options = {}) {
|
|
9338
|
-
return sampleBankFromManifest(withAliases(manifest, options.aliases ?? KIT_SAMPLE_ALIASES), {
|
|
9339
|
-
id: options.id ?? "kit_samples",
|
|
9340
|
-
baseUrl: options.baseUrl ?? "",
|
|
9341
|
-
defaults: kitSampleDefaults
|
|
9342
|
-
});
|
|
9343
|
-
}
|
|
9344
|
-
var isFileUrl = (url2) => {
|
|
9345
|
-
const page = globalThis.location?.href;
|
|
9346
|
-
try {
|
|
9347
|
-
return new URL(url2, page).protocol === "file:";
|
|
9348
|
-
} catch {
|
|
9349
|
-
return false;
|
|
9350
|
-
}
|
|
9351
|
-
};
|
|
9352
|
-
var fetchJson = async (url2) => {
|
|
9353
|
-
if (isFileUrl(url2)) throw new Error(`${url2}: file:// is not fetched`);
|
|
9354
|
-
const response = await fetch(url2);
|
|
9355
|
-
if (!response.ok) throw new Error(`${url2}: ${response.status}`);
|
|
9356
|
-
return await response.json();
|
|
9357
|
-
};
|
|
9358
|
-
async function loadKitSamples(engine, options = {}) {
|
|
9359
|
-
const baseUrl = options.baseUrl ?? "";
|
|
9360
|
-
let manifest;
|
|
9361
|
-
try {
|
|
9362
|
-
manifest = await (options.fetchManifest ?? fetchJson)(`${baseUrl}manifest.json`);
|
|
9363
|
-
} catch {
|
|
9364
|
-
return null;
|
|
9365
|
-
}
|
|
9366
|
-
const bank = kitSampleBank(manifest, options);
|
|
9367
|
-
engine.register(bank);
|
|
9368
|
-
if (options.preload && engine.loadSamples) void engine.loadSamples(options.preload).catch(() => void 0);
|
|
9369
|
-
return bank;
|
|
9370
|
-
}
|
|
9371
9448
|
var ATTACK = 2e-3;
|
|
9372
9449
|
function lengthOf(d, attack) {
|
|
9373
9450
|
if (typeof d === "number") return attack + d;
|
|
@@ -22848,7 +22925,6 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
22848
22925
|
var rendererCount = 0;
|
|
22849
22926
|
var COLLAPSE_CLOUD_KG = 1e3;
|
|
22850
22927
|
var CHIP_DECAL_EDGE = 0.05;
|
|
22851
|
-
var OPAQUE_CRACK = 0.1;
|
|
22852
22928
|
var WOOD_RIM = 1.5;
|
|
22853
22929
|
var IMPACT_TAGS = ["metal", "glass", "wood"];
|
|
22854
22930
|
var GLOW_FROM_C = 430;
|
|
@@ -23543,7 +23619,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
23543
23619
|
this.startFire(ev);
|
|
23544
23620
|
this.activate(ev.object, ev.part);
|
|
23545
23621
|
this.sound("ignite", ev.point, 0.7);
|
|
23546
|
-
this.sound("burn_loop", ev.point, 0.5);
|
|
23622
|
+
this.sound("burn_loop", ev.point, 0.5, this.burning(ev.object, ev.part));
|
|
23547
23623
|
break;
|
|
23548
23624
|
case "primed":
|
|
23549
23625
|
if (ev.trigger !== "explosion") {
|
|
@@ -23551,7 +23627,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
23551
23627
|
this.primedBurning.add(`${ev.object}|${ev.part}`);
|
|
23552
23628
|
this.activate(ev.object, ev.part);
|
|
23553
23629
|
this.sound("primed", ev.point, 0.7, { seconds: ev.delay });
|
|
23554
|
-
this.sound("burn_loop", ev.point, 0.5);
|
|
23630
|
+
this.sound("burn_loop", ev.point, 0.5, { fuel: "gas" });
|
|
23555
23631
|
}
|
|
23556
23632
|
break;
|
|
23557
23633
|
case "spall":
|
|
@@ -23577,15 +23653,15 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
23577
23653
|
this.stopFire(`${ev.object}|${ev.part}`);
|
|
23578
23654
|
this.vfx.burst("steam", f.point, [0, 1, 0], 14, 1.2);
|
|
23579
23655
|
}
|
|
23580
|
-
if (f || primed) this.sound("burn_end", f?.point ?? this.rootPoint(ev.object), 0.5);
|
|
23656
|
+
if (f || primed) this.sound("burn_end", f?.point ?? this.rootPoint(ev.object), 0.5, primed ? { fuel: "gas" } : this.burning(ev.object, ev.part));
|
|
23581
23657
|
this.activate(ev.object, ev.part);
|
|
23582
23658
|
this.sound("extinguish", f?.point ?? this.rootPoint(ev.object), 0.6);
|
|
23583
23659
|
break;
|
|
23584
23660
|
}
|
|
23585
23661
|
case "burnout": {
|
|
23586
23662
|
this.stopFire(`${ev.object}|${ev.part}`);
|
|
23587
|
-
this.primedBurning.delete(`${ev.object}|${ev.part}`);
|
|
23588
|
-
this.sound("burn_end", ev.point, 0.5);
|
|
23663
|
+
const primed = this.primedBurning.delete(`${ev.object}|${ev.part}`);
|
|
23664
|
+
this.sound("burn_end", ev.point, 0.5, primed ? { fuel: "gas" } : this.burning(ev.object, ev.part));
|
|
23589
23665
|
this.vfx.burst("ash", ev.point, [0, 1, 0], 16, 1);
|
|
23590
23666
|
this.vfx.burst("smoke", ev.point, [0, 1, 0], 6, 0.8, { color: SMOKE_TONES.grey });
|
|
23591
23667
|
const pv = this.partVis(ev.object, ev.part);
|
|
@@ -23653,7 +23729,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
23653
23729
|
break;
|
|
23654
23730
|
}
|
|
23655
23731
|
case "explode":
|
|
23656
|
-
this.primedBurning.delete(`${ev.object}|${ev.part}`);
|
|
23732
|
+
if (this.primedBurning.delete(`${ev.object}|${ev.part}`)) this.sound("burn_end", ev.point, 0.5, { fuel: "gas" });
|
|
23657
23733
|
this.onExplode(ev);
|
|
23658
23734
|
break;
|
|
23659
23735
|
case "destroyed":
|
|
@@ -23668,6 +23744,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
23668
23744
|
if (detail) this.o.onSound?.(key2, point, volume, detail);
|
|
23669
23745
|
else this.o.onSound?.(key2, point, volume);
|
|
23670
23746
|
}
|
|
23747
|
+
/** What a burning part is made of, for the fire's sound. */
|
|
23748
|
+
burning(objectId, partId) {
|
|
23749
|
+
const material = this.partVis(objectId, partId)?.material || this.world.part(objectId, partId)?.material;
|
|
23750
|
+
return material ? { material } : void 0;
|
|
23751
|
+
}
|
|
23671
23752
|
partVis(objectId, partId) {
|
|
23672
23753
|
return this.bounds.get(objectId)?.parts.get(partId) ?? null;
|
|
23673
23754
|
}
|
|
@@ -23767,14 +23848,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
23767
23848
|
const pv = b?.parts.get(ev.part);
|
|
23768
23849
|
if (!b || !pv) return;
|
|
23769
23850
|
const def = this.world.materials.get(pv.material);
|
|
23770
|
-
|
|
23771
|
-
|
|
23772
|
-
|
|
23773
|
-
const
|
|
23774
|
-
|
|
23775
|
-
const color = glass2 ? 15267071 : new this.THREE.Color(own).multiplyScalar(0.45).getHex();
|
|
23776
|
-
const length3 = glass2 ? ev.crack.length : Math.min(ev.crack.length, OPAQUE_CRACK);
|
|
23777
|
-
this.visuals.addCrack(mv, wp, this.worldDir(b, ev.crack.normal), ev.crack.rays, length3, color, hashNumbers(ev.time, ev.worldPoint[0], ev.worldPoint[1], ev.worldPoint[2]));
|
|
23851
|
+
if (def?.visual?.transparent) {
|
|
23852
|
+
const wp = new this.THREE.Vector3(ev.worldPoint[0], ev.worldPoint[1], ev.worldPoint[2]);
|
|
23853
|
+
const mv = this.nearestMesh(pv, wp);
|
|
23854
|
+
const seed = hashNumbers(ev.time, ev.worldPoint[0], ev.worldPoint[1], ev.worldPoint[2]);
|
|
23855
|
+
if (mv) this.visuals.addCrack(mv, wp, this.worldDir(b, ev.crack.normal), ev.crack.rays, ev.crack.length, 15267071, seed);
|
|
23778
23856
|
}
|
|
23779
23857
|
this.impactSound(pv.material, ev.worldPoint, 0.5, ev.blow);
|
|
23780
23858
|
}
|
|
@@ -24536,6 +24614,47 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
24536
24614
|
volume: 0,
|
|
24537
24615
|
sources: ["sdk: the roar under the crackles of a fire"]
|
|
24538
24616
|
};
|
|
24617
|
+
var FIRE_FUEL_OF = {
|
|
24618
|
+
wood_soft: "wood",
|
|
24619
|
+
wood_hard: "wood",
|
|
24620
|
+
plywood: "wood",
|
|
24621
|
+
mdf: "wood",
|
|
24622
|
+
green_wood: "wood",
|
|
24623
|
+
foliage: "wood",
|
|
24624
|
+
cactus: "wood",
|
|
24625
|
+
paper: "fabric",
|
|
24626
|
+
fabric: "fabric",
|
|
24627
|
+
leather: "fabric",
|
|
24628
|
+
foam: "plastic",
|
|
24629
|
+
plastic: "plastic",
|
|
24630
|
+
rubber: "plastic",
|
|
24631
|
+
wax: "plastic"
|
|
24632
|
+
};
|
|
24633
|
+
var FIRE_LOOP_OF = {
|
|
24634
|
+
wood: "fire_loop",
|
|
24635
|
+
fabric: "fire_loop",
|
|
24636
|
+
plastic: "fire_loop_plastic",
|
|
24637
|
+
gas: "fire_loop_gas",
|
|
24638
|
+
liquid: "fire_loop_liquid"
|
|
24639
|
+
};
|
|
24640
|
+
var FIRE_CRACKLE_OF = { wood: 1, fabric: 0.5, plastic: 0.35, gas: 0, liquid: 0 };
|
|
24641
|
+
var roar = (id, bank, source) => ({
|
|
24642
|
+
id,
|
|
24643
|
+
bus: "world",
|
|
24644
|
+
order: "chain_loop",
|
|
24645
|
+
source: { kind: "noise", loop: true },
|
|
24646
|
+
filters: { mode: "serial", bank },
|
|
24647
|
+
volume: 0,
|
|
24648
|
+
sources: [source]
|
|
24649
|
+
});
|
|
24650
|
+
var FIRE_FUEL_LOOPS = [
|
|
24651
|
+
// a gas jet: a steady, broad roar, brighter than wood and without crackles
|
|
24652
|
+
roar("fire_loop_gas", [{ type: "highpass", frequency: { set: 220 }, q: 0.7 }, { type: "lowpass", frequency: { set: 2400 }, q: 0.6 }], "sdk: a gas jet burning (a vessel venting into the flame)"),
|
|
24653
|
+
// a fuel pool: a soft, low, rolling roar
|
|
24654
|
+
roar("fire_loop_liquid", [{ type: "highpass", frequency: { set: 90 }, q: 0.7 }, { type: "lowpass", frequency: { set: 650 }, q: 0.9 }], "sdk: a pool of fuel burning"),
|
|
24655
|
+
// plastic and rubber: a thin sizzle over a low burn
|
|
24656
|
+
roar("fire_loop_plastic", [{ type: "bandpass", frequency: { set: 1800 }, q: 0.6 }], "sdk: plastic and rubber melting in the fire")
|
|
24657
|
+
];
|
|
24539
24658
|
var BLAST_SOUND_OF = {
|
|
24540
24659
|
grenade: "explosion_grenade",
|
|
24541
24660
|
big: "explosion_big",
|
|
@@ -24680,7 +24799,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
24680
24799
|
impact2("plastic_crack", [sceneNoise({ type: "bandpass", f: 1800, q: 2, d: 0.06, vol: 0.75 }), sceneTone({ f: [450, 550], f2: 250, d: 0.05, vol: 0.22 })]),
|
|
24681
24800
|
impact2("mdf_crumble", [sceneNoise({ type: "lowpass", f: 700, d: 0.25, vol: 0.75, wet: 0.2 }), ...sceneMany(4, () => sceneNoise({ type: "lowpass", f: 500, d: 0.05, vol: 0.32, delay: [0.05, 0.3] }))])
|
|
24682
24801
|
];
|
|
24683
|
-
var DESTRUCTION_SOUND_BANK = { id: "destruction_three", sounds: [...SCENE_SOUNDS, ...DRAG_SOUNDS, ...LEAF_SOUNDS, ...IMPACT_SOUNDS, EXPLOSION_BOOM, ...BLAST_SOUNDS, ...FIRE_SOUNDS], loops: [BURN_LOOP, FIRE_LOOP] };
|
|
24802
|
+
var DESTRUCTION_SOUND_BANK = { id: "destruction_three", sounds: [...SCENE_SOUNDS, ...DRAG_SOUNDS, ...LEAF_SOUNDS, ...IMPACT_SOUNDS, EXPLOSION_BOOM, ...BLAST_SOUNDS, ...FIRE_SOUNDS], loops: [BURN_LOOP, FIRE_LOOP, ...FIRE_FUEL_LOOPS] };
|
|
24684
24803
|
var IMPACT_SOUND_KEYS = {
|
|
24685
24804
|
impact_metal_ballistic: { sound: "metal_bullet" },
|
|
24686
24805
|
impact_metal_blunt: { sound: "metal_blunt" },
|
|
@@ -24829,31 +24948,52 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
24829
24948
|
const rules = { ...DESTRUCTION_SOUND_KEYS.art_scene, ...options.style === "game" ? DESTRUCTION_SOUND_KEYS.game : {}, ...options.keys };
|
|
24830
24949
|
const blastByKind = options.style !== "game" && !(options.keys && "explode" in options.keys);
|
|
24831
24950
|
const channel = engine.channel({ seed: options.seed ?? 1 });
|
|
24832
|
-
|
|
24833
|
-
|
|
24951
|
+
const fuelOf = { ...FIRE_FUEL_OF, ...options.fuels };
|
|
24952
|
+
const loopOf = { ...FIRE_LOOP_OF, ...options.fireLoop ? { wood: fireLoop, fabric: fireLoop } : {}, ...options.fireLoops };
|
|
24953
|
+
const defaultFuel = options.defaultFuel ?? "wood";
|
|
24954
|
+
const loops = /* @__PURE__ */ new Map();
|
|
24834
24955
|
const fires = [];
|
|
24835
24956
|
let nextCrackle = 0;
|
|
24957
|
+
const fuelFor = (detail) => detail?.fuel ?? (detail?.material !== void 0 ? fuelOf[detail.material] : void 0) ?? defaultFuel;
|
|
24836
24958
|
const setFire = () => {
|
|
24837
24959
|
if (options.burnLoop === false) return;
|
|
24838
|
-
|
|
24839
|
-
|
|
24840
|
-
|
|
24841
|
-
|
|
24960
|
+
const count = /* @__PURE__ */ new Map();
|
|
24961
|
+
for (const f of fires) {
|
|
24962
|
+
const id = loopOf[f.fuel];
|
|
24963
|
+
count.set(id, (count.get(id) ?? 0) + 1);
|
|
24964
|
+
}
|
|
24965
|
+
for (const [id, handle] of loops) {
|
|
24966
|
+
if (count.has(id)) continue;
|
|
24967
|
+
handle.stop();
|
|
24968
|
+
loops.delete(id);
|
|
24969
|
+
}
|
|
24970
|
+
for (const [id, n] of count) {
|
|
24971
|
+
let handle = loops.get(id);
|
|
24972
|
+
if (!handle) {
|
|
24973
|
+
handle = engine.loop(id);
|
|
24974
|
+
loops.set(id, handle);
|
|
24975
|
+
}
|
|
24976
|
+
handle.set({ volume: Math.min(fire2.max, fire2.perFire * n) });
|
|
24842
24977
|
}
|
|
24843
|
-
loop ?? (loop = engine.loop(fireLoop));
|
|
24844
|
-
loop.set({ volume: Math.min(fire2.max, fire2.perFire * burning) });
|
|
24845
24978
|
};
|
|
24846
|
-
const forget = (point) => {
|
|
24979
|
+
const forget = (point, fuel) => {
|
|
24847
24980
|
let best = -1;
|
|
24848
24981
|
let bestD = Infinity;
|
|
24849
24982
|
fires.forEach((f, i) => {
|
|
24850
|
-
|
|
24983
|
+
if (fuel !== void 0 && f.fuel !== fuel) return;
|
|
24984
|
+
const d = (f.point[0] - point[0]) ** 2 + (f.point[1] - point[1]) ** 2 + (f.point[2] - point[2]) ** 2;
|
|
24851
24985
|
if (d < bestD) {
|
|
24852
24986
|
bestD = d;
|
|
24853
24987
|
best = i;
|
|
24854
24988
|
}
|
|
24855
24989
|
});
|
|
24856
|
-
if (best
|
|
24990
|
+
if (best < 0 && fuel !== void 0) forget(point, void 0);
|
|
24991
|
+
else if (best >= 0) fires.splice(best, 1);
|
|
24992
|
+
};
|
|
24993
|
+
const reset = () => {
|
|
24994
|
+
for (const handle of loops.values()) handle.stop();
|
|
24995
|
+
loops.clear();
|
|
24996
|
+
fires.length = 0;
|
|
24857
24997
|
};
|
|
24858
24998
|
const blastSound = (point, volume, detail) => {
|
|
24859
24999
|
const named = detail?.effect === void 0 ? void 0 : kinds[detail.effect];
|
|
@@ -24865,14 +25005,12 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
24865
25005
|
return {
|
|
24866
25006
|
onSound(key2, point, volume, detail) {
|
|
24867
25007
|
if (key2 === "burn_loop") {
|
|
24868
|
-
|
|
24869
|
-
fires.push(point);
|
|
25008
|
+
fires.push({ point, fuel: fuelFor(detail) });
|
|
24870
25009
|
setFire();
|
|
24871
25010
|
return;
|
|
24872
25011
|
}
|
|
24873
25012
|
if (key2 === "burn_end") {
|
|
24874
|
-
|
|
24875
|
-
forget(point);
|
|
25013
|
+
forget(point, detail?.fuel ?? (detail?.material !== void 0 ? fuelOf[detail.material] : void 0));
|
|
24876
25014
|
setFire();
|
|
24877
25015
|
return;
|
|
24878
25016
|
}
|
|
@@ -24902,12 +25040,15 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
24902
25040
|
},
|
|
24903
25041
|
update(dt) {
|
|
24904
25042
|
if (!crackles || fires.length === 0 || options.burnLoop === false) return;
|
|
25043
|
+
const weight = fires.reduce((sum2, f) => sum2 + FIRE_CRACKLE_OF[f.fuel], 0);
|
|
25044
|
+
if (weight <= 0) return;
|
|
24905
25045
|
nextCrackle -= dt;
|
|
24906
25046
|
for (let i = 0; i < 4 && nextCrackle <= 0; i++) {
|
|
24907
|
-
const rate = Math.min(crackles.max, crackles.base + crackles.perSqrtFire * Math.sqrt(
|
|
25047
|
+
const rate = Math.min(crackles.max, crackles.base * Math.min(1, weight) + crackles.perSqrtFire * Math.sqrt(weight));
|
|
24908
25048
|
nextCrackle += (0.4 + channel.random() * 1.2) / rate;
|
|
24909
|
-
|
|
24910
|
-
|
|
25049
|
+
let pick3 = channel.random() * weight;
|
|
25050
|
+
const at3 = fires.find((f) => (pick3 -= FIRE_CRACKLE_OF[f.fuel]) <= 0) ?? fires[fires.length - 1];
|
|
25051
|
+
engine.play(channel.random() < 0.18 ? "fire_pop" : "fire_crackle", { position: at3.point, volume: crackles.volume });
|
|
24911
25052
|
}
|
|
24912
25053
|
if (nextCrackle < 0) nextCrackle = 0;
|
|
24913
25054
|
},
|
|
@@ -24916,13 +25057,14 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
24916
25057
|
for (const k of detail?.keys ?? []) if (k in rules) return rules[k] ?? void 0;
|
|
24917
25058
|
return rules[key2] ?? void 0;
|
|
24918
25059
|
},
|
|
24919
|
-
burning: () =>
|
|
24920
|
-
|
|
24921
|
-
|
|
24922
|
-
|
|
24923
|
-
|
|
24924
|
-
|
|
24925
|
-
|
|
25060
|
+
burning: () => fires.length,
|
|
25061
|
+
burningBy: () => {
|
|
25062
|
+
const by = {};
|
|
25063
|
+
for (const f of fires) by[f.fuel] = (by[f.fuel] ?? 0) + 1;
|
|
25064
|
+
return by;
|
|
25065
|
+
},
|
|
25066
|
+
reset,
|
|
25067
|
+
dispose: reset
|
|
24926
25068
|
};
|
|
24927
25069
|
}
|
|
24928
25070
|
var blast2 = (gain) => ({ bus: "world", gain, falloff: BLAST_FALLOFF, cutoffK: 6e-3, priority: 3 });
|
|
@@ -24941,7 +25083,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
24941
25083
|
fire_extinguish: fire(0.7),
|
|
24942
25084
|
gas_leak: fire(0.5),
|
|
24943
25085
|
// the roar: recorded fires chained with a crossfade (the level comes from `createDestructionSound`, by how much burns)
|
|
24944
|
-
fire_loop: { bus: "world", gain: 4, loop: { crossfade: 1 } }
|
|
25086
|
+
fire_loop: { bus: "world", gain: 4, loop: { crossfade: 1 } },
|
|
25087
|
+
// each fuel has its own roar: a gas jet (burners and torches), a pool of fuel, plastic and rubber sizzling under the flames
|
|
25088
|
+
fire_loop_gas: { bus: "world", gain: 6, loop: { crossfade: 1 } },
|
|
25089
|
+
fire_loop_liquid: { bus: "world", gain: 3.5, loop: { crossfade: 1 } },
|
|
25090
|
+
fire_loop_plastic: { bus: "world", gain: 1, loop: { crossfade: 0.6 } }
|
|
24945
25091
|
};
|
|
24946
25092
|
|
|
24947
25093
|
// src/body-sounds.ts
|
|
@@ -47790,6 +47936,7 @@ void main(){
|
|
|
47790
47936
|
var LYING_EYE = 0.3;
|
|
47791
47937
|
var LYING_PITCH = 1.05;
|
|
47792
47938
|
var LYING_ROLL = 0.35;
|
|
47939
|
+
var LYING_PITCH_FACE_DOWN = -1.05;
|
|
47793
47940
|
function createPlayer(THREE, o) {
|
|
47794
47941
|
const cam = o.camera;
|
|
47795
47942
|
let yaw = 0;
|
|
@@ -47828,11 +47975,12 @@ void main(){
|
|
|
47828
47975
|
floorLevel += Math.max(-reach, Math.min(reach, gap));
|
|
47829
47976
|
};
|
|
47830
47977
|
let knocked = null;
|
|
47978
|
+
let knockedForward = false;
|
|
47831
47979
|
let rollSide = 1;
|
|
47832
47980
|
const apply = () => {
|
|
47833
47981
|
const lying = knocked?.lying ?? 0;
|
|
47834
47982
|
const fallen = lying * lying * (3 - 2 * lying);
|
|
47835
|
-
euler.set(pitch + (LYING_PITCH - pitch) * fallen, yaw, LYING_ROLL * rollSide * fallen, "YXZ");
|
|
47983
|
+
euler.set(pitch + ((knockedForward ? LYING_PITCH_FACE_DOWN : LYING_PITCH) - pitch) * fallen, yaw, LYING_ROLL * rollSide * fallen, "YXZ");
|
|
47836
47984
|
cam.quaternion.setFromEuler(euler);
|
|
47837
47985
|
const standing = eye - CROUCH_DROP * crouch - bend;
|
|
47838
47986
|
cam.position.set(px.x, floorLevel + y + standing + (LYING_EYE - standing) * fallen, px.z);
|
|
@@ -48110,6 +48258,7 @@ void main(){
|
|
|
48110
48258
|
if (next.down) {
|
|
48111
48259
|
const right = Math.cos(yaw) * next.velocity[0] - Math.sin(yaw) * next.velocity[2];
|
|
48112
48260
|
rollSide = right >= 0 ? -1 : 1;
|
|
48261
|
+
knockedForward = -Math.sin(yaw) * next.velocity[0] - Math.cos(yaw) * next.velocity[2] > 0;
|
|
48113
48262
|
crouchLatched = false;
|
|
48114
48263
|
}
|
|
48115
48264
|
if (knocked.airborne) vy2 = Math.max(vy2, knocked.velocity[1]);
|
|
@@ -48117,6 +48266,9 @@ void main(){
|
|
|
48117
48266
|
get knocked() {
|
|
48118
48267
|
return knocked;
|
|
48119
48268
|
},
|
|
48269
|
+
get knockedForward() {
|
|
48270
|
+
return knockedForward;
|
|
48271
|
+
},
|
|
48120
48272
|
update(dt) {
|
|
48121
48273
|
if (knocked) {
|
|
48122
48274
|
stepKnocked(dt);
|
|
@@ -53124,7 +53276,11 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
53124
53276
|
const audio = options.audio === false ? null : options.audio ?? createAudioEngine({ deferredStart: {} });
|
|
53125
53277
|
const destructionSound = audio ? createDestructionSound(audio) : null;
|
|
53126
53278
|
if (audio && options.samplesBaseUrl !== null) {
|
|
53127
|
-
void loadKitSamples(audio, { baseUrl: options.samplesBaseUrl ?? "./sfx/" }).then((bank) => {
|
|
53279
|
+
void loadKitSamples(audio, { baseUrl: options.samplesBaseUrl ?? "./sfx/" }).then(async (bank) => {
|
|
53280
|
+
if (options.userSamplesBaseUrl !== null) {
|
|
53281
|
+
const own = await loadUserSamples(audio, { baseUrl: options.userSamplesBaseUrl ?? "./sfx-local/" });
|
|
53282
|
+
if (own) log.add({ channel: "event", type: "user_sounds", text: `sons do dono: ${own.playing.length} tocando, ${own.behindKit.length} atr\xE1s do SDK`, data: { playing: own.playing, behindKit: own.behindKit } });
|
|
53283
|
+
}
|
|
53128
53284
|
if (!bank || typeof window === "undefined") return;
|
|
53129
53285
|
const preload = () => {
|
|
53130
53286
|
window.removeEventListener("keydown", preload, true);
|
|
@@ -53946,6 +54102,7 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
53946
54102
|
explosives.clear();
|
|
53947
54103
|
fireZones.length = 0;
|
|
53948
54104
|
burningStains.length = 0;
|
|
54105
|
+
destructionSound?.reset();
|
|
53949
54106
|
terrain.setLayout(defaultGround);
|
|
53950
54107
|
for (const id of [...entries2.keys()]) if (!entries2.get(id)?.arena) removeEntry(id);
|
|
53951
54108
|
clearLoose();
|
|
@@ -54113,6 +54270,7 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
54113
54270
|
avatarState.running = !player.crouching && (player.keys.has("ShiftLeft") || player.keys.has("ShiftRight"));
|
|
54114
54271
|
avatarState.crouch = crouchForced || player.crouching || push.isBent;
|
|
54115
54272
|
avatarState.down = downForced || Boolean(player.knocked?.down || (player.knocked?.lying ?? 0) > 0.5);
|
|
54273
|
+
avatarState.fallForward = downForced ? void 0 : player.knockedForward;
|
|
54116
54274
|
avatarState.armed = armedForced ?? tool.def.action.kind === "firearm";
|
|
54117
54275
|
avatarState.pitch = player.pitch;
|
|
54118
54276
|
avatarState.holding = heldPiece !== null;
|
|
@@ -54312,6 +54470,15 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
54312
54470
|
};
|
|
54313
54471
|
const fireZones = [];
|
|
54314
54472
|
const burningStains = [];
|
|
54473
|
+
const poolFire = (point, burning) => playSound(burning ? "burn_loop" : "burn_end", point, 0.5, { fuel: "liquid" });
|
|
54474
|
+
const dropZone = (i) => {
|
|
54475
|
+
const [zone] = fireZones.splice(i, 1);
|
|
54476
|
+
if (zone) poolFire(zone.point, false);
|
|
54477
|
+
};
|
|
54478
|
+
const dropStain = (i) => {
|
|
54479
|
+
const [stain] = burningStains.splice(i, 1);
|
|
54480
|
+
if (stain) poolFire(stain.center, false);
|
|
54481
|
+
};
|
|
54315
54482
|
const stainRadius = (s) => {
|
|
54316
54483
|
let sum2 = 0;
|
|
54317
54484
|
for (const r of s.front) sum2 += r;
|
|
@@ -54328,6 +54495,7 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
54328
54495
|
if (stainBurning(s)) continue;
|
|
54329
54496
|
const seconds = Math.max(3, Math.min(20, 4 + s.liters * 30 + stainRadius(s) * 6));
|
|
54330
54497
|
burningStains.push({ center: [s.center[0], s.center[1], s.center[2]], remaining: seconds, acc: 0 });
|
|
54498
|
+
poolFire([s.center[0], s.center[1], s.center[2]], true);
|
|
54331
54499
|
lit = true;
|
|
54332
54500
|
log.add({
|
|
54333
54501
|
channel: "event",
|
|
@@ -54358,7 +54526,7 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
54358
54526
|
const a = rnd2() * Math.PI * 2;
|
|
54359
54527
|
const r = Math.sqrt(rnd2()) * z.radius;
|
|
54360
54528
|
renderer.emit("fire", [z.point[0] + Math.cos(a) * r, z.point[1] + 0.05, z.point[2] + Math.sin(a) * r], [0, 1, 0], 2, 1.5);
|
|
54361
|
-
if (z.remaining <= 0)
|
|
54529
|
+
if (z.remaining <= 0) dropZone(i);
|
|
54362
54530
|
}
|
|
54363
54531
|
if (burningStains.length) {
|
|
54364
54532
|
const stains = fluids.stains();
|
|
@@ -54379,7 +54547,7 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
54379
54547
|
if (b.remaining <= 0 || !st) {
|
|
54380
54548
|
fluids.clearStains(b.center, r + 0.1);
|
|
54381
54549
|
log.add({ channel: "event", type: "stain_burned", text: t("ev.stain_burned"), data: { point: b.center } });
|
|
54382
|
-
|
|
54550
|
+
dropStain(i);
|
|
54383
54551
|
}
|
|
54384
54552
|
}
|
|
54385
54553
|
}
|
|
@@ -54716,8 +54884,8 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
54716
54884
|
hit.add(r.object);
|
|
54717
54885
|
world.extinguish(r.object, void 0, u.coolC * Math.max(u.duration, 0.05) * 6);
|
|
54718
54886
|
fluids.clearStains(r.point, 0.5);
|
|
54719
|
-
for (let i = burningStains.length - 1; i >= 0; i--) if (Math.hypot(burningStains[i].center[0] - r.point[0], burningStains[i].center[2] - r.point[2]) < 1.2)
|
|
54720
|
-
for (let i = fireZones.length - 1; i >= 0; i--) if (Math.hypot(fireZones[i].point[0] - r.point[0], fireZones[i].point[2] - r.point[2]) < 1.5)
|
|
54887
|
+
for (let i = burningStains.length - 1; i >= 0; i--) if (Math.hypot(burningStains[i].center[0] - r.point[0], burningStains[i].center[2] - r.point[2]) < 1.2) dropStain(i);
|
|
54888
|
+
for (let i = fireZones.length - 1; i >= 0; i--) if (Math.hypot(fireZones[i].point[0] - r.point[0], fireZones[i].point[2] - r.point[2]) < 1.5) dropZone(i);
|
|
54721
54889
|
}
|
|
54722
54890
|
});
|
|
54723
54891
|
log.coalesce(
|
|
@@ -54728,7 +54896,9 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
54728
54896
|
};
|
|
54729
54897
|
const startFire = (weapon, at3, fire3, impact3) => {
|
|
54730
54898
|
fluids.splash("fuel", [at3[0], Math.max(at3[1], groundAt(at3[0], at3[2])), at3[2]], 0.5);
|
|
54731
|
-
|
|
54899
|
+
const zone = { point: [at3[0], Math.max(0.02, groundAt(at3[0], at3[2])), at3[2]], radius: fire3.radius, temperature: fire3.temperature, remaining: fire3.seconds, acc: 0 };
|
|
54900
|
+
fireZones.push(zone);
|
|
54901
|
+
poolFire(zone.point, true);
|
|
54732
54902
|
renderer.emit("fire", at3, [0, 1, 0], 24, 3);
|
|
54733
54903
|
action("molotov_fire", t("act.molotov_fire", { weapon: toolName(weapon), seconds: num(fire3.seconds, 0), radius: num(fire3.radius, 1) }), { data: { weapon, impact: impact3 } });
|
|
54734
54904
|
};
|
|
@@ -55866,6 +56036,7 @@ ${SURFACE_GLSL}`).replace("#include <color_fragment>", "#include <color_fragment
|
|
|
55866
56036
|
loading,
|
|
55867
56037
|
addView: (view) => moduleViews.add(view),
|
|
55868
56038
|
setViewCamera: (view) => moduleViews.setMain(view ?? null),
|
|
56039
|
+
holdPlayer: (held) => player.setWalkHeld(held),
|
|
55869
56040
|
...options.blastShove ? { blastShove: options.blastShove } : {},
|
|
55870
56041
|
blastReach: (point, target, ignore) => world.blastReach(point, target, ignore ? { ignore } : {}),
|
|
55871
56042
|
tool: () => ({
|