@adatechnology/game-weapons-three 0.15.0 → 0.16.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.
@@ -1413,6 +1413,10 @@ function computeCasingSound(input) {
1413
1413
  const surfaceName = surface === "hard" ? "concreto" : surface === "soft" ? "terra" : surface === "wood" ? "madeira" : "metal";
1414
1414
  return { surface, kind, sample: `casing_drop_${surfaceName}_${kind}`, voices };
1415
1415
  }
1416
+ function magazineDropId(material) {
1417
+ const surface = casingSurfaceOf(material);
1418
+ return `mag_drop_${surface === "hard" ? "concreto" : surface === "soft" ? "terra" : surface === "wood" ? "madeira" : "metal"}`;
1419
+ }
1416
1420
 
1417
1421
  // src/audio/flyby.ts
1418
1422
  function computeFlyby(input) {
@@ -2217,7 +2221,7 @@ var CUES_IN_SAMPLE = { mag_release: "mag_out", mag_insert: "mag_seat" };
2217
2221
  var isGunshot = (id) => GUNSHOT_SAMPLE_IDS.includes(id);
2218
2222
  function weaponSampleDefaults(sound3, overrides = {}) {
2219
2223
  if (sound3.category !== "armas") return void 0;
2220
- const base = sound3.id.startsWith("suppressed_") ? SUPPRESSED_SAMPLE : isGunshot(sound3.id) ? GUNSHOT_SAMPLE : sound3.id.startsWith("casing_drop_") ? CASING_SAMPLE : RELOAD_SAMPLE;
2224
+ const base = sound3.id.startsWith("suppressed_") ? SUPPRESSED_SAMPLE : isGunshot(sound3.id) ? GUNSHOT_SAMPLE : sound3.id.startsWith("casing_drop_") || sound3.id.startsWith("mag_drop_") ? CASING_SAMPLE : RELOAD_SAMPLE;
2221
2225
  return { ...base, ...overrides[sound3.id] };
2222
2226
  }
2223
2227
  function weaponSampleBank(options) {
@@ -2268,6 +2272,8 @@ function createWeaponAudio(volume = 0.6, options = {}) {
2268
2272
  void loadSamples();
2269
2273
  return false;
2270
2274
  };
2275
+ const fittedReady = (id) => sampleIds.has(id) && engine.registry.sound(id) === void 0 && engine.registry.set(id) !== void 0;
2276
+ const hostReady = (id) => sampleReady(id) || engine.registry.sound(id) === void 0 && engine.registry.set(id) !== void 0;
2271
2277
  const burst = (config) => {
2272
2278
  const id = config.filter === "highpass" ? BURST_IDS.highpass : BURST_IDS.lowpass;
2273
2279
  const params = { frequency: config.frequency, q: config.q ?? 0.8, gain: Math.max(config.gain, 2e-4), seconds: config.seconds };
@@ -2322,6 +2328,11 @@ function createWeaponAudio(volume = 0.6, options = {}) {
2322
2328
  options.onCasing?.(sound3, "sample");
2323
2329
  return;
2324
2330
  }
2331
+ if (recorded && fittedReady(recorded)) {
2332
+ if ((input.bounce ?? 0) === 0) channel.play(recorded, { volume: Math.min(1, Math.max(0.2, (input.speed ?? 1.5) / 2.5)) });
2333
+ options.onCasing?.(sound3, "fitted");
2334
+ return;
2335
+ }
2325
2336
  for (const voice of sound3.voices) playCasingVoice(voice);
2326
2337
  options.onCasing?.(sound3, "synth");
2327
2338
  };
@@ -2346,7 +2357,9 @@ function createWeaponAudio(volume = 0.6, options = {}) {
2346
2357
  const pitch = 1 + (channel.random() * 2 - 1) * pitchSpread;
2347
2358
  const shot = computeGunshot({ ...base, take, pitch }, options.gunshot);
2348
2359
  const recorded = shot.samples.close;
2349
- if (shot.audible && sampleReady(recorded)) {
2360
+ const sample = shot.audible && sampleReady(recorded);
2361
+ const fitted = shot.audible && !sample && fittedReady(recorded);
2362
+ if (sample || fitted) {
2350
2363
  const occlusion = Math.min(1, Math.max(0, extras.occlusion ?? 0));
2351
2364
  const handle = channel.play(recorded, {
2352
2365
  volume: (extras.volume ?? 1) * (1 - 0.5 * occlusion),
@@ -2359,7 +2372,7 @@ function createWeaponAudio(volume = 0.6, options = {}) {
2359
2372
  for (const voice of shot.voices) if (voice.group === "tail") playGunshotVoice(voice, extras);
2360
2373
  }
2361
2374
  const layers = handle?.kind === "sample" ? handle.plan.layers.map((layer) => ({ role: layer.role, take: layer.take, rate: layer.rate })) : [];
2362
- options.onGunshot?.(shot, { ...base, take, pitch }, { kind: "sample", id: recorded, layers });
2375
+ options.onGunshot?.(shot, { ...base, take, pitch }, fitted ? { kind: "fitted", id: recorded } : { kind: "sample", id: recorded, layers });
2363
2376
  return;
2364
2377
  }
2365
2378
  for (const voice of shot.voices) playGunshotVoice(voice, extras);
@@ -2380,10 +2393,11 @@ function createWeaponAudio(volume = 0.6, options = {}) {
2380
2393
  mechanical,
2381
2394
  cue(id, profile, lead = 0) {
2382
2395
  const carriedBy = CUES_IN_SAMPLE[id];
2383
- if (carriedBy && sampleReady(carriedBy)) return "carried";
2384
- if (sampleReady(id)) {
2396
+ if (carriedBy && (sampleReady(carriedBy) || fittedReady(carriedBy))) return "carried";
2397
+ const recorded = sampleReady(id);
2398
+ if (recorded || fittedReady(id)) {
2385
2399
  channel.play(id, { intensity: WEIGHT_INTENSITY[(profile ?? DEFAULT_SOUND_PROFILE).weight] });
2386
- return "sample";
2400
+ return recorded ? "sample" : "fitted";
2387
2401
  }
2388
2402
  for (const entry of reloadCueSteps(id, profile, cueTable)) step(lead > 0 ? { ...entry, at: entry.at + lead } : entry);
2389
2403
  return "synth";
@@ -2410,7 +2424,12 @@ function createWeaponAudio(volume = 0.6, options = {}) {
2410
2424
  casing,
2411
2425
  flyby(input) {
2412
2426
  const sound3 = computeFlyby({ ...input, pitch: input.pitch ?? 1 + (channel.random() * 2 - 1) * 0.05 });
2413
- for (const voice of sound3?.voices ?? []) playCasingVoice(voice, input.position);
2427
+ if (!sound3) return;
2428
+ if (hostReady(sound3.sample)) {
2429
+ channel.play(sound3.sample, { volume: Math.min(1, 1 / (1 + input.miss / 1.5)), ...input.position ? { position: [input.position[0], input.position[1], input.position[2]] } : {} });
2430
+ return;
2431
+ }
2432
+ for (const voice of sound3.voices) playCasingVoice(voice, input.position);
2414
2433
  },
2415
2434
  clink() {
2416
2435
  if (options.shotModel !== "game") {
@@ -2421,8 +2440,13 @@ function createWeaponAudio(volume = 0.6, options = {}) {
2421
2440
  const at = 0.25 + channel.random() * 0.2;
2422
2441
  sceneTone({ layer: "scene_tone", at, wave: "sine", f, f2: 3800, d: 0.06, vol: 0.06 });
2423
2442
  },
2424
- thud() {
2425
- burst({ seconds: 0.09, gain: 0.35, filter: "lowpass", frequency: 380 });
2443
+ thud(input = {}) {
2444
+ const id = magazineDropId(input.surface);
2445
+ if (hostReady(id)) {
2446
+ if ((input.bounce ?? 0) === 0) channel.play(id, { volume: Math.min(1, Math.max(0.2, (input.speed ?? 1.5) / 2.5)) });
2447
+ return;
2448
+ }
2449
+ burst({ seconds: 0.09, gain: 0.35 * (input.speed === void 0 ? 1 : Math.min(1, Math.max(0.3, input.speed / 2.5))) * ((input.bounce ?? 0) === 0 ? 1 : 0.5), filter: "lowpass", frequency: 380 });
2426
2450
  },
2427
2451
  setVolume(next) {
2428
2452
  const level = Math.max(0, Math.min(1, next));
@@ -8393,10 +8417,13 @@ function createViewmodel(options) {
8393
8417
  const distance = () => options.soundDistance?.() ?? 0;
8394
8418
  const particles = createParticles(THREE, scene, groundAt, options.particleLimit);
8395
8419
  particles.onBounce = (kind, hit) => {
8396
- if (kind === "magazine") audio?.thud();
8397
- if (kind !== "casing" || !audio) return;
8398
- const caseType = hit?.object.userData["caseType"];
8420
+ if (!audio || kind !== "casing" && kind !== "magazine") return;
8399
8421
  const surface = hit ? options.surfaceAt?.(hit.object.position.x, hit.object.position.z) : void 0;
8422
+ if (kind === "magazine") {
8423
+ audio.thud({ ...surface ? { surface } : {}, ...hit ? { speed: hit.speed, bounce: hit.bounce } : {} });
8424
+ return;
8425
+ }
8426
+ const caseType = hit?.object.userData["caseType"];
8400
8427
  audio.casing({ ...caseType ? { caseType } : {}, ...surface ? { surface } : {}, ...hit ? { speed: hit.speed, bounce: hit.bounce } : {} });
8401
8428
  };
8402
8429
  if (!options.effects) warnOnce2("game-weapons-three.own-effects-world", "game-weapons-three made an effects world of its own because the host lent none (options.effects); pass the host effects so the effects share one budget");
@@ -9858,6 +9885,7 @@ var TEXT = {
9858
9885
  reloadClip: "Reload of {weapon}: {kind}, clip {clip} ({seconds} s)",
9859
9886
  soundCue: "Sound: {cue} ({weapon})",
9860
9887
  cueRecorded: " \xB7 recorded",
9888
+ cueFitted: " \xB7 fitted copy of the recording",
9861
9889
  cueCarried: " \xB7 inside the next recording",
9862
9890
  gunshotSound: "Shot sound: {profile}, take {take}/4, pitch {pitch}, {space}, {distance} m{far}",
9863
9891
  gunshotRecorded: " \xB7 recorded take {takes}",
@@ -9893,6 +9921,7 @@ var TEXT = {
9893
9921
  reloadClip: "Recarga de {weapon}: {kind}, clipe {clip} ({seconds} s)",
9894
9922
  soundCue: "Som: {cue} ({weapon})",
9895
9923
  cueRecorded: " \xB7 grava\xE7\xE3o",
9924
+ cueFitted: " \xB7 c\xF3pia medida da grava\xE7\xE3o",
9896
9925
  cueCarried: " \xB7 dentro da grava\xE7\xE3o seguinte",
9897
9926
  gunshotSound: "Som do tiro: {profile}, tomada {take}/4, tom {pitch}, {space}, {distance} m{far}",
9898
9927
  gunshotRecorded: " \xB7 grava\xE7\xE3o, tomada {takes}",
@@ -10107,20 +10136,20 @@ function createWeaponsTestModule(options = {}) {
10107
10136
  engine: lentEngine,
10108
10137
  ...options.samples ? { samples: options.samples } : {},
10109
10138
  onGunshot: (shot, input, played) => {
10110
- const recorded = played.kind === "sample" && played.layers.length > 0 ? fill(text.gunshotRecorded, { takes: played.layers.map((layer) => `${layer.role} ${layer.take + 1}`).join(", ") }) : "";
10139
+ const recorded = played.kind === "sample" && played.layers.length > 0 ? fill(text.gunshotRecorded, { takes: played.layers.map((layer) => `${layer.role} ${layer.take + 1}`).join(", ") }) : played.kind === "fitted" ? text.cueFitted : "";
10111
10140
  lent.log(
10112
10141
  fill(text.gunshotSound, { profile: shot.profile, take: String(shot.take + 1), pitch: `${shot.pitch >= 1 ? "+" : ""}${((shot.pitch - 1) * 100).toFixed(1)} %`, space: text.spaces[input.space ?? "outdoor"], distance: String(Math.round(input.distance ?? 0)), far: shot.closeMix < 1 ? ` (${Math.round((1 - shot.closeMix) * 100)} % far)` : "" }) + recorded,
10113
10142
  { profile: shot.profile, take: shot.take, pitch: shot.pitch, space: input.space ?? "outdoor", distance: input.distance ?? 0, closeMix: shot.closeMix, delay: shot.delay, samples: shot.samples, played },
10114
10143
  "sound"
10115
10144
  );
10116
10145
  },
10117
- onCasing: (sound3, played) => lent.log(fill(text.casingSound, { case: sound3.kind, surface: text.surfaces[sound3.surface] }) + (played === "sample" ? text.cueRecorded : ""), { case: sound3.kind, surface: sound3.surface, sample: sound3.sample, played }, "sound")
10146
+ onCasing: (sound3, played) => lent.log(fill(text.casingSound, { case: sound3.kind, surface: text.surfaces[sound3.surface] }) + (played === "sample" ? text.cueRecorded : played === "fitted" ? text.cueFitted : ""), { case: sound3.kind, surface: sound3.surface, sample: sound3.sample, played }, "sound")
10118
10147
  });
10119
10148
  }
10120
10149
  let simulatedMs = 0;
10121
10150
  const offClock = lent.onFrame((dt) => simulatedMs += dt * 1e3);
10122
10151
  const created = createWeaponFx({
10123
- onSound: ({ weapon, cue: cue2, profile, played }) => lent.log(fill(text.soundCue, { weapon: arsenal.name(weapon), cue: text.soundCues[cue2] ?? cue2 }) + (played === "sample" ? text.cueRecorded : played === "carried" ? text.cueCarried : ""), { weapon, cue: cue2, weight: profile.weight, material: profile.material, ...played ? { played } : {} }, "sound"),
10152
+ onSound: ({ weapon, cue: cue2, profile, played }) => lent.log(fill(text.soundCue, { weapon: arsenal.name(weapon), cue: text.soundCues[cue2] ?? cue2 }) + (played === "sample" ? text.cueRecorded : played === "fitted" ? text.cueFitted : played === "carried" ? text.cueCarried : ""), { weapon, cue: cue2, weight: profile.weight, material: profile.material, ...played ? { played } : {} }, "sound"),
10124
10153
  THREE: lent.THREE,
10125
10154
  scene: lent.scene,
10126
10155
  camera: lent.camera,
@@ -10170,6 +10199,7 @@ function createWeaponsTestModule(options = {}) {
10170
10199
  const offEvents = lent.on((event) => {
10171
10200
  worldEffects.handle(event, lent.effects);
10172
10201
  if (event.type === "explosion") {
10202
+ if (lentEngine) return;
10173
10203
  const away = Math.hypot(event.point[0] - camera.position.x, event.point[1] - camera.position.y, event.point[2] - camera.position.z);
10174
10204
  ownAudio()?.play("explosion", Math.min(1, EXPLOSION_VOLUME_BASE + event.radius * EXPLOSION_VOLUME_PER_METRE), away);
10175
10205
  return;
@@ -11299,4 +11329,4 @@ export {
11299
11329
  DEFAULT_EXPLOSIVES_SCENE,
11300
11330
  createExplosivesTestModule
11301
11331
  };
11302
- //# sourceMappingURL=chunk-GBO6L7CQ.js.map
11332
+ //# sourceMappingURL=chunk-KWJQO6JS.js.map