@adatechnology/game-destruction-three 0.5.0 → 0.6.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.js CHANGED
@@ -295,9 +295,9 @@ var FragmentSystem = class {
295
295
  // src/ground.ts
296
296
  var MAX_RADIUS = 1.2;
297
297
  var GroundSpots = class {
298
- constructor(THREE, scene, groundAt, cap) {
298
+ constructor(THREE, scene2, groundAt, cap) {
299
299
  __publicField(this, "THREE", THREE);
300
- __publicField(this, "scene", scene);
300
+ __publicField(this, "scene", scene2);
301
301
  __publicField(this, "groundAt", groundAt);
302
302
  __publicField(this, "cap", cap);
303
303
  __publicField(this, "spots", []);
@@ -699,9 +699,9 @@ var PieceSystem = class {
699
699
 
700
700
  // src/rebar.ts
701
701
  var RebarCages = class {
702
- constructor(THREE, scene, radius = 4e-3) {
702
+ constructor(THREE, scene2, radius = 4e-3) {
703
703
  __publicField(this, "THREE", THREE);
704
- __publicField(this, "scene", scene);
704
+ __publicField(this, "scene", scene2);
705
705
  __publicField(this, "cages", /* @__PURE__ */ new Map());
706
706
  __publicField(this, "geometry");
707
707
  __publicField(this, "material");
@@ -1517,10 +1517,10 @@ var Visuals = class {
1517
1517
  const sy = lerp(1, 0.25, melt);
1518
1518
  const sxz = 1 + 0.18 * melt;
1519
1519
  for (let i = range[0] * 3, v = 0; i < range[1] * 3; i += 3, v++) {
1520
- const noise = (Math.imul(v + 1, 2654435761) >>> 0) % 1e3 / 1e3;
1520
+ const noise2 = (Math.imul(v + 1, 2654435761) >>> 0) % 1e3 / 1e3;
1521
1521
  arr[i] = cx + (work[i] - cx) * sxz;
1522
1522
  arr[i + 2] = cz + (work[i + 2] - cz) * sxz;
1523
- arr[i + 1] = Math.max(minY, minY + (work[i + 1] - minY) * sy - noise * melt * h * 0.04);
1523
+ arr[i + 1] = Math.max(minY, minY + (work[i + 1] - minY) * sy - noise2 * melt * h * 0.04);
1524
1524
  }
1525
1525
  }
1526
1526
  /** The colour attribute of the host's current geometry (created white when there is none) with vertex colours switched on in its material. */
@@ -1845,6 +1845,8 @@ var Renderer = class {
1845
1845
  __publicField(this, "cages");
1846
1846
  __publicField(this, "active", /* @__PURE__ */ new Map());
1847
1847
  __publicField(this, "fires", /* @__PURE__ */ new Map());
1848
+ /** Primed parts burning in the effects world until they go off: their burn loop ends when they are put out. */
1849
+ __publicField(this, "primedBurning", /* @__PURE__ */ new Set());
1848
1850
  __publicField(this, "leaks", []);
1849
1851
  __publicField(this, "homeTags", []);
1850
1852
  __publicField(this, "throttles", /* @__PURE__ */ new Map());
@@ -2186,8 +2188,10 @@ var Renderer = class {
2186
2188
  case "primed":
2187
2189
  if (ev.trigger !== "explosion") {
2188
2190
  this.vfx.fire({ point: ev.point, radius: PRIMED_FIRE_RADIUS, life: ev.delay });
2191
+ this.primedBurning.add(`${ev.object}|${ev.part}`);
2189
2192
  this.activate(ev.object, ev.part);
2190
2193
  this.sound("ignite", ev.point, 0.7);
2194
+ this.sound("burn_loop", ev.point, 0.5);
2191
2195
  }
2192
2196
  break;
2193
2197
  case "spall":
@@ -2205,16 +2209,20 @@ var Renderer = class {
2205
2209
  break;
2206
2210
  case "extinguish": {
2207
2211
  const f = this.fires.get(`${ev.object}|${ev.part}`);
2212
+ const primed = this.primedBurning.delete(`${ev.object}|${ev.part}`);
2208
2213
  if (f) {
2209
2214
  this.stopFire(`${ev.object}|${ev.part}`);
2210
2215
  this.vfx.burst("steam", f.point, [0, 1, 0], 14, 1.2);
2211
2216
  }
2217
+ if (f || primed) this.sound("burn_end", f?.point ?? this.rootPoint(ev.object), 0.5);
2212
2218
  this.activate(ev.object, ev.part);
2213
2219
  this.sound("extinguish", f?.point ?? this.rootPoint(ev.object), 0.6);
2214
2220
  break;
2215
2221
  }
2216
2222
  case "burnout": {
2217
2223
  this.stopFire(`${ev.object}|${ev.part}`);
2224
+ this.primedBurning.delete(`${ev.object}|${ev.part}`);
2225
+ this.sound("burn_end", ev.point, 0.5);
2218
2226
  this.vfx.burst("ash", ev.point, [0, 1, 0], 16, 1);
2219
2227
  this.vfx.burst("smoke", ev.point, [0, 1, 0], 6, 0.8, { color: SMOKE_TONES.grey });
2220
2228
  const pv = this.partVis(ev.object, ev.part);
@@ -2256,6 +2264,7 @@ var Renderer = class {
2256
2264
  break;
2257
2265
  }
2258
2266
  case "explode":
2267
+ this.primedBurning.delete(`${ev.object}|${ev.part}`);
2259
2268
  this.onExplode(ev);
2260
2269
  break;
2261
2270
  case "destroyed":
@@ -2746,6 +2755,7 @@ var Renderer = class {
2746
2755
  this.fragments.clear();
2747
2756
  this.ground.clear();
2748
2757
  this.cages.clear();
2758
+ this.primedBurning.clear();
2749
2759
  this.vfx.sprites().clear();
2750
2760
  this.ownVfx?.world.clear();
2751
2761
  }
@@ -2774,8 +2784,206 @@ var Renderer = class {
2774
2784
  this.disposed = true;
2775
2785
  }
2776
2786
  };
2787
+
2788
+ // src/audio/recipes.ts
2789
+ import { DISTANCE_CURVES } from "@adatechnology/game-audio";
2790
+ var ATTACK = 2e-3;
2791
+ var lengthOf = (d, attack) => {
2792
+ if (typeof d === "number") return attack + d;
2793
+ if (Array.isArray(d)) return [attack + d[0], attack + d[1]];
2794
+ return { ...d, add: (d.add ?? 0) + attack };
2795
+ };
2796
+ var envelope = (attack) => [
2797
+ [0, 1e-4, "set", "fixed"],
2798
+ [attack, 1, "exp"],
2799
+ ["1d", 1e-4, "exp", "fixed"]
2800
+ ];
2801
+ function noise(o) {
2802
+ const a = o.a ?? ATTACK;
2803
+ const over = typeof o.d === "number" ? o.d : 0;
2804
+ return {
2805
+ filters: {
2806
+ mode: "serial",
2807
+ 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 }]
2808
+ },
2809
+ duration: lengthOf(o.d, a),
2810
+ gain: o.vol,
2811
+ ...o.delay === void 0 ? {} : { at: o.delay },
2812
+ ...o.wet === void 0 ? {} : { wet: o.wet },
2813
+ source: { kind: "noise", offset: "random", offsetScale: 1.5, loop: true },
2814
+ envelope: envelope(a)
2815
+ };
2816
+ }
2817
+ function tone(o) {
2818
+ return {
2819
+ source: { kind: "osc", wave: o.wave ?? "sine", frequency: { from: o.f, to: o.f2 ?? "from", curve: "exp", over: "duration" } },
2820
+ duration: lengthOf(o.d, ATTACK),
2821
+ gain: o.vol,
2822
+ ...o.delay === void 0 ? {} : { at: o.delay },
2823
+ ...o.wet === void 0 ? {} : { wet: o.wet },
2824
+ envelope: envelope(ATTACK)
2825
+ };
2826
+ }
2827
+ var many = (count, make) => Array.from({ length: count }, make);
2828
+ var scene = (id, layers, line, vars) => ({
2829
+ id,
2830
+ bus: "world",
2831
+ pan: true,
2832
+ layers,
2833
+ falloff: DISTANCE_CURVES.art_scene,
2834
+ ...vars ? { vars } : {},
2835
+ sources: [`cena:${line}`]
2836
+ });
2837
+ var boomLayers = (big) => [
2838
+ noise({ f: 1200, f2: 120, d: 1.8, vol: 2, wet: 1.2 }),
2839
+ tone({ f: 65, f2: 24, d: 1, vol: 1.8 }),
2840
+ noise({ type: "highpass", f: 1500, d: 0.2, vol: 0.8 }),
2841
+ ...big ? [noise({ f: 500, f2: 90, a: 0.2, d: 2.4, vol: 1.2, wet: 1, delay: 0.15 })] : [],
2842
+ ...many(8, () => tone({ f: [2600, 5600], d: 0.05, vol: 0.08, delay: [0.4, 1.6] }))
2843
+ ];
2844
+ var SCENE_SOUNDS = [
2845
+ scene(
2846
+ "glass_shatter",
2847
+ [noise({ type: "highpass", f: 2800, d: 0.45, vol: 0.9, wet: 0.5 }), ...many(12, () => tone({ f: [3e3, 7500], d: [0.06, 0.14], vol: 0.18, delay: [0, 0.55] }))],
2848
+ "L1359 glass"
2849
+ ),
2850
+ scene(
2851
+ "wood_hit",
2852
+ [noise({ type: "bandpass", f: 850, q: 1, d: 0.25, vol: 0.9, wet: 0.3 }), tone({ f: 210, f2: 90, d: 0.1, vol: 0.6 }), noise({ type: "highpass", f: 2e3, d: 0.04, vol: 0.5 })],
2853
+ "L1360 wood"
2854
+ ),
2855
+ scene("thunk", [noise({ type: "bandpass", f: 700, q: 2, d: 0.07, vol: 0.4 })], "L1361 thunk"),
2856
+ scene("ping", [tone({ f: [2600, 3500], f2: 1400, d: 0.14, vol: 0.18, wet: 0.3 })], "L1362 ping"),
2857
+ scene("clang", [tone({ f: [520, 720], f2: 480, d: 0.5, vol: 0.35, wet: 0.4 }), tone({ f: 1370, f2: 1300, d: 0.3, vol: 0.15 }), noise({ type: "highpass", f: 2e3, d: 0.05, vol: 0.5 })], "L1363 clang"),
2858
+ scene("chip", [noise({ type: "bandpass", f: 1600, q: 1.2, d: 0.06, vol: 0.5 })], "L1364 chip"),
2859
+ scene(
2860
+ "crumble",
2861
+ [noise({ f: 900, f2: 200, d: 0.6, vol: 0.9, wet: 0.3 }), ...many(5, () => noise({ type: "bandpass", f: [500, 1400], q: 2, d: 0.05, vol: 0.4, delay: [0.1, 0.5] }))],
2862
+ "L1365 crumble"
2863
+ ),
2864
+ // `thud(x, z, v)`: `v` is the `scale` param (default 1)
2865
+ scene("thud", [tone({ f: 75, f2: 38, d: 0.22, vol: { param: "scale", scale: 0.6 } }), noise({ f: 420, d: 0.16, vol: { param: "scale", scale: 0.45 } })], "L1358 thud", { scale: 1 }),
2866
+ // `hiss(x, z, d)`: `seconds` is the param `d` (default 1.2)
2867
+ scene("hiss", [noise({ type: "highpass", f: 3500, a: 0.05, d: { param: "seconds" }, vol: 0.35 })], "L1366 hiss", { seconds: 1.2 }),
2868
+ scene("boom", boomLayers(false), "L1367 boom"),
2869
+ scene("boom_big", boomLayers(true), "L1367 boom (big)"),
2870
+ scene("burst", [noise({ f: 700, f2: 120, d: 0.7, vol: 1.4, wet: 0.5 }), noise({ type: "highpass", f: 3e3, a: 0.05, d: 1.2, vol: 0.4, delay: 0.1 })], "L1357 burst"),
2871
+ scene("crack", [noise({ type: "highpass", f: 1800, d: 0.05, vol: 0.8 }), tone({ f: 420, f2: 180, d: 0.06, vol: 0.4 })], "L1354 crack")
2872
+ ];
2873
+ var EXPLOSION_BOOM = {
2874
+ id: "explosion_boom",
2875
+ bus: "world",
2876
+ order: "boom",
2877
+ duration: 1.6,
2878
+ tail: 0.1,
2879
+ layers: [
2880
+ {
2881
+ source: { kind: "osc", wave: "sine", frequency: { from: 70, to: 28, curve: "exp", over: 1.2 } },
2882
+ envelope: [
2883
+ [0, 1, "set"],
2884
+ ["1d", 1e-3, "exp", "fixed"]
2885
+ ]
2886
+ }
2887
+ ],
2888
+ falloff: DISTANCE_CURVES.game_boom,
2889
+ sources: ["jogo:L68278-68285 boom"]
2890
+ };
2891
+ var BURN_LOOP = {
2892
+ id: "burn_loop",
2893
+ bus: "world",
2894
+ order: "chain_loop",
2895
+ source: { kind: "noise", loop: true },
2896
+ filters: { mode: "serial", bank: [{ type: "bandpass", frequency: { set: 1800 }, q: 0.6 }] },
2897
+ volume: 0,
2898
+ sources: ["cena:L1316 fire loop (silent in the page: its gain is never raised)", "sdk: the level while burning"]
2899
+ };
2900
+ var DESTRUCTION_SOUND_BANK = { id: "destruction_three", sounds: [...SCENE_SOUNDS, EXPLOSION_BOOM], loops: [BURN_LOOP] };
2901
+
2902
+ // src/audio/sound.ts
2903
+ import { GAME_SFX_BANK } from "@adatechnology/game-audio";
2904
+ var DESTRUCTION_SOUND_KEYS = {
2905
+ art_scene: {
2906
+ impact_metal: { sound: "clang" },
2907
+ impact_wood: { sound: "wood_hit" },
2908
+ impact_glass: { sound: "ping" },
2909
+ impact_masonry: { sound: "chip" },
2910
+ impact_soft: { sound: "thud" },
2911
+ shatter_glass: { sound: "glass_shatter" },
2912
+ crumble: { sound: "crumble" },
2913
+ splinter: { sound: "crack" },
2914
+ ricochet: { sound: "ping" },
2915
+ unscrew: { sound: "chip" },
2916
+ detach: { sound: "thunk" },
2917
+ ignite: { sound: "hiss", params: { seconds: 0.5 } },
2918
+ extinguish: { sound: "hiss" },
2919
+ melt_sizzle: { sound: "hiss", params: { seconds: 0.6 } },
2920
+ explode: { sound: "boom", above: { volume: 0.9, sound: "boom_big" } }
2921
+ },
2922
+ game: {
2923
+ impact_metal: { sound: "sfx_impact" },
2924
+ impact_wood: { sound: "sfx_wood" },
2925
+ impact_glass: { sound: "sfx_glass" },
2926
+ impact_masonry: { sound: "sfx_impact" },
2927
+ impact_soft: { sound: "sfx_flesh" },
2928
+ shatter_glass: { sound: "sfx_glass" },
2929
+ crumble: { sound: "sfx_impact" },
2930
+ splinter: { sound: "sfx_wood" },
2931
+ explode: { sound: "explosion_boom" }
2932
+ }
2933
+ };
2934
+ var DEFAULT_FIRE = { perFire: 0.05, max: 0.2 };
2935
+ function createDestructionSound(engine, options = {}) {
2936
+ engine.register(DESTRUCTION_SOUND_BANK);
2937
+ engine.register(GAME_SFX_BANK);
2938
+ const fire = { ...DEFAULT_FIRE, ...options.fire };
2939
+ const rules = { ...DESTRUCTION_SOUND_KEYS.art_scene, ...options.style === "game" ? DESTRUCTION_SOUND_KEYS.game : {}, ...options.keys };
2940
+ let loop;
2941
+ let burning = 0;
2942
+ const setFire = () => {
2943
+ if (options.burnLoop === false) return;
2944
+ if (burning <= 0) {
2945
+ loop?.stop();
2946
+ loop = void 0;
2947
+ return;
2948
+ }
2949
+ loop ?? (loop = engine.loop("burn_loop"));
2950
+ loop.set({ volume: Math.min(fire.max, fire.perFire * burning) });
2951
+ };
2952
+ return {
2953
+ onSound(key, point, volume) {
2954
+ if (key === "burn_loop") {
2955
+ burning += 1;
2956
+ setFire();
2957
+ return;
2958
+ }
2959
+ if (key === "burn_end") {
2960
+ if (burning > 0) burning -= 1;
2961
+ setFire();
2962
+ return;
2963
+ }
2964
+ const rule = rules[key];
2965
+ if (!rule) return;
2966
+ const sound = rule.above && volume >= rule.above.volume ? rule.above.sound : rule.sound;
2967
+ engine.play(sound, { position: point, volume: volume * (rule.volumeScale ?? 1), ...rule.params ? { params: rule.params } : {} });
2968
+ },
2969
+ rule: (key) => rules[key] ?? void 0,
2970
+ burning: () => burning,
2971
+ dispose() {
2972
+ loop?.stop();
2973
+ loop = void 0;
2974
+ burning = 0;
2975
+ }
2976
+ };
2977
+ }
2777
2978
  export {
2979
+ BURN_LOOP,
2980
+ DEFAULT_FIRE,
2981
+ DESTRUCTION_SOUND_BANK,
2982
+ DESTRUCTION_SOUND_KEYS,
2983
+ EXPLOSION_BOOM,
2984
+ SCENE_SOUNDS,
2778
2985
  createDestructionRenderer,
2986
+ createDestructionSound,
2779
2987
  heatColor,
2780
2988
  specFromObject3D
2781
2989
  };