@adatechnology/game-destruction-three 0.5.0 → 0.7.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/README.md +2 -2
- package/dist/index.d.ts +73 -3
- package/dist/index.global.js +357 -13
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +220 -8
- package/dist/index.js.map +1 -1
- package/package.json +8 -6
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ physics, loose pieces after a part comes off, and pooled particles (fire, smoke,
|
|
|
7
7
|
- Nothing is changed in place: geometry and materials are cloned on the first visual change of a mesh, and `restore` / `clear` give the originals back.
|
|
8
8
|
- Blasts and the fires of burning parts are drawn by the effects world of [`@adatechnology/game-vfx`](../game-vfx) (an `explode` event plays `ev.effect ?? 'generic'`, scaled by the radius when it names none). Pass the world the host shares in `vfx`; without it the renderer makes its own world and its own `game-vfx-three` layer and steps them in `update`. Debris, sparks, drips and leaks still use two pooled `THREE.Points` (additive and normal blending), with a soft sprite computed in the shader (no texture asset); they move to the shared sprite pool when `game-vfx` gets one.
|
|
9
9
|
- `three` is a peer dependency used for types only: you pass your own `THREE` instance at runtime.
|
|
10
|
-
-
|
|
10
|
+
- The renderer plays nothing: you get keys (`impact_metal`, `shatter_glass`, `burn_loop`, `burn_end`, ...) through `onSound`. `createDestructionSound(engine)` is the sound bank for them on a [`@adatechnology/game-audio`](../game-audio) engine: the Cena de Arte's material sounds (clang, wood, glass, crumble, thud, boom...) and the game's explosion thump, a fire loop that follows how many parts burn, and a key table (`style: 'art_scene' | 'game'`, `keys` to replace) so a game changes what each key plays.
|
|
11
11
|
|
|
12
12
|
Contracts live in [`@adatechnology/game-contracts`](../game-contracts); the types are re-exported here, so existing imports keep working.
|
|
13
13
|
|
|
@@ -155,7 +155,7 @@ heatColor(temperatureC: number): number // 0xRRGGBB, 0 below ~450 C, dark red ~5
|
|
|
155
155
|
Renderizador three.js para o `@adatechnology/game-destruction`. O núcleo decide o que cada golpe faz e devolve eventos; este pacote desenha: amassados
|
|
156
156
|
nos vértices, furos de bala e rachaduras, carbonização e brilho de calor, derretimento e poças, fragmentos com física leve, peças soltas e partículas
|
|
157
157
|
em pool (fogo, fumaça, faíscas, poeira, cacos, lascas). Geometria e materiais só são clonados na primeira mudança visual de uma malha, e `restore` /
|
|
158
|
-
`clear` devolvem os originais.
|
|
158
|
+
`clear` devolvem os originais. O renderer não toca nada: o jogo recebe chaves (`impact_metal`, `shatter_glass`, `burn_loop`, `burn_end`, ...) em `onSound`; `createDestructionSound(engine)` é o banco de sons delas no `game-audio` (sons dos materiais da Cena de Arte, o estouro do jogo, o laço de fogo e a tabela chave → som, trocável).
|
|
159
159
|
|
|
160
160
|
Uso: `specFromObject3D(THREE, modelo)` gera a especificação e o mapa parte -> malhas; registre no mundo com `world.add(spec)`, ligue com
|
|
161
161
|
`renderer.bind(id, modelo, { parts })` e chame `world.update(dt)` e `renderer.update(dt)` a cada quadro. Com `quality: 'low'` os orçamentos de
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as THREE_NS from 'three';
|
|
2
|
-
import { Vec3, DebrisKind, DestructionWorld, MaterialId, DestructibleSpec } from '@adatechnology/game-destruction';
|
|
2
|
+
import { Vec3, DebrisKind, HitResult, DestructionWorld, MaterialId, DestructibleSpec } from '@adatechnology/game-destruction';
|
|
3
3
|
export { Quat, Vec3 } from '@adatechnology/game-destruction';
|
|
4
4
|
import { VfxWorld, SpriteKind } from '@adatechnology/game-vfx';
|
|
5
|
+
import { LoopRecipe, SoundBank, SoundRecipe, AudioEngine } from '@adatechnology/game-audio';
|
|
6
|
+
import { Vec3 as Vec3$1 } from '@adatechnology/game-contracts';
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* Public types of @adatechnology/game-destruction-three.
|
|
@@ -34,7 +36,7 @@ interface RendererOptions {
|
|
|
34
36
|
autoSplit?: boolean;
|
|
35
37
|
/** Called when a loose piece is created (the bench registers it as grabbable). */
|
|
36
38
|
onPiece?: (piece: Piece) => void;
|
|
37
|
-
/** Called when a sound should play; the host maps keys to audio (e.g. `impact_metal`, `shatter_glass`, `ignite`, `explode`). */
|
|
39
|
+
/** Called when a sound should play; the host maps keys to audio (e.g. `impact_metal`, `shatter_glass`, `ignite`, `explode`). `burn_loop` is sent when a part starts to burn and `burn_end` when it burns out or is put out. */
|
|
38
40
|
onSound?: (key: string, point: Vec3, volume: number) => void;
|
|
39
41
|
/**
|
|
40
42
|
* The effects world that draws blasts and fires. Pass the one the host shares with the other renderers (and step it, through its
|
|
@@ -101,6 +103,11 @@ interface ExplodeOptions {
|
|
|
101
103
|
readonly direction?: Vec3;
|
|
102
104
|
/** `false`: the host drew the blast, only the shove and the sound are left. Default `true`. */
|
|
103
105
|
readonly visual?: boolean;
|
|
106
|
+
/**
|
|
107
|
+
* What `world.explode` returned for this blast. When its results carry a `blast` report (`shelter`, `confinement`), the shove on each piece uses
|
|
108
|
+
* the energy that reached it (`energy * confinement * shelter` of the piece's object) instead of the raw energy. Without it the old formula.
|
|
109
|
+
*/
|
|
110
|
+
readonly report?: readonly HitResult[];
|
|
104
111
|
}
|
|
105
112
|
interface DestructionRenderer {
|
|
106
113
|
/** Attach a world object to its three.js root. */
|
|
@@ -187,7 +194,70 @@ declare function specFromObject3D(THREE: ThreeNamespace, root: Object3D, options
|
|
|
187
194
|
*/
|
|
188
195
|
declare function heatColor(temperatureC: number): number;
|
|
189
196
|
|
|
197
|
+
/** The art scene's destruction sounds, each with the team name in its `sources`. */
|
|
198
|
+
declare const SCENE_SOUNDS: readonly SoundRecipe[];
|
|
199
|
+
/** The game's explosion thump: a sine from 70 to 28 Hz over 1.2 s, `1.4 / (1 + d² × 0.002)` (jogo L68278). */
|
|
200
|
+
declare const EXPLOSION_BOOM: SoundRecipe;
|
|
201
|
+
/**
|
|
202
|
+
* The fire loop of the art scene (cena L1316): noise through a 1800 Hz bandpass (Q 0.6) into a gain that starts at 0. The page never raises it, so it is
|
|
203
|
+
* silent there; here `createDestructionSound` raises it while something burns (the level is the kit's, in `fire`).
|
|
204
|
+
*/
|
|
205
|
+
declare const BURN_LOOP: LoopRecipe;
|
|
206
|
+
declare const DESTRUCTION_SOUND_BANK: SoundBank;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* What a sound key plays: the recipe, its params, a scale on the volume the renderer gives, and (optionally) a louder recipe above a volume
|
|
210
|
+
* (a big blast gets the long boom).
|
|
211
|
+
*/
|
|
212
|
+
type SoundKeyRule = {
|
|
213
|
+
readonly sound: string;
|
|
214
|
+
readonly params?: Readonly<Record<string, number>>;
|
|
215
|
+
readonly volumeScale?: number;
|
|
216
|
+
readonly above?: {
|
|
217
|
+
readonly volume: number;
|
|
218
|
+
readonly sound: string;
|
|
219
|
+
};
|
|
220
|
+
};
|
|
221
|
+
type DestructionSoundStyle = 'art_scene' | 'game';
|
|
222
|
+
/**
|
|
223
|
+
* The keys `createDestructionRenderer` sends to `onSound`, mapped to the sounds the teams delivered. The Cena de Arte has a sound for every material
|
|
224
|
+
* (clang, wood, glass, crumble, thud...); the game has four classes (impact, glass, wood, explosion) and its own explosion thump. Which team sound answers
|
|
225
|
+
* which key is the kit's choice (the teams call the sounds, not the renderer's keys), so it is data: `keys` replaces any entry.
|
|
226
|
+
*/
|
|
227
|
+
declare const DESTRUCTION_SOUND_KEYS: Readonly<Record<DestructionSoundStyle, Readonly<Record<string, SoundKeyRule>>>>;
|
|
228
|
+
type DestructionSoundOptions = {
|
|
229
|
+
/** Which team answers the keys (default `art_scene`, the kit mix). `game` falls back to the art scene for the keys the game has no sound for. */
|
|
230
|
+
readonly style?: DestructionSoundStyle;
|
|
231
|
+
/** Replaces or adds a key's rule; `null` silences it. */
|
|
232
|
+
readonly keys?: Readonly<Record<string, SoundKeyRule | null>>;
|
|
233
|
+
/** The fire loop: the volume each burning part adds and the most it reaches (the page never raises it, so these are the kit's). */
|
|
234
|
+
readonly fire?: {
|
|
235
|
+
readonly perFire?: number;
|
|
236
|
+
readonly max?: number;
|
|
237
|
+
};
|
|
238
|
+
/** Burn loop on or off (default on). */
|
|
239
|
+
readonly burnLoop?: boolean;
|
|
240
|
+
};
|
|
241
|
+
type DestructionSound = {
|
|
242
|
+
/** Pass to `createDestructionRenderer({ onSound })`. */
|
|
243
|
+
readonly onSound: (key: string, point: Vec3$1, volume: number) => void;
|
|
244
|
+
/** The rule a key resolves to, if any. */
|
|
245
|
+
rule(key: string): SoundKeyRule | undefined;
|
|
246
|
+
/** Parts burning now. */
|
|
247
|
+
readonly burning: () => number;
|
|
248
|
+
dispose(): void;
|
|
249
|
+
};
|
|
250
|
+
declare const DEFAULT_FIRE: {
|
|
251
|
+
readonly perFire: 0.05;
|
|
252
|
+
readonly max: 0.2;
|
|
253
|
+
};
|
|
254
|
+
/**
|
|
255
|
+
* Plays the renderer's sound keys on a game-audio engine: the bank is registered in the engine, a key becomes a positional sound at the point, and
|
|
256
|
+
* `burn_loop` / `burn_end` (a part starts to burn, a part burns out or is put out) drive one fire loop whose volume follows how many parts burn.
|
|
257
|
+
*/
|
|
258
|
+
declare function createDestructionSound(engine: AudioEngine, options?: DestructionSoundOptions): DestructionSound;
|
|
259
|
+
|
|
190
260
|
/** Every particle kind the renderer can emit (the game's sprite kinds, see `@adatechnology/game-vfx`). */
|
|
191
261
|
type ParticleKind = SpriteKind;
|
|
192
262
|
|
|
193
|
-
export { type BindOptions, type DestructionRenderer, type ExplodeOptions, type Mesh, type MeshRange, type Object3D, type PartHint, type ParticleKind, type Piece, type Quality, type RendererOptions, type SpecFromObjectOptions, type SpecFromObjectResult, type ThreeNamespace, createDestructionRenderer, heatColor, specFromObject3D };
|
|
263
|
+
export { BURN_LOOP, type BindOptions, DEFAULT_FIRE, DESTRUCTION_SOUND_BANK, DESTRUCTION_SOUND_KEYS, type DestructionRenderer, type DestructionSound, type DestructionSoundOptions, type DestructionSoundStyle, EXPLOSION_BOOM, type ExplodeOptions, type Mesh, type MeshRange, type Object3D, type PartHint, type ParticleKind, type Piece, type Quality, type RendererOptions, SCENE_SOUNDS, type SoundKeyRule, type SpecFromObjectOptions, type SpecFromObjectResult, type ThreeNamespace, createDestructionRenderer, createDestructionSound, heatColor, specFromObject3D };
|
package/dist/index.global.js
CHANGED
|
@@ -23,7 +23,14 @@ var GameDestructionThree = (() => {
|
|
|
23
23
|
// src/index.ts
|
|
24
24
|
var index_exports = {};
|
|
25
25
|
__export(index_exports, {
|
|
26
|
+
BURN_LOOP: () => BURN_LOOP,
|
|
27
|
+
DEFAULT_FIRE: () => DEFAULT_FIRE,
|
|
28
|
+
DESTRUCTION_SOUND_BANK: () => DESTRUCTION_SOUND_BANK,
|
|
29
|
+
DESTRUCTION_SOUND_KEYS: () => DESTRUCTION_SOUND_KEYS,
|
|
30
|
+
EXPLOSION_BOOM: () => EXPLOSION_BOOM,
|
|
31
|
+
SCENE_SOUNDS: () => SCENE_SOUNDS,
|
|
26
32
|
createDestructionRenderer: () => createDestructionRenderer,
|
|
33
|
+
createDestructionSound: () => createDestructionSound,
|
|
27
34
|
heatColor: () => heatColor,
|
|
28
35
|
specFromObject3D: () => specFromObject3D
|
|
29
36
|
});
|
|
@@ -5284,9 +5291,9 @@ var GameDestructionThree = (() => {
|
|
|
5284
5291
|
this.color[i3] = lerp4(this.rgbStart[i3], this.rgbEnd[i3], t);
|
|
5285
5292
|
this.color[i3 + 1] = lerp4(this.rgbStart[i3 + 1], this.rgbEnd[i3 + 1], t);
|
|
5286
5293
|
this.color[i3 + 2] = lerp4(this.rgbStart[i3 + 2], this.rgbEnd[i3 + 2], t);
|
|
5287
|
-
let
|
|
5288
|
-
if (def.flicker)
|
|
5289
|
-
this.alpha[i] = clamp4(
|
|
5294
|
+
let envelope2 = t < def.fadeIn ? t / def.fadeIn : 1 - (t - def.fadeIn) / (1 - def.fadeIn);
|
|
5295
|
+
if (def.flicker) envelope2 *= 1 - def.flicker * (0.5 + 0.5 * Math.sin(age * 38 + this.seed[i] * 50));
|
|
5296
|
+
this.alpha[i] = clamp4(envelope2, 0, 1) * def.alpha * this.alphaMul[i];
|
|
5290
5297
|
top = i + 1;
|
|
5291
5298
|
}
|
|
5292
5299
|
this.high = top;
|
|
@@ -8143,9 +8150,9 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8143
8150
|
// src/ground.ts
|
|
8144
8151
|
var MAX_RADIUS = 1.2;
|
|
8145
8152
|
var GroundSpots = class {
|
|
8146
|
-
constructor(THREE,
|
|
8153
|
+
constructor(THREE, scene2, groundAt, cap) {
|
|
8147
8154
|
__publicField(this, "THREE", THREE);
|
|
8148
|
-
__publicField(this, "scene",
|
|
8155
|
+
__publicField(this, "scene", scene2);
|
|
8149
8156
|
__publicField(this, "groundAt", groundAt);
|
|
8150
8157
|
__publicField(this, "cap", cap);
|
|
8151
8158
|
__publicField(this, "spots", []);
|
|
@@ -8547,9 +8554,9 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8547
8554
|
|
|
8548
8555
|
// src/rebar.ts
|
|
8549
8556
|
var RebarCages = class {
|
|
8550
|
-
constructor(THREE,
|
|
8557
|
+
constructor(THREE, scene2, radius = 4e-3) {
|
|
8551
8558
|
__publicField(this, "THREE", THREE);
|
|
8552
|
-
__publicField(this, "scene",
|
|
8559
|
+
__publicField(this, "scene", scene2);
|
|
8553
8560
|
__publicField(this, "cages", /* @__PURE__ */ new Map());
|
|
8554
8561
|
__publicField(this, "geometry");
|
|
8555
8562
|
__publicField(this, "material");
|
|
@@ -8969,7 +8976,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8969
8976
|
0.25
|
|
8970
8977
|
],
|
|
8971
8978
|
damageScale: {
|
|
8972
|
-
blunt: 1.5
|
|
8979
|
+
blunt: 1.5,
|
|
8980
|
+
shelter: 3
|
|
8973
8981
|
},
|
|
8974
8982
|
hitDebris: "shards",
|
|
8975
8983
|
breakDebris: "shards",
|
|
@@ -9020,7 +9028,10 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
9020
9028
|
"glass",
|
|
9021
9029
|
"brittle"
|
|
9022
9030
|
],
|
|
9023
|
-
compressive: 2e5
|
|
9031
|
+
compressive: 2e5,
|
|
9032
|
+
damageScale: {
|
|
9033
|
+
shelter: 3
|
|
9034
|
+
}
|
|
9024
9035
|
},
|
|
9025
9036
|
{
|
|
9026
9037
|
id: "ceramic",
|
|
@@ -10413,10 +10424,10 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
10413
10424
|
const sy = lerp5(1, 0.25, melt);
|
|
10414
10425
|
const sxz = 1 + 0.18 * melt;
|
|
10415
10426
|
for (let i = range[0] * 3, v = 0; i < range[1] * 3; i += 3, v++) {
|
|
10416
|
-
const
|
|
10427
|
+
const noise2 = (Math.imul(v + 1, 2654435761) >>> 0) % 1e3 / 1e3;
|
|
10417
10428
|
arr[i] = cx + (work[i] - cx) * sxz;
|
|
10418
10429
|
arr[i + 2] = cz + (work[i + 2] - cz) * sxz;
|
|
10419
|
-
arr[i + 1] = Math.max(minY, minY + (work[i + 1] - minY) * sy -
|
|
10430
|
+
arr[i + 1] = Math.max(minY, minY + (work[i + 1] - minY) * sy - noise2 * melt * h * 0.04);
|
|
10420
10431
|
}
|
|
10421
10432
|
}
|
|
10422
10433
|
/** The colour attribute of the host's current geometry (created white when there is none) with vertex colours switched on in its material. */
|
|
@@ -10741,6 +10752,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
10741
10752
|
__publicField(this, "cages");
|
|
10742
10753
|
__publicField(this, "active", /* @__PURE__ */ new Map());
|
|
10743
10754
|
__publicField(this, "fires", /* @__PURE__ */ new Map());
|
|
10755
|
+
/** Primed parts burning in the effects world until they go off: their burn loop ends when they are put out. */
|
|
10756
|
+
__publicField(this, "primedBurning", /* @__PURE__ */ new Set());
|
|
10744
10757
|
__publicField(this, "leaks", []);
|
|
10745
10758
|
__publicField(this, "homeTags", []);
|
|
10746
10759
|
__publicField(this, "throttles", /* @__PURE__ */ new Map());
|
|
@@ -11082,8 +11095,10 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
11082
11095
|
case "primed":
|
|
11083
11096
|
if (ev.trigger !== "explosion") {
|
|
11084
11097
|
this.vfx.fire({ point: ev.point, radius: PRIMED_FIRE_RADIUS, life: ev.delay });
|
|
11098
|
+
this.primedBurning.add(`${ev.object}|${ev.part}`);
|
|
11085
11099
|
this.activate(ev.object, ev.part);
|
|
11086
11100
|
this.sound("ignite", ev.point, 0.7);
|
|
11101
|
+
this.sound("burn_loop", ev.point, 0.5);
|
|
11087
11102
|
}
|
|
11088
11103
|
break;
|
|
11089
11104
|
case "spall":
|
|
@@ -11101,16 +11116,20 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
11101
11116
|
break;
|
|
11102
11117
|
case "extinguish": {
|
|
11103
11118
|
const f = this.fires.get(`${ev.object}|${ev.part}`);
|
|
11119
|
+
const primed = this.primedBurning.delete(`${ev.object}|${ev.part}`);
|
|
11104
11120
|
if (f) {
|
|
11105
11121
|
this.stopFire(`${ev.object}|${ev.part}`);
|
|
11106
11122
|
this.vfx.burst("steam", f.point, [0, 1, 0], 14, 1.2);
|
|
11107
11123
|
}
|
|
11124
|
+
if (f || primed) this.sound("burn_end", f?.point ?? this.rootPoint(ev.object), 0.5);
|
|
11108
11125
|
this.activate(ev.object, ev.part);
|
|
11109
11126
|
this.sound("extinguish", f?.point ?? this.rootPoint(ev.object), 0.6);
|
|
11110
11127
|
break;
|
|
11111
11128
|
}
|
|
11112
11129
|
case "burnout": {
|
|
11113
11130
|
this.stopFire(`${ev.object}|${ev.part}`);
|
|
11131
|
+
this.primedBurning.delete(`${ev.object}|${ev.part}`);
|
|
11132
|
+
this.sound("burn_end", ev.point, 0.5);
|
|
11114
11133
|
this.vfx.burst("ash", ev.point, [0, 1, 0], 16, 1);
|
|
11115
11134
|
this.vfx.burst("smoke", ev.point, [0, 1, 0], 6, 0.8, { color: SMOKE_TONES.grey });
|
|
11116
11135
|
const pv = this.partVis(ev.object, ev.part);
|
|
@@ -11152,6 +11171,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
11152
11171
|
break;
|
|
11153
11172
|
}
|
|
11154
11173
|
case "explode":
|
|
11174
|
+
this.primedBurning.delete(`${ev.object}|${ev.part}`);
|
|
11155
11175
|
this.onExplode(ev);
|
|
11156
11176
|
break;
|
|
11157
11177
|
case "destroyed":
|
|
@@ -11445,6 +11465,9 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
11445
11465
|
if (options.visual !== false) this.playExplosion(ev, options);
|
|
11446
11466
|
this.vfx.push(p, ev.radius, 4);
|
|
11447
11467
|
const c = this.v1;
|
|
11468
|
+
const report = options.report;
|
|
11469
|
+
const confinement = report?.find((r) => r.blast !== void 0)?.blast?.confinement ?? 1;
|
|
11470
|
+
const energy = ev.energy * confinement;
|
|
11448
11471
|
for (const pc of this.pieceSys.list) {
|
|
11449
11472
|
this.pieceSys.centerOf(pc, c);
|
|
11450
11473
|
const dx = c.x - p[0];
|
|
@@ -11453,13 +11476,14 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
11453
11476
|
const d = Math.hypot(dx, dy, dz);
|
|
11454
11477
|
if (d > ev.radius) continue;
|
|
11455
11478
|
const fall = (1 - d / ev.radius) ** 2;
|
|
11456
|
-
const
|
|
11479
|
+
const reach = report?.find((r) => r.object === pc.objectId)?.blast?.shelter ?? 1;
|
|
11480
|
+
const speed = Math.min(30, Math.sqrt(2 * energy * reach * 0.02 / pc.mass)) * fall;
|
|
11457
11481
|
const inv = d > 1e-4 ? 1 / d : 0;
|
|
11458
11482
|
const dir = d > 1e-4 ? [dx * inv, dy * inv + 0.3, dz * inv] : [0, 1, 0];
|
|
11459
11483
|
const spread = pc.halfExtents[0];
|
|
11460
11484
|
this.pieceSys.impulse(pc, [dir[0] * speed * pc.mass, dir[1] * speed * pc.mass, dir[2] * speed * pc.mass], [c.x + (this.rng() - 0.5) * spread, c.y + spread * 0.5, c.z + (this.rng() - 0.5) * spread]);
|
|
11461
11485
|
}
|
|
11462
|
-
this.fragments.blast(p, ev.radius, Math.min(20, Math.sqrt(
|
|
11486
|
+
this.fragments.blast(p, ev.radius, Math.min(20, Math.sqrt(energy) * 0.08));
|
|
11463
11487
|
this.sound("explode", p, clamp6(0.5 + ev.radius / 10, 0.5, 1));
|
|
11464
11488
|
}
|
|
11465
11489
|
playExplosion(ev, options) {
|
|
@@ -11642,6 +11666,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
11642
11666
|
this.fragments.clear();
|
|
11643
11667
|
this.ground.clear();
|
|
11644
11668
|
this.cages.clear();
|
|
11669
|
+
this.primedBurning.clear();
|
|
11645
11670
|
this.vfx.sprites().clear();
|
|
11646
11671
|
this.ownVfx?.world.clear();
|
|
11647
11672
|
}
|
|
@@ -11670,6 +11695,325 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
11670
11695
|
this.disposed = true;
|
|
11671
11696
|
}
|
|
11672
11697
|
};
|
|
11698
|
+
|
|
11699
|
+
// ../game-audio/dist/index.js
|
|
11700
|
+
var DISTANCE_CURVES = {
|
|
11701
|
+
/** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
|
|
11702
|
+
game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
|
|
11703
|
+
/** The game's `grito`: `1 / (1 + d² × 0.006)`, silent below 0.02 (jogo L62129–62130). */
|
|
11704
|
+
game_scream: { model: "inverse_square", k: 6e-3, minGain: 0.02 },
|
|
11705
|
+
/** The game's `voz`: `1 / (1 + d² × 0.01)`, silent below 0.02 (jogo L62146–62147). */
|
|
11706
|
+
game_voice: { model: "inverse_square", k: 0.01, minGain: 0.02 },
|
|
11707
|
+
/** The game's `boom`: `1.4 / (1 + d² × 0.002)`, never silent (jogo L68280). */
|
|
11708
|
+
game_boom: { model: "inverse_square", k: 2e-3, scale: 1.4 },
|
|
11709
|
+
/** The art scene's `outAt`: `vol / (1 + d² × 0.008)` (cena L1320). */
|
|
11710
|
+
art_scene: { model: "inverse_square", k: 8e-3 },
|
|
11711
|
+
/** The game's animal calls: `max(0, 1 − d / 70) × 0.25`, silent at or below 0.005 (jogo L66627–66628). */
|
|
11712
|
+
animals: { model: "linear", range: 70, scale: 0.25, minGain: 5e-3 }
|
|
11713
|
+
};
|
|
11714
|
+
var mix_profiles_default = [
|
|
11715
|
+
{
|
|
11716
|
+
id: "game",
|
|
11717
|
+
master: 0.5,
|
|
11718
|
+
noise: { seconds: 1.5, create: "lazy" },
|
|
11719
|
+
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"]
|
|
11720
|
+
},
|
|
11721
|
+
{
|
|
11722
|
+
id: "art_scene",
|
|
11723
|
+
master: 0.85,
|
|
11724
|
+
compressor: { threshold: -12, ratio: 5 },
|
|
11725
|
+
reverb: { seconds: 2.2, decay: 3.4, wet: 0.4 },
|
|
11726
|
+
noise: { seconds: 2, create: "eager" },
|
|
11727
|
+
sources: [
|
|
11728
|
+
"cena:L1308 compressor -12 dB, ratio 5",
|
|
11729
|
+
"cena:L1309 master 0.85",
|
|
11730
|
+
"cena:L1310 convolver, impulse 2.2 s of (1 - i/len)^3.4",
|
|
11731
|
+
"cena:L1311 wet 0.4",
|
|
11732
|
+
"cena:L1312 noise 2 s made with the chain"
|
|
11733
|
+
]
|
|
11734
|
+
}
|
|
11735
|
+
];
|
|
11736
|
+
var MIX_PROFILES = Object.fromEntries(
|
|
11737
|
+
mix_profiles_default.map((profile) => [profile.id, profile])
|
|
11738
|
+
);
|
|
11739
|
+
var game_sfx_default = {
|
|
11740
|
+
sources: ["jogo:L62089-62107"],
|
|
11741
|
+
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`.",
|
|
11742
|
+
classes: [
|
|
11743
|
+
{ id: "pistol", team: "pistola", bus: "weapons", cutoff: 1800, gain: 0.9, seconds: 0.18 },
|
|
11744
|
+
{ id: "shotgun", team: "escopeta", bus: "weapons", cutoff: 900, gain: 1.2, seconds: 0.35 },
|
|
11745
|
+
{ id: "rifle", team: "fuzil", bus: "weapons", cutoff: 1400, gain: 1.1, seconds: 0.28 },
|
|
11746
|
+
{ id: "long_rifle", team: "rifle", bus: "weapons", cutoff: 1100, gain: 1.3, seconds: 0.45 },
|
|
11747
|
+
{ id: "impact", team: "impacto", bus: "world", cutoff: 2500, gain: 0.25, seconds: 0.05 },
|
|
11748
|
+
{ id: "flesh", team: "carne", bus: "world", cutoff: 600, gain: 0.35, seconds: 0.08 },
|
|
11749
|
+
{ id: "step", team: "passo", bus: "world", cutoff: 400, gain: 0.08, seconds: 0.05 },
|
|
11750
|
+
{ id: "glass", team: "vidro", bus: "world", cutoff: 5e3, gain: 0.5, seconds: 0.3 },
|
|
11751
|
+
{ id: "wood", team: "madeira", bus: "world", cutoff: 700, gain: 0.5, seconds: 0.2 },
|
|
11752
|
+
{ id: "reload", team: "recarga", bus: "weapons", cutoff: 3e3, gain: 0.15, seconds: 0.06 },
|
|
11753
|
+
{ id: "empty", team: "vazio", bus: "weapons", cutoff: 4e3, gain: 0.12, seconds: 0.03 },
|
|
11754
|
+
{ id: "explosion", team: "explosao", bus: "world", cutoff: 200, gain: 1.6, seconds: 1.4 }
|
|
11755
|
+
],
|
|
11756
|
+
fallback: { id: "unknown", team: "(any other name)", bus: "world", cutoff: 1e3, gain: 0.5, seconds: 0.1 }
|
|
11757
|
+
};
|
|
11758
|
+
var GAME_SFX = game_sfx_default;
|
|
11759
|
+
var GAME_SFX_CLASSES = GAME_SFX.classes;
|
|
11760
|
+
var GAME_SFX_FALLBACK = GAME_SFX.fallback;
|
|
11761
|
+
function noiseClassRecipe(row, id = `sfx_${row.id}`) {
|
|
11762
|
+
return {
|
|
11763
|
+
id,
|
|
11764
|
+
bus: row.bus,
|
|
11765
|
+
order: "burst",
|
|
11766
|
+
duration: row.seconds,
|
|
11767
|
+
tail: 0.05,
|
|
11768
|
+
layers: [
|
|
11769
|
+
{
|
|
11770
|
+
source: { kind: "noise", offset: "random" },
|
|
11771
|
+
filters: { mode: "serial", bank: [{ type: "lowpass", frequency: { set: row.cutoff } }] },
|
|
11772
|
+
envelope: [
|
|
11773
|
+
[0, row.gain, "set"],
|
|
11774
|
+
["1d", 1e-3, "exp", "fixed"]
|
|
11775
|
+
]
|
|
11776
|
+
}
|
|
11777
|
+
],
|
|
11778
|
+
falloff: DISTANCE_CURVES.game_sfx,
|
|
11779
|
+
sources: [...GAME_SFX.sources.map((source) => `${source} ${row.team}`)]
|
|
11780
|
+
};
|
|
11781
|
+
}
|
|
11782
|
+
var GAME_SFX_BANK = { id: "game_sfx", sounds: [...GAME_SFX_CLASSES, GAME_SFX_FALLBACK].map((row) => noiseClassRecipe(row)) };
|
|
11783
|
+
var BENCH_BANK = {
|
|
11784
|
+
id: "audio_bench",
|
|
11785
|
+
sounds: [
|
|
11786
|
+
{
|
|
11787
|
+
id: "bench_ping",
|
|
11788
|
+
bus: "ui",
|
|
11789
|
+
pan: true,
|
|
11790
|
+
duration: 0.25,
|
|
11791
|
+
layers: [
|
|
11792
|
+
{
|
|
11793
|
+
gain: 0.5,
|
|
11794
|
+
wet: 0.3,
|
|
11795
|
+
source: { kind: "osc", wave: "sine", frequency: { from: 880 } },
|
|
11796
|
+
envelope: [
|
|
11797
|
+
[0, 1e-4, "set", "fixed"],
|
|
11798
|
+
[2e-3, 1, "exp"],
|
|
11799
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
11800
|
+
]
|
|
11801
|
+
}
|
|
11802
|
+
],
|
|
11803
|
+
falloff: DISTANCE_CURVES.art_scene,
|
|
11804
|
+
sources: ["sdk: bench probe, a 880 Hz ping through the art scene output stage"]
|
|
11805
|
+
},
|
|
11806
|
+
{
|
|
11807
|
+
id: "bench_hiss",
|
|
11808
|
+
bus: "ui",
|
|
11809
|
+
pan: true,
|
|
11810
|
+
duration: [0.3, 0.9],
|
|
11811
|
+
layers: [
|
|
11812
|
+
{
|
|
11813
|
+
gain: 0.4,
|
|
11814
|
+
source: { kind: "noise", offset: "random", offsetScale: 1.5, loop: true },
|
|
11815
|
+
filters: { mode: "serial", bank: [{ type: "highpass", frequency: { set: 3e3 }, q: 0.7 }] },
|
|
11816
|
+
envelope: [
|
|
11817
|
+
[0, 1e-4, "set", "fixed"],
|
|
11818
|
+
[2e-3, 1, "exp"],
|
|
11819
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
11820
|
+
]
|
|
11821
|
+
}
|
|
11822
|
+
],
|
|
11823
|
+
falloff: DISTANCE_CURVES.art_scene,
|
|
11824
|
+
sources: ["sdk: bench probe, a highpass hiss of random length"]
|
|
11825
|
+
}
|
|
11826
|
+
]
|
|
11827
|
+
};
|
|
11828
|
+
|
|
11829
|
+
// src/audio/recipes.ts
|
|
11830
|
+
var ATTACK = 2e-3;
|
|
11831
|
+
var lengthOf = (d, attack) => {
|
|
11832
|
+
if (typeof d === "number") return attack + d;
|
|
11833
|
+
if (Array.isArray(d)) return [attack + d[0], attack + d[1]];
|
|
11834
|
+
return { ...d, add: (d.add ?? 0) + attack };
|
|
11835
|
+
};
|
|
11836
|
+
var envelope = (attack) => [
|
|
11837
|
+
[0, 1e-4, "set", "fixed"],
|
|
11838
|
+
[attack, 1, "exp"],
|
|
11839
|
+
["1d", 1e-4, "exp", "fixed"]
|
|
11840
|
+
];
|
|
11841
|
+
function noise(o) {
|
|
11842
|
+
const a = o.a ?? ATTACK;
|
|
11843
|
+
const over = typeof o.d === "number" ? o.d : 0;
|
|
11844
|
+
return {
|
|
11845
|
+
filters: {
|
|
11846
|
+
mode: "serial",
|
|
11847
|
+
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 }]
|
|
11848
|
+
},
|
|
11849
|
+
duration: lengthOf(o.d, a),
|
|
11850
|
+
gain: o.vol,
|
|
11851
|
+
...o.delay === void 0 ? {} : { at: o.delay },
|
|
11852
|
+
...o.wet === void 0 ? {} : { wet: o.wet },
|
|
11853
|
+
source: { kind: "noise", offset: "random", offsetScale: 1.5, loop: true },
|
|
11854
|
+
envelope: envelope(a)
|
|
11855
|
+
};
|
|
11856
|
+
}
|
|
11857
|
+
function tone(o) {
|
|
11858
|
+
return {
|
|
11859
|
+
source: { kind: "osc", wave: o.wave ?? "sine", frequency: { from: o.f, to: o.f2 ?? "from", curve: "exp", over: "duration" } },
|
|
11860
|
+
duration: lengthOf(o.d, ATTACK),
|
|
11861
|
+
gain: o.vol,
|
|
11862
|
+
...o.delay === void 0 ? {} : { at: o.delay },
|
|
11863
|
+
...o.wet === void 0 ? {} : { wet: o.wet },
|
|
11864
|
+
envelope: envelope(ATTACK)
|
|
11865
|
+
};
|
|
11866
|
+
}
|
|
11867
|
+
var many = (count, make) => Array.from({ length: count }, make);
|
|
11868
|
+
var scene = (id, layers, line, vars) => ({
|
|
11869
|
+
id,
|
|
11870
|
+
bus: "world",
|
|
11871
|
+
pan: true,
|
|
11872
|
+
layers,
|
|
11873
|
+
falloff: DISTANCE_CURVES.art_scene,
|
|
11874
|
+
...vars ? { vars } : {},
|
|
11875
|
+
sources: [`cena:${line}`]
|
|
11876
|
+
});
|
|
11877
|
+
var boomLayers = (big) => [
|
|
11878
|
+
noise({ f: 1200, f2: 120, d: 1.8, vol: 2, wet: 1.2 }),
|
|
11879
|
+
tone({ f: 65, f2: 24, d: 1, vol: 1.8 }),
|
|
11880
|
+
noise({ type: "highpass", f: 1500, d: 0.2, vol: 0.8 }),
|
|
11881
|
+
...big ? [noise({ f: 500, f2: 90, a: 0.2, d: 2.4, vol: 1.2, wet: 1, delay: 0.15 })] : [],
|
|
11882
|
+
...many(8, () => tone({ f: [2600, 5600], d: 0.05, vol: 0.08, delay: [0.4, 1.6] }))
|
|
11883
|
+
];
|
|
11884
|
+
var SCENE_SOUNDS = [
|
|
11885
|
+
scene(
|
|
11886
|
+
"glass_shatter",
|
|
11887
|
+
[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] }))],
|
|
11888
|
+
"L1359 glass"
|
|
11889
|
+
),
|
|
11890
|
+
scene(
|
|
11891
|
+
"wood_hit",
|
|
11892
|
+
[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 })],
|
|
11893
|
+
"L1360 wood"
|
|
11894
|
+
),
|
|
11895
|
+
scene("thunk", [noise({ type: "bandpass", f: 700, q: 2, d: 0.07, vol: 0.4 })], "L1361 thunk"),
|
|
11896
|
+
scene("ping", [tone({ f: [2600, 3500], f2: 1400, d: 0.14, vol: 0.18, wet: 0.3 })], "L1362 ping"),
|
|
11897
|
+
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"),
|
|
11898
|
+
scene("chip", [noise({ type: "bandpass", f: 1600, q: 1.2, d: 0.06, vol: 0.5 })], "L1364 chip"),
|
|
11899
|
+
scene(
|
|
11900
|
+
"crumble",
|
|
11901
|
+
[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] }))],
|
|
11902
|
+
"L1365 crumble"
|
|
11903
|
+
),
|
|
11904
|
+
// `thud(x, z, v)`: `v` is the `scale` param (default 1)
|
|
11905
|
+
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 }),
|
|
11906
|
+
// `hiss(x, z, d)`: `seconds` is the param `d` (default 1.2)
|
|
11907
|
+
scene("hiss", [noise({ type: "highpass", f: 3500, a: 0.05, d: { param: "seconds" }, vol: 0.35 })], "L1366 hiss", { seconds: 1.2 }),
|
|
11908
|
+
scene("boom", boomLayers(false), "L1367 boom"),
|
|
11909
|
+
scene("boom_big", boomLayers(true), "L1367 boom (big)"),
|
|
11910
|
+
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"),
|
|
11911
|
+
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")
|
|
11912
|
+
];
|
|
11913
|
+
var EXPLOSION_BOOM = {
|
|
11914
|
+
id: "explosion_boom",
|
|
11915
|
+
bus: "world",
|
|
11916
|
+
order: "boom",
|
|
11917
|
+
duration: 1.6,
|
|
11918
|
+
tail: 0.1,
|
|
11919
|
+
layers: [
|
|
11920
|
+
{
|
|
11921
|
+
source: { kind: "osc", wave: "sine", frequency: { from: 70, to: 28, curve: "exp", over: 1.2 } },
|
|
11922
|
+
envelope: [
|
|
11923
|
+
[0, 1, "set"],
|
|
11924
|
+
["1d", 1e-3, "exp", "fixed"]
|
|
11925
|
+
]
|
|
11926
|
+
}
|
|
11927
|
+
],
|
|
11928
|
+
falloff: DISTANCE_CURVES.game_boom,
|
|
11929
|
+
sources: ["jogo:L68278-68285 boom"]
|
|
11930
|
+
};
|
|
11931
|
+
var BURN_LOOP = {
|
|
11932
|
+
id: "burn_loop",
|
|
11933
|
+
bus: "world",
|
|
11934
|
+
order: "chain_loop",
|
|
11935
|
+
source: { kind: "noise", loop: true },
|
|
11936
|
+
filters: { mode: "serial", bank: [{ type: "bandpass", frequency: { set: 1800 }, q: 0.6 }] },
|
|
11937
|
+
volume: 0,
|
|
11938
|
+
sources: ["cena:L1316 fire loop (silent in the page: its gain is never raised)", "sdk: the level while burning"]
|
|
11939
|
+
};
|
|
11940
|
+
var DESTRUCTION_SOUND_BANK = { id: "destruction_three", sounds: [...SCENE_SOUNDS, EXPLOSION_BOOM], loops: [BURN_LOOP] };
|
|
11941
|
+
|
|
11942
|
+
// src/audio/sound.ts
|
|
11943
|
+
var DESTRUCTION_SOUND_KEYS = {
|
|
11944
|
+
art_scene: {
|
|
11945
|
+
impact_metal: { sound: "clang" },
|
|
11946
|
+
impact_wood: { sound: "wood_hit" },
|
|
11947
|
+
impact_glass: { sound: "ping" },
|
|
11948
|
+
impact_masonry: { sound: "chip" },
|
|
11949
|
+
impact_soft: { sound: "thud" },
|
|
11950
|
+
shatter_glass: { sound: "glass_shatter" },
|
|
11951
|
+
crumble: { sound: "crumble" },
|
|
11952
|
+
splinter: { sound: "crack" },
|
|
11953
|
+
ricochet: { sound: "ping" },
|
|
11954
|
+
unscrew: { sound: "chip" },
|
|
11955
|
+
detach: { sound: "thunk" },
|
|
11956
|
+
ignite: { sound: "hiss", params: { seconds: 0.5 } },
|
|
11957
|
+
extinguish: { sound: "hiss" },
|
|
11958
|
+
melt_sizzle: { sound: "hiss", params: { seconds: 0.6 } },
|
|
11959
|
+
explode: { sound: "boom", above: { volume: 0.9, sound: "boom_big" } }
|
|
11960
|
+
},
|
|
11961
|
+
game: {
|
|
11962
|
+
impact_metal: { sound: "sfx_impact" },
|
|
11963
|
+
impact_wood: { sound: "sfx_wood" },
|
|
11964
|
+
impact_glass: { sound: "sfx_glass" },
|
|
11965
|
+
impact_masonry: { sound: "sfx_impact" },
|
|
11966
|
+
impact_soft: { sound: "sfx_flesh" },
|
|
11967
|
+
shatter_glass: { sound: "sfx_glass" },
|
|
11968
|
+
crumble: { sound: "sfx_impact" },
|
|
11969
|
+
splinter: { sound: "sfx_wood" },
|
|
11970
|
+
explode: { sound: "explosion_boom" }
|
|
11971
|
+
}
|
|
11972
|
+
};
|
|
11973
|
+
var DEFAULT_FIRE = { perFire: 0.05, max: 0.2 };
|
|
11974
|
+
function createDestructionSound(engine, options = {}) {
|
|
11975
|
+
engine.register(DESTRUCTION_SOUND_BANK);
|
|
11976
|
+
engine.register(GAME_SFX_BANK);
|
|
11977
|
+
const fire = { ...DEFAULT_FIRE, ...options.fire };
|
|
11978
|
+
const rules = { ...DESTRUCTION_SOUND_KEYS.art_scene, ...options.style === "game" ? DESTRUCTION_SOUND_KEYS.game : {}, ...options.keys };
|
|
11979
|
+
let loop;
|
|
11980
|
+
let burning = 0;
|
|
11981
|
+
const setFire = () => {
|
|
11982
|
+
if (options.burnLoop === false) return;
|
|
11983
|
+
if (burning <= 0) {
|
|
11984
|
+
loop?.stop();
|
|
11985
|
+
loop = void 0;
|
|
11986
|
+
return;
|
|
11987
|
+
}
|
|
11988
|
+
loop ?? (loop = engine.loop("burn_loop"));
|
|
11989
|
+
loop.set({ volume: Math.min(fire.max, fire.perFire * burning) });
|
|
11990
|
+
};
|
|
11991
|
+
return {
|
|
11992
|
+
onSound(key, point, volume) {
|
|
11993
|
+
if (key === "burn_loop") {
|
|
11994
|
+
burning += 1;
|
|
11995
|
+
setFire();
|
|
11996
|
+
return;
|
|
11997
|
+
}
|
|
11998
|
+
if (key === "burn_end") {
|
|
11999
|
+
if (burning > 0) burning -= 1;
|
|
12000
|
+
setFire();
|
|
12001
|
+
return;
|
|
12002
|
+
}
|
|
12003
|
+
const rule = rules[key];
|
|
12004
|
+
if (!rule) return;
|
|
12005
|
+
const sound = rule.above && volume >= rule.above.volume ? rule.above.sound : rule.sound;
|
|
12006
|
+
engine.play(sound, { position: point, volume: volume * (rule.volumeScale ?? 1), ...rule.params ? { params: rule.params } : {} });
|
|
12007
|
+
},
|
|
12008
|
+
rule: (key) => rules[key] ?? void 0,
|
|
12009
|
+
burning: () => burning,
|
|
12010
|
+
dispose() {
|
|
12011
|
+
loop?.stop();
|
|
12012
|
+
loop = void 0;
|
|
12013
|
+
burning = 0;
|
|
12014
|
+
}
|
|
12015
|
+
};
|
|
12016
|
+
}
|
|
11673
12017
|
return __toCommonJS(index_exports);
|
|
11674
12018
|
})();
|
|
11675
12019
|
//# sourceMappingURL=index.global.js.map
|