@adatechnology/game-weapons-three 0.11.3 → 0.13.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 +7 -1
- package/dist/chunk-NQELXT56.js +11060 -0
- package/dist/chunk-NQELXT56.js.map +1 -0
- package/dist/index.d.ts +33 -989
- package/dist/index.global.js +6902 -3229
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +108 -9827
- package/dist/index.js.map +1 -1
- package/dist/testing-BoxqhX_W.d.ts +1698 -0
- package/dist/testing.d.ts +6 -0
- package/dist/testing.js +25 -0
- package/dist/testing.js.map +1 -0
- package/package.json +15 -11
|
@@ -0,0 +1,1698 @@
|
|
|
1
|
+
import { HostTool, HandPose, EffectSink, HostEvent, HandTargets, TestableModule, AreaPlacement, DestructionEvent, Hit, Vec3 as Vec3$1, ModuleControl, ModuleLayer, ModuleMetric, ModuleHost } from '@adatechnology/game-contracts';
|
|
2
|
+
import { CaseType, CaliberDef, ReloadStageId, WeaponEvent, MountKind, AttachmentDef, FittedAttachment, Arsenal, WeaponDef, ExplosiveDef } from '@adatechnology/game-weapons';
|
|
3
|
+
import { SampleDefaults, SfxManifest, SoundBank, SfxManifestSound, AudioEngine } from '@adatechnology/game-audio';
|
|
4
|
+
import * as THREE_NS from 'three';
|
|
5
|
+
import { LightBudget, RenderPools } from '@adatechnology/game-render-three';
|
|
6
|
+
|
|
7
|
+
interface FlybyInput {
|
|
8
|
+
/** Bullet speed where it passes the listener, m/s. */
|
|
9
|
+
readonly speed: number;
|
|
10
|
+
/** Closest distance from the bullet path to the listener's head, metres. Past `maxMiss` nothing is heard. */
|
|
11
|
+
readonly miss: number;
|
|
12
|
+
/** Pitch factor around 1. */
|
|
13
|
+
readonly pitch?: number;
|
|
14
|
+
/** Default 6 m. */
|
|
15
|
+
readonly maxMiss?: number;
|
|
16
|
+
}
|
|
17
|
+
interface FlybyVoice {
|
|
18
|
+
readonly kind: 'noise' | 'tone';
|
|
19
|
+
readonly filter?: 'highpass' | 'bandpass';
|
|
20
|
+
readonly frequency: number;
|
|
21
|
+
readonly to?: number;
|
|
22
|
+
readonly q?: number;
|
|
23
|
+
readonly gain: number;
|
|
24
|
+
readonly seconds: number;
|
|
25
|
+
}
|
|
26
|
+
interface FlybySound {
|
|
27
|
+
readonly supersonic: boolean;
|
|
28
|
+
readonly sample: 'bullet_crack_by' | 'bullet_whiz';
|
|
29
|
+
readonly voices: readonly FlybyVoice[];
|
|
30
|
+
}
|
|
31
|
+
declare function computeFlyby(input: FlybyInput): FlybySound | null;
|
|
32
|
+
|
|
33
|
+
type CasingSurface = 'hard' | 'wood' | 'metal' | 'soft';
|
|
34
|
+
type CasingKind = 'pistol' | 'rifle' | 'shell';
|
|
35
|
+
interface CasingInput {
|
|
36
|
+
readonly caseType?: CaseType | string;
|
|
37
|
+
/** Floor material id (`concrete`, `wood_hard`, `soil`...). */
|
|
38
|
+
readonly surface?: string;
|
|
39
|
+
/** Vertical speed at the hit, m/s (the louder the faster). Default 1.5. */
|
|
40
|
+
readonly speed?: number;
|
|
41
|
+
/** 0 for the first hit, then 1, 2...: each bounce is softer and a little higher. */
|
|
42
|
+
readonly bounce?: number;
|
|
43
|
+
/** Pitch factor around 1 (the adapter draws ±6 %: no two cases ring the same). */
|
|
44
|
+
readonly pitch?: number;
|
|
45
|
+
}
|
|
46
|
+
interface CasingVoice {
|
|
47
|
+
readonly kind: 'tone' | 'noise';
|
|
48
|
+
readonly filter?: 'lowpass' | 'highpass' | 'bandpass';
|
|
49
|
+
readonly frequency: number;
|
|
50
|
+
readonly to?: number;
|
|
51
|
+
readonly q?: number;
|
|
52
|
+
readonly gain: number;
|
|
53
|
+
readonly seconds: number;
|
|
54
|
+
}
|
|
55
|
+
interface CasingSound {
|
|
56
|
+
readonly surface: CasingSurface;
|
|
57
|
+
readonly kind: CasingKind;
|
|
58
|
+
readonly sample: string;
|
|
59
|
+
readonly voices: readonly CasingVoice[];
|
|
60
|
+
}
|
|
61
|
+
declare function computeCasingSound(input: CasingInput): CasingSound;
|
|
62
|
+
|
|
63
|
+
var profiles$1 = {
|
|
64
|
+
pistol_22lr: {
|
|
65
|
+
referenceJ: 160,
|
|
66
|
+
far: "pistol",
|
|
67
|
+
crack: {
|
|
68
|
+
frequency: 5200,
|
|
69
|
+
gain: 0.4,
|
|
70
|
+
seconds: 0.006
|
|
71
|
+
},
|
|
72
|
+
blast: {
|
|
73
|
+
cutoff: 3400,
|
|
74
|
+
gain: 0.517,
|
|
75
|
+
seconds: 0.05
|
|
76
|
+
},
|
|
77
|
+
body: {
|
|
78
|
+
from: 200,
|
|
79
|
+
to: 90,
|
|
80
|
+
gain: 0.045,
|
|
81
|
+
seconds: 0.04
|
|
82
|
+
},
|
|
83
|
+
far_layer: {
|
|
84
|
+
cutoff: 1300,
|
|
85
|
+
gain: 0.22,
|
|
86
|
+
seconds: 0.12
|
|
87
|
+
},
|
|
88
|
+
tail_out: {
|
|
89
|
+
cutoff: 1500,
|
|
90
|
+
gain: 0.08,
|
|
91
|
+
seconds: 0.5
|
|
92
|
+
},
|
|
93
|
+
tail_in: {
|
|
94
|
+
cutoff: 2400,
|
|
95
|
+
gain: 0.24,
|
|
96
|
+
seconds: 0.25
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
pistol_9mm: {
|
|
100
|
+
referenceJ: 500,
|
|
101
|
+
far: "pistol",
|
|
102
|
+
crack: {
|
|
103
|
+
frequency: 4200,
|
|
104
|
+
gain: 0.55,
|
|
105
|
+
seconds: 0.008
|
|
106
|
+
},
|
|
107
|
+
blast: {
|
|
108
|
+
cutoff: 2500,
|
|
109
|
+
gain: 0.92,
|
|
110
|
+
seconds: 0.09
|
|
111
|
+
},
|
|
112
|
+
body: {
|
|
113
|
+
from: 160,
|
|
114
|
+
to: 55,
|
|
115
|
+
gain: 0.189,
|
|
116
|
+
seconds: 0.1
|
|
117
|
+
},
|
|
118
|
+
far_layer: {
|
|
119
|
+
cutoff: 950,
|
|
120
|
+
gain: 0.35,
|
|
121
|
+
seconds: 0.2
|
|
122
|
+
},
|
|
123
|
+
tail_out: {
|
|
124
|
+
cutoff: 1150,
|
|
125
|
+
gain: 0.2,
|
|
126
|
+
seconds: 0.9
|
|
127
|
+
},
|
|
128
|
+
tail_in: {
|
|
129
|
+
cutoff: 2200,
|
|
130
|
+
gain: 0.45,
|
|
131
|
+
seconds: 0.4
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
pistol_45: {
|
|
135
|
+
referenceJ: 480,
|
|
136
|
+
far: "pistol",
|
|
137
|
+
crack: {
|
|
138
|
+
frequency: 3400,
|
|
139
|
+
gain: 0.42,
|
|
140
|
+
seconds: 0.009
|
|
141
|
+
},
|
|
142
|
+
blast: {
|
|
143
|
+
cutoff: 1650,
|
|
144
|
+
gain: 0.977,
|
|
145
|
+
seconds: 0.12
|
|
146
|
+
},
|
|
147
|
+
body: {
|
|
148
|
+
from: 120,
|
|
149
|
+
to: 42,
|
|
150
|
+
gain: 0.279,
|
|
151
|
+
seconds: 0.15
|
|
152
|
+
},
|
|
153
|
+
far_layer: {
|
|
154
|
+
cutoff: 760,
|
|
155
|
+
gain: 0.4,
|
|
156
|
+
seconds: 0.25
|
|
157
|
+
},
|
|
158
|
+
tail_out: {
|
|
159
|
+
cutoff: 1000,
|
|
160
|
+
gain: 0.22,
|
|
161
|
+
seconds: 1
|
|
162
|
+
},
|
|
163
|
+
tail_in: {
|
|
164
|
+
cutoff: 1900,
|
|
165
|
+
gain: 0.48,
|
|
166
|
+
seconds: 0.45
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
revolver_38_357: {
|
|
170
|
+
referenceJ: 800,
|
|
171
|
+
far: "pistol",
|
|
172
|
+
crack: {
|
|
173
|
+
frequency: 4000,
|
|
174
|
+
gain: 0.6,
|
|
175
|
+
seconds: 0.009
|
|
176
|
+
},
|
|
177
|
+
blast: {
|
|
178
|
+
cutoff: 2000,
|
|
179
|
+
gain: 1.035,
|
|
180
|
+
seconds: 0.13
|
|
181
|
+
},
|
|
182
|
+
body: {
|
|
183
|
+
from: 135,
|
|
184
|
+
to: 45,
|
|
185
|
+
gain: 0.248,
|
|
186
|
+
seconds: 0.15
|
|
187
|
+
},
|
|
188
|
+
far_layer: {
|
|
189
|
+
cutoff: 820,
|
|
190
|
+
gain: 0.42,
|
|
191
|
+
seconds: 0.28
|
|
192
|
+
},
|
|
193
|
+
tail_out: {
|
|
194
|
+
cutoff: 1100,
|
|
195
|
+
gain: 0.28,
|
|
196
|
+
seconds: 1.4
|
|
197
|
+
},
|
|
198
|
+
tail_in: {
|
|
199
|
+
cutoff: 2000,
|
|
200
|
+
gain: 0.54,
|
|
201
|
+
seconds: 0.5
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
revolver_44_50ae: {
|
|
205
|
+
referenceJ: 1800,
|
|
206
|
+
far: "pistol",
|
|
207
|
+
crack: {
|
|
208
|
+
frequency: 3100,
|
|
209
|
+
gain: 0.62,
|
|
210
|
+
seconds: 0.012
|
|
211
|
+
},
|
|
212
|
+
blast: {
|
|
213
|
+
cutoff: 1350,
|
|
214
|
+
gain: 1.15,
|
|
215
|
+
seconds: 0.18
|
|
216
|
+
},
|
|
217
|
+
body: {
|
|
218
|
+
from: 100,
|
|
219
|
+
to: 36,
|
|
220
|
+
gain: 0.369,
|
|
221
|
+
seconds: 0.21
|
|
222
|
+
},
|
|
223
|
+
far_layer: {
|
|
224
|
+
cutoff: 650,
|
|
225
|
+
gain: 0.5,
|
|
226
|
+
seconds: 0.33
|
|
227
|
+
},
|
|
228
|
+
tail_out: {
|
|
229
|
+
cutoff: 900,
|
|
230
|
+
gain: 0.34,
|
|
231
|
+
seconds: 1.7
|
|
232
|
+
},
|
|
233
|
+
tail_in: {
|
|
234
|
+
cutoff: 1700,
|
|
235
|
+
gain: 0.6,
|
|
236
|
+
seconds: 0.6
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
shotgun_12: {
|
|
240
|
+
referenceJ: 2700,
|
|
241
|
+
far: "shotgun",
|
|
242
|
+
crack: {
|
|
243
|
+
frequency: 2600,
|
|
244
|
+
gain: 0.36,
|
|
245
|
+
seconds: 0.012
|
|
246
|
+
},
|
|
247
|
+
blast: {
|
|
248
|
+
cutoff: 900,
|
|
249
|
+
gain: 1.15,
|
|
250
|
+
seconds: 0.26
|
|
251
|
+
},
|
|
252
|
+
body: {
|
|
253
|
+
from: 90,
|
|
254
|
+
to: 32,
|
|
255
|
+
gain: 0.405,
|
|
256
|
+
seconds: 0.3
|
|
257
|
+
},
|
|
258
|
+
far_layer: {
|
|
259
|
+
cutoff: 540,
|
|
260
|
+
gain: 0.55,
|
|
261
|
+
seconds: 0.42
|
|
262
|
+
},
|
|
263
|
+
tail_out: {
|
|
264
|
+
cutoff: 800,
|
|
265
|
+
gain: 0.38,
|
|
266
|
+
seconds: 1.9
|
|
267
|
+
},
|
|
268
|
+
tail_in: {
|
|
269
|
+
cutoff: 1500,
|
|
270
|
+
gain: 0.63,
|
|
271
|
+
seconds: 0.7
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
rifle_5_56: {
|
|
275
|
+
referenceJ: 1750,
|
|
276
|
+
far: "rifle",
|
|
277
|
+
crack: {
|
|
278
|
+
frequency: 5400,
|
|
279
|
+
gain: 0.78,
|
|
280
|
+
seconds: 0.007
|
|
281
|
+
},
|
|
282
|
+
blast: {
|
|
283
|
+
cutoff: 2700,
|
|
284
|
+
gain: 0.977,
|
|
285
|
+
seconds: 0.11
|
|
286
|
+
},
|
|
287
|
+
body: {
|
|
288
|
+
from: 145,
|
|
289
|
+
to: 50,
|
|
290
|
+
gain: 0.216,
|
|
291
|
+
seconds: 0.12
|
|
292
|
+
},
|
|
293
|
+
far_layer: {
|
|
294
|
+
cutoff: 900,
|
|
295
|
+
gain: 0.5,
|
|
296
|
+
seconds: 0.36
|
|
297
|
+
},
|
|
298
|
+
tail_out: {
|
|
299
|
+
cutoff: 1300,
|
|
300
|
+
gain: 0.4,
|
|
301
|
+
seconds: 2.1
|
|
302
|
+
},
|
|
303
|
+
tail_in: {
|
|
304
|
+
cutoff: 2300,
|
|
305
|
+
gain: 0.57,
|
|
306
|
+
seconds: 0.55
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
rifle_7_62x39: {
|
|
310
|
+
referenceJ: 2100,
|
|
311
|
+
far: "rifle",
|
|
312
|
+
crack: {
|
|
313
|
+
frequency: 4300,
|
|
314
|
+
gain: 0.72,
|
|
315
|
+
seconds: 0.01
|
|
316
|
+
},
|
|
317
|
+
blast: {
|
|
318
|
+
cutoff: 1850,
|
|
319
|
+
gain: 1.092,
|
|
320
|
+
seconds: 0.15
|
|
321
|
+
},
|
|
322
|
+
body: {
|
|
323
|
+
from: 115,
|
|
324
|
+
to: 40,
|
|
325
|
+
gain: 0.297,
|
|
326
|
+
seconds: 0.17
|
|
327
|
+
},
|
|
328
|
+
far_layer: {
|
|
329
|
+
cutoff: 780,
|
|
330
|
+
gain: 0.52,
|
|
331
|
+
seconds: 0.38
|
|
332
|
+
},
|
|
333
|
+
tail_out: {
|
|
334
|
+
cutoff: 1100,
|
|
335
|
+
gain: 0.42,
|
|
336
|
+
seconds: 2.2
|
|
337
|
+
},
|
|
338
|
+
tail_in: {
|
|
339
|
+
cutoff: 2000,
|
|
340
|
+
gain: 0.6,
|
|
341
|
+
seconds: 0.6
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
rifle_308_3006: {
|
|
345
|
+
referenceJ: 3500,
|
|
346
|
+
far: "rifle",
|
|
347
|
+
crack: {
|
|
348
|
+
frequency: 4500,
|
|
349
|
+
gain: 0.8,
|
|
350
|
+
seconds: 0.01
|
|
351
|
+
},
|
|
352
|
+
blast: {
|
|
353
|
+
cutoff: 1500,
|
|
354
|
+
gain: 1.15,
|
|
355
|
+
seconds: 0.19
|
|
356
|
+
},
|
|
357
|
+
body: {
|
|
358
|
+
from: 100,
|
|
359
|
+
to: 36,
|
|
360
|
+
gain: 0.36,
|
|
361
|
+
seconds: 0.21
|
|
362
|
+
},
|
|
363
|
+
far_layer: {
|
|
364
|
+
cutoff: 650,
|
|
365
|
+
gain: 0.6,
|
|
366
|
+
seconds: 0.46
|
|
367
|
+
},
|
|
368
|
+
tail_out: {
|
|
369
|
+
cutoff: 950,
|
|
370
|
+
gain: 0.5,
|
|
371
|
+
seconds: 2.7
|
|
372
|
+
},
|
|
373
|
+
tail_in: {
|
|
374
|
+
cutoff: 1800,
|
|
375
|
+
gain: 0.675,
|
|
376
|
+
seconds: 0.7
|
|
377
|
+
}
|
|
378
|
+
},
|
|
379
|
+
sniper_338_300wm: {
|
|
380
|
+
referenceJ: 6600,
|
|
381
|
+
far: "heavy",
|
|
382
|
+
crack: {
|
|
383
|
+
frequency: 4200,
|
|
384
|
+
gain: 0.86,
|
|
385
|
+
seconds: 0.012
|
|
386
|
+
},
|
|
387
|
+
blast: {
|
|
388
|
+
cutoff: 1250,
|
|
389
|
+
gain: 1.208,
|
|
390
|
+
seconds: 0.23
|
|
391
|
+
},
|
|
392
|
+
body: {
|
|
393
|
+
from: 85,
|
|
394
|
+
to: 32,
|
|
395
|
+
gain: 0.414,
|
|
396
|
+
seconds: 0.26
|
|
397
|
+
},
|
|
398
|
+
far_layer: {
|
|
399
|
+
cutoff: 580,
|
|
400
|
+
gain: 0.65,
|
|
401
|
+
seconds: 0.52
|
|
402
|
+
},
|
|
403
|
+
tail_out: {
|
|
404
|
+
cutoff: 850,
|
|
405
|
+
gain: 0.56,
|
|
406
|
+
seconds: 3.1
|
|
407
|
+
},
|
|
408
|
+
tail_in: {
|
|
409
|
+
cutoff: 1650,
|
|
410
|
+
gain: 0.72,
|
|
411
|
+
seconds: 0.8
|
|
412
|
+
}
|
|
413
|
+
},
|
|
414
|
+
antimateriel_50bmg: {
|
|
415
|
+
referenceJ: 18000,
|
|
416
|
+
far: "heavy",
|
|
417
|
+
crack: {
|
|
418
|
+
frequency: 3500,
|
|
419
|
+
gain: 0.9,
|
|
420
|
+
seconds: 0.015
|
|
421
|
+
},
|
|
422
|
+
blast: {
|
|
423
|
+
cutoff: 900,
|
|
424
|
+
gain: 1.265,
|
|
425
|
+
seconds: 0.3
|
|
426
|
+
},
|
|
427
|
+
body: {
|
|
428
|
+
from: 62,
|
|
429
|
+
to: 25,
|
|
430
|
+
gain: 0.495,
|
|
431
|
+
seconds: 0.36
|
|
432
|
+
},
|
|
433
|
+
far_layer: {
|
|
434
|
+
cutoff: 450,
|
|
435
|
+
gain: 0.7,
|
|
436
|
+
seconds: 0.62
|
|
437
|
+
},
|
|
438
|
+
tail_out: {
|
|
439
|
+
cutoff: 700,
|
|
440
|
+
gain: 0.6,
|
|
441
|
+
seconds: 3.6
|
|
442
|
+
},
|
|
443
|
+
tail_in: {
|
|
444
|
+
cutoff: 1400,
|
|
445
|
+
gain: 0.75,
|
|
446
|
+
seconds: 0.9
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
var data$1 = {
|
|
451
|
+
profiles: profiles$1};
|
|
452
|
+
|
|
453
|
+
type GunshotProfileId = keyof typeof data$1.profiles;
|
|
454
|
+
type GunshotFarClass = 'pistol' | 'rifle' | 'shotgun' | 'heavy';
|
|
455
|
+
type Noise = {
|
|
456
|
+
readonly cutoff: number;
|
|
457
|
+
readonly gain: number;
|
|
458
|
+
readonly seconds: number;
|
|
459
|
+
};
|
|
460
|
+
interface GunshotProfile {
|
|
461
|
+
/** Muzzle energy (J) the numbers are written for: a lighter or heavier calibre of the family is scaled from it. */
|
|
462
|
+
readonly referenceJ: number;
|
|
463
|
+
readonly far: GunshotFarClass;
|
|
464
|
+
/** Supersonic N-wave or muzzle snap: highpass noise. */
|
|
465
|
+
readonly crack: {
|
|
466
|
+
readonly frequency: number;
|
|
467
|
+
readonly gain: number;
|
|
468
|
+
readonly seconds: number;
|
|
469
|
+
};
|
|
470
|
+
/** The mid "slap" of the muzzle blast: lowpass noise. */
|
|
471
|
+
readonly blast: Noise;
|
|
472
|
+
/** The low thump: a sine sweeping `from` → `to`. */
|
|
473
|
+
readonly body: {
|
|
474
|
+
readonly from: number;
|
|
475
|
+
readonly to: number;
|
|
476
|
+
readonly gain: number;
|
|
477
|
+
readonly seconds: number;
|
|
478
|
+
};
|
|
479
|
+
readonly far_layer: Noise;
|
|
480
|
+
readonly tail_out: Noise;
|
|
481
|
+
readonly tail_in: Noise;
|
|
482
|
+
}
|
|
483
|
+
declare const GUNSHOT_PROFILES: Readonly<Record<GunshotProfileId, GunshotProfile>>;
|
|
484
|
+
type GunshotSpace = 'outdoor' | 'indoor';
|
|
485
|
+
type GunshotGroup = 'close' | 'mech' | 'tail' | 'far';
|
|
486
|
+
interface GunshotInput {
|
|
487
|
+
readonly caliber?: CaliberDef;
|
|
488
|
+
/** Muzzle energy (J), for a shot with no calibre; the calibre's energy (× pellets) otherwise. */
|
|
489
|
+
readonly energyJ?: number;
|
|
490
|
+
readonly category?: string;
|
|
491
|
+
/** Metres from the listener, default 0 (the player's own weapon). */
|
|
492
|
+
readonly distance?: number;
|
|
493
|
+
readonly suppressed?: boolean;
|
|
494
|
+
readonly space?: GunshotSpace;
|
|
495
|
+
/** 0..n−1: which take (`pickTake` gives one that is not the last). */
|
|
496
|
+
readonly take?: number;
|
|
497
|
+
/** Pitch factor of this shot, around 1 (the adapter draws ±4 %). */
|
|
498
|
+
readonly pitch?: number;
|
|
499
|
+
/** Master level, default 1. */
|
|
500
|
+
readonly volume?: number;
|
|
501
|
+
/** 0..1, a wall between the shot and the listener: −6 dB and the lowpass cutoffs at 40 % when fully behind it (as game-audio's occlusion). */
|
|
502
|
+
readonly occlusion?: number;
|
|
503
|
+
}
|
|
504
|
+
interface GunshotOptions {
|
|
505
|
+
/** Replaces or adds profiles. */
|
|
506
|
+
readonly profiles?: Readonly<Partial<Record<string, GunshotProfile>>>;
|
|
507
|
+
/** Replaces or adds calibre → profile links. */
|
|
508
|
+
readonly calibers?: Readonly<Record<string, string>>;
|
|
509
|
+
/** Level law `(reference / d)^exponent` beyond `reference` metres (default 4 m, 0.8: a little gentler than the 6 dB per doubling of the free field, as games do). */
|
|
510
|
+
readonly reference?: number;
|
|
511
|
+
readonly exponent?: number;
|
|
512
|
+
/** Below this the shot is not played (default 0.004, −48 dB). */
|
|
513
|
+
readonly minGain?: number;
|
|
514
|
+
/** The close sound fades to the far one between these distances, metres (default 25 and 80). */
|
|
515
|
+
readonly farFrom?: number;
|
|
516
|
+
readonly farTo?: number;
|
|
517
|
+
}
|
|
518
|
+
interface GunshotVoice {
|
|
519
|
+
readonly group: GunshotGroup;
|
|
520
|
+
/** Which part of the group: `crack`, `blast`, `body`, `action`, `tail`, `echo`, `reflection`, `boom`. */
|
|
521
|
+
readonly part: string;
|
|
522
|
+
/** Seconds after the trigger (the arrival delay included). */
|
|
523
|
+
readonly at: number;
|
|
524
|
+
readonly kind: 'noise' | 'tone';
|
|
525
|
+
readonly filter?: 'lowpass' | 'highpass' | 'bandpass';
|
|
526
|
+
/** Filter frequency (noise) or start frequency (tone). */
|
|
527
|
+
readonly frequency: number;
|
|
528
|
+
/** Tone end frequency. */
|
|
529
|
+
readonly to?: number;
|
|
530
|
+
readonly q?: number;
|
|
531
|
+
readonly gain: number;
|
|
532
|
+
readonly seconds: number;
|
|
533
|
+
/** Send to the reverb (a room). */
|
|
534
|
+
readonly wet?: number;
|
|
535
|
+
}
|
|
536
|
+
interface Gunshot {
|
|
537
|
+
readonly profile: string;
|
|
538
|
+
readonly energyJ: number;
|
|
539
|
+
readonly supersonic: boolean;
|
|
540
|
+
readonly take: number;
|
|
541
|
+
readonly pitch: number;
|
|
542
|
+
/** Distance / speed of sound. */
|
|
543
|
+
readonly delay: number;
|
|
544
|
+
/** 1 = all close, 0 = all far. */
|
|
545
|
+
readonly closeMix: number;
|
|
546
|
+
readonly audible: boolean;
|
|
547
|
+
/** The sample ids each group can be replaced by (checklist 5.1). */
|
|
548
|
+
readonly samples: Readonly<Record<GunshotGroup, string>>;
|
|
549
|
+
readonly voices: readonly GunshotVoice[];
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* The voices of one gunshot. Distance: every layer arrives `d / 343` s late; the level falls as `(reference / d)^exponent`, the highs go first (the
|
|
553
|
+
* crack fades over ~60 m, lowpass cutoffs fall with `1 + d / 250`) and the close sound fades into the far boom between `farFrom` and `farTo`. Space:
|
|
554
|
+
* outdoors the field answers with two late echoes and a long low tail; indoors the room answers at once (early reflections and a dense, short tail
|
|
555
|
+
* sent to the reverb). A suppressor takes the blast and the body down and leaves the action and a supersonic crack.
|
|
556
|
+
*/
|
|
557
|
+
declare function computeGunshot(input: GunshotInput, options?: GunshotOptions): Gunshot;
|
|
558
|
+
|
|
559
|
+
/** One sound of the game: [lowpass cutoff Hz, gain, seconds]. Literal from the `P` table of `sfx` in the game (jogo.js L62101-L62104). */
|
|
560
|
+
type SoundClassDef = readonly [cutoff: number, gain: number, seconds: number];
|
|
561
|
+
/** The game names are pistola, escopeta, fuzil, rifle, impacto, carne, passo, vidro, madeira, recarga, vazio and explosao. */
|
|
562
|
+
declare const GAME_SOUND_CLASSES: {
|
|
563
|
+
readonly pistol: readonly [1800, 0.9, 0.18];
|
|
564
|
+
readonly shotgun: readonly [900, 1.2, 0.35];
|
|
565
|
+
readonly rifle: readonly [1400, 1.1, 0.28];
|
|
566
|
+
readonly long_rifle: readonly [1100, 1.3, 0.45];
|
|
567
|
+
readonly impact: readonly [2500, 0.25, 0.05];
|
|
568
|
+
readonly flesh: readonly [600, 0.35, 0.08];
|
|
569
|
+
readonly step: readonly [400, 0.08, 0.05];
|
|
570
|
+
readonly glass: readonly [5000, 0.5, 0.3];
|
|
571
|
+
readonly wood: readonly [700, 0.5, 0.2];
|
|
572
|
+
readonly reload: readonly [3000, 0.15, 0.06];
|
|
573
|
+
readonly empty: readonly [4000, 0.12, 0.03];
|
|
574
|
+
readonly explosion: readonly [200, 1.6, 1.4];
|
|
575
|
+
};
|
|
576
|
+
/** The four classes a shot can have: the game picks one by calibre (jogo.js L68697). */
|
|
577
|
+
type ShotSoundClass = 'pistol' | 'shotgun' | 'rifle' | 'long_rifle';
|
|
578
|
+
/** Distance muffling of the game (jogo.js L62092, L62105): `gain / (1 + d² × gainFalloff)`, `cutoff / (1 + d × cutoffFalloff)`, silent under `minGain`. */
|
|
579
|
+
type DistanceCurve = {
|
|
580
|
+
readonly gainFalloff: number;
|
|
581
|
+
readonly cutoffFalloff: number;
|
|
582
|
+
readonly minGain: number;
|
|
583
|
+
};
|
|
584
|
+
declare const GAME_DISTANCE_CURVE: DistanceCurve;
|
|
585
|
+
/**
|
|
586
|
+
* The calibre energy (joules) scales loudness, length and brightness around the class: each factor is `base + span × k`, where k goes from 0 (50 J)
|
|
587
|
+
* to 1 (50 J × 10^spanDecades) on a log scale, divided by the same factor at the class reference energy. So the game calibres sound exactly as in
|
|
588
|
+
* the game, and a lighter or heavier calibre of the same class is quieter and brighter, or louder and duller.
|
|
589
|
+
*/
|
|
590
|
+
type EnergyCurve = {
|
|
591
|
+
readonly floorJ: number;
|
|
592
|
+
readonly spanDecades: number;
|
|
593
|
+
readonly gain: readonly [base: number, span: number];
|
|
594
|
+
readonly duration: readonly [base: number, span: number];
|
|
595
|
+
readonly cutoff: readonly [base: number, span: number];
|
|
596
|
+
/** The muzzle crack (high noise) and the body (low thump) follow the energy alone. */
|
|
597
|
+
readonly crackGain: readonly [base: number, span: number];
|
|
598
|
+
readonly bodyGain: readonly [base: number, span: number];
|
|
599
|
+
readonly bodyDuration: readonly [base: number, span: number];
|
|
600
|
+
readonly bodyFrequency: readonly [base: number, span: number];
|
|
601
|
+
};
|
|
602
|
+
declare const DEFAULT_ENERGY_CURVE: EnergyCurve;
|
|
603
|
+
/** Muzzle energy of the game calibres in the SDK (9x19, 12ga_00buck × pellets, 7_62x39, 7_62x51): where a class sounds exactly as in the game. */
|
|
604
|
+
declare const CLASS_REFERENCE_ENERGY: Readonly<Record<ShotSoundClass, number>>;
|
|
605
|
+
type ShotSoundOptions = {
|
|
606
|
+
/** Replaces or adds sound classes (the game table is the default). */
|
|
607
|
+
readonly classes?: Readonly<Record<string, SoundClassDef>>;
|
|
608
|
+
readonly distance?: Partial<DistanceCurve>;
|
|
609
|
+
readonly energy?: Partial<EnergyCurve>;
|
|
610
|
+
readonly referenceEnergy?: Partial<Record<ShotSoundClass, number>>;
|
|
611
|
+
/** Picks the class of a shot; the default follows the game (shotgun by shell, handguns by category, then by energy). */
|
|
612
|
+
readonly classOf?: (input: ShotSoundInput, energyJ: number) => ShotSoundClass;
|
|
613
|
+
/** Class bands by energy (J): below `handgunBelowJ` a pistol, below `rifleBelowJ` a rifle, above that a long rifle. */
|
|
614
|
+
readonly bands?: {
|
|
615
|
+
readonly handgunBelowJ: number;
|
|
616
|
+
readonly rifleBelowJ: number;
|
|
617
|
+
};
|
|
618
|
+
readonly suppressor?: {
|
|
619
|
+
readonly gain: number;
|
|
620
|
+
readonly cutoff: number;
|
|
621
|
+
readonly crack: number;
|
|
622
|
+
readonly body: number;
|
|
623
|
+
};
|
|
624
|
+
readonly indoors?: {
|
|
625
|
+
readonly duration: number;
|
|
626
|
+
readonly cutoff: number;
|
|
627
|
+
};
|
|
628
|
+
};
|
|
629
|
+
type ShotSoundInput = {
|
|
630
|
+
/** The calibre; its energy (× pellets) is used unless `energyJ` is given. */
|
|
631
|
+
readonly caliber?: CaliberDef;
|
|
632
|
+
readonly energyJ?: number;
|
|
633
|
+
readonly category?: string;
|
|
634
|
+
/** Metres from the listener, default 0. */
|
|
635
|
+
readonly distance?: number;
|
|
636
|
+
/** Master gain of the game `sfx` (its `vol`), default 1. */
|
|
637
|
+
readonly volume?: number;
|
|
638
|
+
readonly suppressed?: boolean;
|
|
639
|
+
readonly indoors?: boolean;
|
|
640
|
+
};
|
|
641
|
+
type ShotSound = {
|
|
642
|
+
readonly soundClass: ShotSoundClass;
|
|
643
|
+
readonly energyJ: number;
|
|
644
|
+
/** False when the shot is under the game's `minGain` at this distance: nothing is played. */
|
|
645
|
+
readonly audible: boolean;
|
|
646
|
+
/** The main noise burst: lowpass cutoff Hz, starting gain and the seconds of the exponential tail (to 0.001). */
|
|
647
|
+
readonly cutoff: number;
|
|
648
|
+
readonly gain: number;
|
|
649
|
+
readonly duration: number;
|
|
650
|
+
/** High noise burst of the muzzle. */
|
|
651
|
+
readonly crack: {
|
|
652
|
+
readonly gain: number;
|
|
653
|
+
readonly cutoff: number;
|
|
654
|
+
readonly duration: number;
|
|
655
|
+
};
|
|
656
|
+
/** Low thump that sweeps from `frequency` to `to`. */
|
|
657
|
+
readonly body: {
|
|
658
|
+
readonly gain: number;
|
|
659
|
+
readonly frequency: number;
|
|
660
|
+
readonly to: number;
|
|
661
|
+
readonly duration: number;
|
|
662
|
+
};
|
|
663
|
+
};
|
|
664
|
+
/**
|
|
665
|
+
* The parameters of a gunshot, without WebAudio: the sound class and the distance muffling of the game (S2) with the calibre energy of the SDK.
|
|
666
|
+
* Pure and deterministic; the playback layer only turns it into nodes.
|
|
667
|
+
*/
|
|
668
|
+
declare const computeShotSound: (input: ShotSoundInput, options?: ShotSoundOptions) => ShotSound;
|
|
669
|
+
|
|
670
|
+
/** One layer of a mechanical sound; `at` is seconds after the start. */
|
|
671
|
+
type SoundStep =
|
|
672
|
+
/** Metal click: a short high noise plus a square tone at 0.6 × the frequency (the SDK synth, as before). */
|
|
673
|
+
{
|
|
674
|
+
readonly layer: 'metal';
|
|
675
|
+
readonly at: number;
|
|
676
|
+
readonly frequency: number;
|
|
677
|
+
readonly gain: number;
|
|
678
|
+
}
|
|
679
|
+
/** A sound class of the game (`recarga`, `vazio`...) played at a volume. */
|
|
680
|
+
| {
|
|
681
|
+
readonly layer: 'class';
|
|
682
|
+
readonly at: number;
|
|
683
|
+
readonly soundClass: keyof typeof GAME_SOUND_CLASSES;
|
|
684
|
+
readonly volume: number;
|
|
685
|
+
}
|
|
686
|
+
/** Dull landing: lowpass noise. */
|
|
687
|
+
| {
|
|
688
|
+
readonly layer: 'thud';
|
|
689
|
+
readonly at: number;
|
|
690
|
+
readonly gain: number;
|
|
691
|
+
readonly frequency: number;
|
|
692
|
+
}
|
|
693
|
+
/** The art scene's `sTone` (cena L1324): a tone sliding from `f` to `f2` (default `f`) in `d` seconds, at `vol`, `at` seconds after the start. */
|
|
694
|
+
| {
|
|
695
|
+
readonly layer: 'scene_tone';
|
|
696
|
+
readonly at: number;
|
|
697
|
+
readonly wave: 'sine' | 'square';
|
|
698
|
+
readonly f: number;
|
|
699
|
+
readonly f2?: number;
|
|
700
|
+
readonly d: number;
|
|
701
|
+
readonly vol: number;
|
|
702
|
+
}
|
|
703
|
+
/** The art scene's `sNoise` (cena L1323): filtered noise, the filter sliding to `f2` when given, `d` seconds, at `vol`. */
|
|
704
|
+
| {
|
|
705
|
+
readonly layer: 'scene_noise';
|
|
706
|
+
readonly at: number;
|
|
707
|
+
readonly type: 'lowpass' | 'highpass' | 'bandpass';
|
|
708
|
+
readonly f: number;
|
|
709
|
+
readonly f2?: number;
|
|
710
|
+
readonly q: number;
|
|
711
|
+
readonly d: number;
|
|
712
|
+
readonly vol: number;
|
|
713
|
+
};
|
|
714
|
+
type MechanicalSoundId = ReloadStageId | 'dry_fire' | 'misfire' | 'feed' | 'cycle' | 'mode' | 'safety_on' | 'safety_off' | 'jam' | 'clear_start' | 'clear_end' | 'stock_fold' | 'light_click' | 'attach';
|
|
715
|
+
/**
|
|
716
|
+
* Sounds keyed by the rule: the `reload_stage` ids of `RELOAD_STAGES`, plus the other weapon events. The click of an empty weapon and the generic
|
|
717
|
+
* reload tick are the game's `vazio` and `recarga` classes (jogo.js L62101-L62104; played at L68644-L68662). The Cena de Arte delivered the reload sounds
|
|
718
|
+
* (`empty` -> dry_fire, `magOut` -> magazine_out, `magIn` -> magazine_in, `bolt` -> charge, `shell` -> round_in; cena L1339-L1343), so those use them; the gallery
|
|
719
|
+
* (sources/armas-itens__galeria-3d-arsenal.js) has no sound, and the other metal layers are the SDK synth (the same `metal` used since the first version).
|
|
720
|
+
*/
|
|
721
|
+
declare const MECHANICAL_SOUNDS: Readonly<Record<MechanicalSoundId, readonly SoundStep[]>>;
|
|
722
|
+
/** Which mechanical sound a weapon event asks for, if any (`shot`, `draw` and `reload` start/end have their own handling). */
|
|
723
|
+
declare const mechanicalSoundOf: (event: WeaponEvent) => MechanicalSoundId | undefined;
|
|
724
|
+
|
|
725
|
+
var profiles = {
|
|
726
|
+
weight: {
|
|
727
|
+
light: {
|
|
728
|
+
pitch: 1.3,
|
|
729
|
+
gain: 0.85
|
|
730
|
+
},
|
|
731
|
+
medium: {
|
|
732
|
+
pitch: 1,
|
|
733
|
+
gain: 1
|
|
734
|
+
},
|
|
735
|
+
heavy: {
|
|
736
|
+
pitch: 0.78,
|
|
737
|
+
gain: 1.2
|
|
738
|
+
}
|
|
739
|
+
},
|
|
740
|
+
material: {
|
|
741
|
+
steel: {
|
|
742
|
+
pitch: 1,
|
|
743
|
+
gain: 1
|
|
744
|
+
},
|
|
745
|
+
polymer: {
|
|
746
|
+
pitch: 0.82,
|
|
747
|
+
gain: 0.8
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
};
|
|
751
|
+
var data = {
|
|
752
|
+
profiles: profiles};
|
|
753
|
+
|
|
754
|
+
/** How a weapon sounds: the weight of its metal (pitch and level) and what it is made of. */
|
|
755
|
+
interface SoundProfile {
|
|
756
|
+
readonly weight: keyof typeof data.profiles.weight;
|
|
757
|
+
readonly material: keyof typeof data.profiles.material;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/** Where the recorded files are: the manifest the converter wrote and how a file of it becomes a url. */
|
|
761
|
+
interface WeaponSampleOptions {
|
|
762
|
+
readonly manifest: SfxManifest;
|
|
763
|
+
/** Prefix of every file (`/sfx/`), when `url` is not given. Default ''. */
|
|
764
|
+
readonly baseUrl?: string;
|
|
765
|
+
/** The url of a file of the manifest (`armas/pistol_9mm_close_01.ogg`): a served path or a `data:` url of the inlined bytes. */
|
|
766
|
+
readonly url?: (file: string) => string;
|
|
767
|
+
/** Replaces the numbers of a sound by id (gain, crossover, falloff...). */
|
|
768
|
+
readonly sounds?: Readonly<Record<string, Partial<SampleDefaults>>>;
|
|
769
|
+
}
|
|
770
|
+
/** The shot sounds: the calibre profiles and the suppressed ones. */
|
|
771
|
+
declare const GUNSHOT_SAMPLE_IDS: readonly string[];
|
|
772
|
+
/**
|
|
773
|
+
* A shot as recorded: the near take up to 20 m, the mid-distance one from 90 m, an equal-power crossfade between. The level falls gently (a
|
|
774
|
+
* gunshot carries: about −14 dB at 100 m, −36 dB at 800 m) and the highs go with the air (6.7 kHz at 50 m, 2.2 kHz at 200 m). Three plays ring at once at most, so a burst stays shot
|
|
775
|
+
* by shot.
|
|
776
|
+
*/
|
|
777
|
+
declare const GUNSHOT_SAMPLE: SampleDefaults;
|
|
778
|
+
/** A reload step: heard at the hands, about a third of a shot's level after the converter's peak normalization. */
|
|
779
|
+
declare const RELOAD_SAMPLE: SampleDefaults;
|
|
780
|
+
/** Seconds from the start of each recorded reload step to its hit (`data/reload-sample-hits.json`, measured on the files). */
|
|
781
|
+
declare const RELOAD_SAMPLE_HITS: Readonly<Record<string, number>>;
|
|
782
|
+
/** The tier a weapon's weight plays (`SFX_TIERS`: light from 0, medium from 0.34, heavy from 0.67). */
|
|
783
|
+
declare const WEIGHT_INTENSITY: Readonly<Record<SoundProfile['weight'], number>>;
|
|
784
|
+
/**
|
|
785
|
+
* Reload cues the recordings of another cue already carry: the magazine release button is the start of the "detach magazine" take, the slide of
|
|
786
|
+
* the magazine into the well the start of the "insert magazine" one. When that sample plays, these cues stay silent.
|
|
787
|
+
*/
|
|
788
|
+
declare const CUES_IN_SAMPLE: Readonly<Record<string, string>>;
|
|
789
|
+
/** The numbers of a sound of the manifest: a gunshot, a case landing or a reload step (`armas` only). */
|
|
790
|
+
declare function weaponSampleDefaults(sound: SfxManifestSound, overrides?: WeaponSampleOptions['sounds']): SampleDefaults | undefined;
|
|
791
|
+
/** The bank of the recorded weapon sounds, every url through `url` (or `baseUrl`). Gunshots choke at three voices. */
|
|
792
|
+
declare function weaponSampleBank(options: WeaponSampleOptions): SoundBank;
|
|
793
|
+
|
|
794
|
+
/** What a reload cue played: its recording, nothing (another cue's recording carries it), or the synthesized steps. */
|
|
795
|
+
type CuePlayed = 'sample' | 'carried' | 'synth';
|
|
796
|
+
/** What sounded for a shot: the recorded takes (`sample`, with the take of each layer) or the synthesized layers (`synth`). */
|
|
797
|
+
type GunshotPlayed = {
|
|
798
|
+
readonly kind: 'synth';
|
|
799
|
+
} | {
|
|
800
|
+
readonly kind: 'sample';
|
|
801
|
+
readonly id: string;
|
|
802
|
+
readonly layers: readonly {
|
|
803
|
+
readonly role: string;
|
|
804
|
+
readonly take: number;
|
|
805
|
+
readonly rate: number;
|
|
806
|
+
}[];
|
|
807
|
+
};
|
|
808
|
+
/** What a shot adds to the energy and the category: where the listener is and how the weapon is set. */
|
|
809
|
+
type ShotExtras = Pick<ShotSoundInput, 'caliber' | 'distance' | 'volume' | 'suppressed' | 'indoors'> & {
|
|
810
|
+
/** Where the shot is, for the stereo side (the engine's listener is the other end). Left out, the shot is in front (the player's own weapon). */
|
|
811
|
+
readonly position?: readonly [number, number, number];
|
|
812
|
+
/** 0..1, a wall between the shot and the listener (the host's occlusion test): quieter and duller. */
|
|
813
|
+
readonly occlusion?: number;
|
|
814
|
+
/** Open field or a room; `indoors: true` means `'indoor'`. Default outdoor. */
|
|
815
|
+
readonly space?: GunshotSpace;
|
|
816
|
+
};
|
|
817
|
+
/** `gunshot` (default): the layered shot of `computeGunshot`. `game`: the game's single class burst (`computeShotSound`), kept for the golden traces. */
|
|
818
|
+
type ShotModel = 'gunshot' | 'game';
|
|
819
|
+
interface WeaponAudioOptions extends ShotSoundOptions {
|
|
820
|
+
/** How a shot is built; default `gunshot`. */
|
|
821
|
+
readonly shotModel?: ShotModel;
|
|
822
|
+
/** Tunes the layered gunshot (profiles, calibre links, distance law). */
|
|
823
|
+
readonly gunshot?: GunshotOptions;
|
|
824
|
+
/** Pitch spread of a shot, ± this fraction (default 0.04, C5). */
|
|
825
|
+
readonly pitchSpread?: number;
|
|
826
|
+
/** Told each gunshot played (profile, take, pitch, space, distance), so a host can log what sounded. */
|
|
827
|
+
readonly onGunshot?: (shot: Gunshot, input: GunshotInput, played: GunshotPlayed) => void;
|
|
828
|
+
/** Told each case that lands (floor, case type, sample id). */
|
|
829
|
+
readonly onCasing?: (sound: CasingSound, played: 'sample' | 'synth') => void;
|
|
830
|
+
/** Seed of the noise buffer, of the start point in it and of the casing pitch: same seed, same sound. Default 1. */
|
|
831
|
+
readonly seed?: number;
|
|
832
|
+
/** Replaces or adds mechanical sounds by id. */
|
|
833
|
+
readonly mechanical?: Readonly<Partial<Record<MechanicalSoundId, readonly SoundStep[]>>>;
|
|
834
|
+
/** Replaces or adds the sounds of the reload clip cues by id (`reload-sounds.json` has the ones the kit ships). */
|
|
835
|
+
readonly reloadCues?: Readonly<Record<string, readonly SoundStep[]>>;
|
|
836
|
+
/** Where the AudioContext comes from (default: the global one); lets a host or a test lend its own. Not used with `engine`. */
|
|
837
|
+
readonly createContext?: () => AudioContext;
|
|
838
|
+
/**
|
|
839
|
+
* A sound engine the host already has (one shared engine mixes, limits and pans every module the same way). The weapon sounds are registered in it
|
|
840
|
+
* and play on its `weapons` bus; `seed` gives them their own random stream, the master volume and the context stay the engine's. Without it the
|
|
841
|
+
* weapon audio makes its own engine with the game mix, no voice limit, and the master at `volume`.
|
|
842
|
+
*/
|
|
843
|
+
readonly engine?: AudioEngine;
|
|
844
|
+
/**
|
|
845
|
+
* The recorded shots and reload steps (game-audio's `assets/sfx/manifest.json` and where its files are served). A shot of a profile with files
|
|
846
|
+
* plays its takes, a reload cue the takes of the weapon's weight; until they are loaded, and for anything without files, the synthesized sound.
|
|
847
|
+
*/
|
|
848
|
+
readonly samples?: WeaponSampleOptions;
|
|
849
|
+
}
|
|
850
|
+
/** Sounds the weapon presentation plays. */
|
|
851
|
+
interface WeaponAudio {
|
|
852
|
+
/** A shot: the layered gunshot of its calibre (close, action, room or field, far) at its distance, or the game's class burst with `shotModel: 'game'`. */
|
|
853
|
+
shot(energyJ: number, category: string, extras?: ShotExtras): void;
|
|
854
|
+
/** The parameters `shot` would play with the `game` model (pure). */
|
|
855
|
+
shotSound(input: ShotSoundInput): ShotSound;
|
|
856
|
+
/** The voices `shot` plays with the `gunshot` model (pure; give `take` and `pitch` to fix them). */
|
|
857
|
+
gunshot(input: GunshotInput): Gunshot;
|
|
858
|
+
/** Dry click of an empty weapon. */
|
|
859
|
+
click(): void;
|
|
860
|
+
/** A mechanical sound by id: a reload stage, `dry_fire`, `jam`, `safety_on`... */
|
|
861
|
+
mechanical(id: MechanicalSoundId): void;
|
|
862
|
+
/**
|
|
863
|
+
* A cue of a reload clip (`mag_seat`, `charging_handle_pull`, `pump_back`...) for a weapon's profile (the weight of its metal and what it is made
|
|
864
|
+
* of), where the clip says. `lead` is how early the clip started it (seconds before the part reaches its stop): a recording plays at once, its hit
|
|
865
|
+
* that much later; the synthesized steps, whose hit is at their start, wait `lead`.
|
|
866
|
+
*/
|
|
867
|
+
cue(id: string, profile?: SoundProfile, lead?: number): CuePlayed;
|
|
868
|
+
/** Loads the recorded files now (they load on the first sound otherwise, and the synthesized sound plays meanwhile). */
|
|
869
|
+
loadSamples(): Promise<void>;
|
|
870
|
+
/** The mechanical sound of a weapon event, if it has one (reload stages, empty, misfire, fault, clear, safety, mode, feed). */
|
|
871
|
+
event(event: WeaponEvent): void;
|
|
872
|
+
/** A sound class of the game by name (`impact`, `flesh`, `glass`...), with the game's distance muffling. */
|
|
873
|
+
play(soundClass: string, volume?: number, distance?: number): void;
|
|
874
|
+
/** Magazine out, or the first shell in. */
|
|
875
|
+
reloadStart(category: string): void;
|
|
876
|
+
/** Magazine seated and the action racked. */
|
|
877
|
+
reloadEnd(category: string): void;
|
|
878
|
+
/** The pump or lever cycling after a shot. */
|
|
879
|
+
cycle(): void;
|
|
880
|
+
/** A casing bouncing on the floor (the art scene's single ring; with the `gunshot` model, a pistol case on concrete). */
|
|
881
|
+
clink(): void;
|
|
882
|
+
/** A case hitting the floor: its type (pistol, rifle, shell), the floor material, the speed and which bounce. */
|
|
883
|
+
casing(input: CasingInput): void;
|
|
884
|
+
/** A bullet passing the listener (shot by someone else): crack when supersonic, whiz when not; `position` is where it passes, for the side. */
|
|
885
|
+
flyby(input: FlybyInput & {
|
|
886
|
+
readonly position?: readonly [number, number, number];
|
|
887
|
+
}): void;
|
|
888
|
+
/** A magazine landing on the floor. */
|
|
889
|
+
thud(): void;
|
|
890
|
+
/** Master volume, 0 to 1. */
|
|
891
|
+
setVolume(volume: number): void;
|
|
892
|
+
dispose(): void;
|
|
893
|
+
}
|
|
894
|
+
declare function createWeaponAudio(volume?: number, options?: WeaponAudioOptions): WeaponAudio;
|
|
895
|
+
|
|
896
|
+
/** What the bench turns on or off in the presentation of the weapon: the ejected casings, the dropped magazines, the muzzle flash, the accessory models and the light and laser beams. */
|
|
897
|
+
interface FxLayers {
|
|
898
|
+
casings: boolean;
|
|
899
|
+
magazines: boolean;
|
|
900
|
+
muzzleFlash: boolean;
|
|
901
|
+
attachments: boolean;
|
|
902
|
+
beams: boolean;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/** How the gallery builders describe a weapon: the short keys of `data/models.json` (the page's own option names), all optional. */
|
|
906
|
+
interface ModelOptions {
|
|
907
|
+
/** Total length and barrel length in mm, and the calibre text, as the weapons table gives them. */
|
|
908
|
+
L?: number;
|
|
909
|
+
B?: number;
|
|
910
|
+
cal?: string;
|
|
911
|
+
/** Pistol style (`glock`, `taurus`, `g2c`, `beretta`, `pt100`, `sig`, `cz`, `m1911`, `makarov`, `fiveseven`, `deagle`), slide height, grip length. */
|
|
912
|
+
st?: string;
|
|
913
|
+
h?: number;
|
|
914
|
+
gl?: number;
|
|
915
|
+
deagle?: number;
|
|
916
|
+
/** Metal and furniture finish. */
|
|
917
|
+
steel?: number;
|
|
918
|
+
stain?: number;
|
|
919
|
+
wood?: number;
|
|
920
|
+
olive?: number;
|
|
921
|
+
tan?: number;
|
|
922
|
+
/** Selector or safety mark, cyclic rate (rpm), rounds in a burst, how unreliable (`rel`). */
|
|
923
|
+
sel?: number;
|
|
924
|
+
rpm?: number;
|
|
925
|
+
burst?: number;
|
|
926
|
+
rel?: number;
|
|
927
|
+
/** Rifle layout. */
|
|
928
|
+
stock?: string;
|
|
929
|
+
stockLen?: number;
|
|
930
|
+
hg?: string;
|
|
931
|
+
hgFrac?: number;
|
|
932
|
+
hR?: number;
|
|
933
|
+
wR?: number;
|
|
934
|
+
br?: number;
|
|
935
|
+
grip?: string;
|
|
936
|
+
gripAt?: number;
|
|
937
|
+
mag?: string;
|
|
938
|
+
magLen?: number;
|
|
939
|
+
magAt?: number;
|
|
940
|
+
magMat?: string;
|
|
941
|
+
curve?: number;
|
|
942
|
+
fore?: number;
|
|
943
|
+
tubeLen?: number;
|
|
944
|
+
scope?: number;
|
|
945
|
+
brake?: number;
|
|
946
|
+
ejectBack?: number;
|
|
947
|
+
round?: number;
|
|
948
|
+
ar?: number;
|
|
949
|
+
ak?: number;
|
|
950
|
+
g3?: number;
|
|
951
|
+
charge?: number;
|
|
952
|
+
rail?: number;
|
|
953
|
+
jacket?: number;
|
|
954
|
+
gas?: number;
|
|
955
|
+
noFH?: number;
|
|
956
|
+
carry?: number;
|
|
957
|
+
bipod?: number;
|
|
958
|
+
bolt?: number;
|
|
959
|
+
lever?: number;
|
|
960
|
+
tube?: number;
|
|
961
|
+
pump?: number;
|
|
962
|
+
heat?: number;
|
|
963
|
+
/** Chambers of the revolver cylinder (default 6): the capacity of the weapon. */
|
|
964
|
+
chambers?: number;
|
|
965
|
+
bayo?: number;
|
|
966
|
+
rod?: number;
|
|
967
|
+
bands?: number;
|
|
968
|
+
shot?: number;
|
|
969
|
+
/** Launcher type: `rpg`, `m72`, `at4`, `carl`, `flame`, `flameDIY`. */
|
|
970
|
+
lt?: string;
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* Numbers the builders write down while they draw, in the space of `inner` (metres along the barrel, before `fitLength` stretches it): where the accessories go.
|
|
974
|
+
* Written by the rifle and the M134 builders; the others get theirs measured from the model (`deriveFrames`).
|
|
975
|
+
*/
|
|
976
|
+
interface ModelFrames {
|
|
977
|
+
length: number;
|
|
978
|
+
barrelY: number;
|
|
979
|
+
barrelRadius: number;
|
|
980
|
+
receiverStart: number;
|
|
981
|
+
receiverEnd: number;
|
|
982
|
+
receiverHeight: number;
|
|
983
|
+
receiverWidth: number;
|
|
984
|
+
handguardEnd: number;
|
|
985
|
+
magazineX: number;
|
|
986
|
+
gripX: number;
|
|
987
|
+
/** The top rail is drawn (an optic sits on it without an adapter). */
|
|
988
|
+
hasRail: boolean;
|
|
989
|
+
/** Where the gun joins what is under the barrel (x, y), when the model has a place for it that the rule does not derive from the handguard. */
|
|
990
|
+
underbarrel?: readonly [number, number];
|
|
991
|
+
}
|
|
992
|
+
/** The moving mechanism of a model, which picks its fire, reload and clear motion. */
|
|
993
|
+
type ModelFamily = 'pistol' | 'revolver' | 'rifle' | 'semiint' | 'semi12' | 'p90' | 'belt' | 'pump' | 'lever' | 'bolt' | 'boltmag' | 'break' | 'rocket' | 'flame';
|
|
994
|
+
/** The named parts a model exposes to the animation: pivots and marks inside the model, never copies. */
|
|
995
|
+
interface ModelParts {
|
|
996
|
+
family: ModelFamily;
|
|
997
|
+
/** Recoil strength of the model (the page's `kick`). */
|
|
998
|
+
kick?: number;
|
|
999
|
+
/** How far the slide or bolt travels back, in metres. */
|
|
1000
|
+
stroke?: number;
|
|
1001
|
+
slide?: THREE_NS.Object3D;
|
|
1002
|
+
bolt?: THREE_NS.Object3D;
|
|
1003
|
+
boltHandle?: THREE_NS.Object3D;
|
|
1004
|
+
boltHandleRest?: number;
|
|
1005
|
+
mag?: THREE_NS.Object3D | null;
|
|
1006
|
+
/** How far a magazine drops, and `1` for one that goes up. */
|
|
1007
|
+
magDrop?: number;
|
|
1008
|
+
magDir?: number;
|
|
1009
|
+
trigger?: THREE_NS.Object3D;
|
|
1010
|
+
hammer?: THREE_NS.Object3D;
|
|
1011
|
+
lever?: THREE_NS.Object3D;
|
|
1012
|
+
pump?: THREE_NS.Object3D;
|
|
1013
|
+
belt?: THREE_NS.Object3D;
|
|
1014
|
+
cover?: THREE_NS.Object3D;
|
|
1015
|
+
crane?: THREE_NS.Object3D;
|
|
1016
|
+
cylinder?: THREE_NS.Object3D;
|
|
1017
|
+
chambers?: THREE_NS.Object3D[];
|
|
1018
|
+
barrels?: THREE_NS.Object3D;
|
|
1019
|
+
breech?: THREE_NS.Object3D[];
|
|
1020
|
+
/** The pivot of the pistol grip (its y runs along the grip, tilted as the grip is): the right hand holds here. Models without a drawn grip leave it out and the hand is placed from `frames`. */
|
|
1021
|
+
grip?: THREE_NS.Object3D;
|
|
1022
|
+
/** The existing selector or safety mesh; the gallery draws it but does not move it. */
|
|
1023
|
+
safety?: THREE_NS.Object3D;
|
|
1024
|
+
muzzle?: THREE_NS.Object3D;
|
|
1025
|
+
eject?: THREE_NS.Object3D;
|
|
1026
|
+
loadPort?: THREE_NS.Object3D;
|
|
1027
|
+
topLoad?: THREE_NS.Object3D;
|
|
1028
|
+
/** Parts that glow with barrel heat; each owns a clone of its material. */
|
|
1029
|
+
glow: THREE_NS.Mesh[];
|
|
1030
|
+
/** Launchers. */
|
|
1031
|
+
launcherType?: string;
|
|
1032
|
+
disposable?: boolean;
|
|
1033
|
+
rear?: THREE_NS.Object3D;
|
|
1034
|
+
round?: THREE_NS.Object3D;
|
|
1035
|
+
roundRest?: number;
|
|
1036
|
+
makeRound?: () => THREE_NS.Object3D;
|
|
1037
|
+
gauge?: THREE_NS.Object3D;
|
|
1038
|
+
/** Where the accessories go (see `ModelFrames`). */
|
|
1039
|
+
frames?: ModelFrames;
|
|
1040
|
+
/** The meshes of the stock the builder drew, in the order it drew them: `rigStock` moves them into one pivot. */
|
|
1041
|
+
stockMeshes?: THREE_NS.Object3D[];
|
|
1042
|
+
/** The stock pivot `rigStock` made, and how it moves. */
|
|
1043
|
+
stock?: THREE_NS.Object3D;
|
|
1044
|
+
stockMove?: StockMove;
|
|
1045
|
+
/** The meshes of each part that ships on the weapon, by accessory id (`red_dot`, `bipod`, `muzzle_brake`): taking the accessory off hides them. */
|
|
1046
|
+
fittings?: Record<string, THREE_NS.Object3D[]>;
|
|
1047
|
+
/** The pivot a launcher under the barrel sits in (made by `rigUnderbarrel`), and its muzzle mark once one is fitted. */
|
|
1048
|
+
ugl?: THREE_NS.Object3D;
|
|
1049
|
+
uglMuzzle?: THREE_NS.Object3D;
|
|
1050
|
+
}
|
|
1051
|
+
/** How the stock moves when it collapses: a slide of `travel` metres along the weapon (in `inner` units), or a half turn about `axis` (`foldAxis` of the rule). */
|
|
1052
|
+
interface StockMove {
|
|
1053
|
+
kind: 'fold' | 'retract';
|
|
1054
|
+
axis: 'x' | 'y' | 'z';
|
|
1055
|
+
travel: number;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
/** One weapon of the gallery as `data/models.json` keeps it: the builder, the measures in mm and the builder's options. */
|
|
1059
|
+
interface ModelEntry {
|
|
1060
|
+
readonly builder: 'pistol' | 'revolver' | 'rifle' | 'bullpup' | 'p90' | 'break' | 'm2' | 'm134' | 'launcher';
|
|
1061
|
+
readonly caliber: string;
|
|
1062
|
+
readonly length: number;
|
|
1063
|
+
readonly barrel: number;
|
|
1064
|
+
readonly options: ModelOptions;
|
|
1065
|
+
readonly variantOf?: string;
|
|
1066
|
+
}
|
|
1067
|
+
declare const MODEL_ENTRIES: Readonly<Record<string, ModelEntry>>;
|
|
1068
|
+
/**
|
|
1069
|
+
* The model each generic archetype wears: the one of the first brand weapon (lowest id) that points to it with `archetype` and fires the same way (a rocket launcher that points to
|
|
1070
|
+
* `shotgun_pump_12` does not lend its tube to the shotgun). An archetype nothing points to, the melee weapons and the bow keep their simple prop.
|
|
1071
|
+
*/
|
|
1072
|
+
declare const ARCHETYPE_MODELS: Readonly<Record<string, string>>;
|
|
1073
|
+
/** A weapon model: `root` (the page's `wr`) holds `inner` (what the builder made, fitted to the real length); `parts` are pivots and marks inside `inner`. */
|
|
1074
|
+
interface WeaponModel {
|
|
1075
|
+
readonly id: string;
|
|
1076
|
+
readonly root: THREE_NS.Group;
|
|
1077
|
+
readonly inner: THREE_NS.Group;
|
|
1078
|
+
readonly parts: ModelParts;
|
|
1079
|
+
}
|
|
1080
|
+
declare const hasWeaponModel: (id: string) => boolean;
|
|
1081
|
+
/** The gallery model of a weapon (or of the brand weapon an archetype wears, see `ARCHETYPE_MODELS`), long axis along +x, rear at the origin; undefined for melee, throwables and what nothing drew. */
|
|
1082
|
+
declare function buildWeaponModelById(THREE: typeof THREE_NS, id: string): WeaponModel | undefined;
|
|
1083
|
+
|
|
1084
|
+
type Three = typeof THREE_NS;
|
|
1085
|
+
type Material = THREE_NS.Material;
|
|
1086
|
+
type Parent = THREE_NS.Object3D;
|
|
1087
|
+
declare const createMaterials: (THREE: Three) => {
|
|
1088
|
+
metal: THREE_NS.MeshStandardMaterial;
|
|
1089
|
+
steel: THREE_NS.MeshStandardMaterial;
|
|
1090
|
+
steelL: THREE_NS.MeshStandardMaterial;
|
|
1091
|
+
dark: THREE_NS.MeshStandardMaterial;
|
|
1092
|
+
poly: THREE_NS.MeshStandardMaterial;
|
|
1093
|
+
olive: THREE_NS.MeshStandardMaterial;
|
|
1094
|
+
tan: THREE_NS.MeshStandardMaterial;
|
|
1095
|
+
wood: THREE_NS.MeshStandardMaterial;
|
|
1096
|
+
woodL: THREE_NS.MeshStandardMaterial;
|
|
1097
|
+
brass: THREE_NS.MeshStandardMaterial;
|
|
1098
|
+
copper: THREE_NS.MeshStandardMaterial;
|
|
1099
|
+
lead: THREE_NS.MeshStandardMaterial;
|
|
1100
|
+
shell: THREE_NS.MeshStandardMaterial;
|
|
1101
|
+
glass: THREE_NS.MeshStandardMaterial;
|
|
1102
|
+
lens: THREE_NS.MeshStandardMaterial;
|
|
1103
|
+
rubber: THREE_NS.MeshStandardMaterial;
|
|
1104
|
+
white: THREE_NS.MeshStandardMaterial;
|
|
1105
|
+
hole: THREE_NS.MeshStandardMaterial;
|
|
1106
|
+
bake: THREE_NS.MeshStandardMaterial;
|
|
1107
|
+
rust: THREE_NS.MeshStandardMaterial;
|
|
1108
|
+
rustD: THREE_NS.MeshStandardMaterial;
|
|
1109
|
+
worn: THREE_NS.MeshStandardMaterial;
|
|
1110
|
+
fire: THREE_NS.MeshBasicMaterial;
|
|
1111
|
+
fire2: THREE_NS.MeshBasicMaterial;
|
|
1112
|
+
flashA: THREE_NS.MeshBasicMaterial;
|
|
1113
|
+
flashB: THREE_NS.MeshBasicMaterial;
|
|
1114
|
+
smokeP: THREE_NS.MeshStandardMaterial;
|
|
1115
|
+
/** Launcher paints. */
|
|
1116
|
+
yellow: THREE_NS.MeshStandardMaterial;
|
|
1117
|
+
red: THREE_NS.MeshStandardMaterial;
|
|
1118
|
+
redPaint: THREE_NS.MeshStandardMaterial;
|
|
1119
|
+
tape: THREE_NS.MeshStandardMaterial;
|
|
1120
|
+
pipe: THREE_NS.MeshStandardMaterial;
|
|
1121
|
+
green: THREE_NS.MeshStandardMaterial;
|
|
1122
|
+
/** Magazine finishes named by the options. */
|
|
1123
|
+
bakelite: THREE_NS.MeshStandardMaterial;
|
|
1124
|
+
polyMag: THREE_NS.MeshStandardMaterial;
|
|
1125
|
+
};
|
|
1126
|
+
type ModelMaterials = ReturnType<typeof createMaterials>;
|
|
1127
|
+
/**
|
|
1128
|
+
* The gallery's primitives on the host's three.js. Each takes the parent first and the position last as the page does (`box(parent, w, h, d, material, x, y, z, rz, ry, rx)`),
|
|
1129
|
+
* so that the builders read like the originals. `roundness` is the page's `RF`: how round the next boxes are, `null` for the default.
|
|
1130
|
+
*/
|
|
1131
|
+
interface ModelKit {
|
|
1132
|
+
readonly THREE: Three;
|
|
1133
|
+
readonly M: ModelMaterials;
|
|
1134
|
+
roundness: number | null;
|
|
1135
|
+
group(): THREE_NS.Group;
|
|
1136
|
+
box(parent: Parent, w: number, h: number, d: number, material: Material, x: number, y: number, z: number, rz?: number, ry?: number, rx?: number): THREE_NS.Mesh;
|
|
1137
|
+
/** Cylinders along x, y and z. `radiusEnd` makes a cone. */
|
|
1138
|
+
cylinderX(parent: Parent, radius: number, length: number, material: Material, x: number, y: number, z: number, segments?: number, radiusEnd?: number): THREE_NS.Mesh;
|
|
1139
|
+
cylinderY(parent: Parent, radius: number, height: number, material: Material, x: number, y: number, z: number, segments?: number, radiusEnd?: number): THREE_NS.Mesh;
|
|
1140
|
+
cylinderZ(parent: Parent, radius: number, length: number, material: Material, x: number, y: number, z: number, segments?: number): THREE_NS.Mesh;
|
|
1141
|
+
sphere(parent: Parent, radius: number, material: Material, x: number, y: number, z: number, detail?: number): THREE_NS.Mesh;
|
|
1142
|
+
torus(parent: Parent, geometry: THREE_NS.TorusGeometry, material: Material, x: number, y: number, z: number): THREE_NS.Mesh;
|
|
1143
|
+
mark(parent: Parent, x: number, y: number, z: number): THREE_NS.Object3D;
|
|
1144
|
+
pivot(parent: Parent, x?: number, y?: number, z?: number): THREE_NS.Group;
|
|
1145
|
+
}
|
|
1146
|
+
/**
|
|
1147
|
+
* One kit per three.js namespace: the materials and the geometry cache are shared by every model built with it. The kit's `THREE` is
|
|
1148
|
+
* `shapeGeometries(host)`: box, cylinder, cone, sphere and torus come from game-shapes (the same bytes, the same classes); the rest is the host's.
|
|
1149
|
+
*/
|
|
1150
|
+
declare function modelKit(host: Three): ModelKit;
|
|
1151
|
+
|
|
1152
|
+
type Vec3 = [number, number, number];
|
|
1153
|
+
/** The shape of a model that carries its `inner` and `root` as `buildWeaponModelById` makes them. */
|
|
1154
|
+
interface FramedModel {
|
|
1155
|
+
readonly root: THREE_NS.Group;
|
|
1156
|
+
readonly inner: THREE_NS.Group;
|
|
1157
|
+
readonly parts: ModelParts;
|
|
1158
|
+
}
|
|
1159
|
+
/** Where an accessory of one kind of mount goes, in the space of the wrapper (`root`): the origin of its own frame and the sizes it needs from the weapon. */
|
|
1160
|
+
interface MountFrame {
|
|
1161
|
+
readonly mount: MountKind;
|
|
1162
|
+
readonly position: Vec3;
|
|
1163
|
+
/** The other end, for what stretches between two points (a sling between its swivels). */
|
|
1164
|
+
readonly secondary?: Vec3;
|
|
1165
|
+
readonly barrelRadius: number;
|
|
1166
|
+
readonly receiverWidth: number;
|
|
1167
|
+
readonly receiverHeight: number;
|
|
1168
|
+
/** The top rail is drawn: an optic needs no adapter. */
|
|
1169
|
+
readonly hasRail: boolean;
|
|
1170
|
+
/** The sign of z for a side rail: left is negative, right is positive (z is to the right of the weapon). */
|
|
1171
|
+
readonly side: -1 | 0 | 1;
|
|
1172
|
+
}
|
|
1173
|
+
/**
|
|
1174
|
+
* Frames for a model whose builder wrote none (pistols, revolvers, bullpups, launchers...): measured from the model as it is built, with `root` still at the origin.
|
|
1175
|
+
* The numbers are in the space of `inner`, like the ones the rifle builder writes.
|
|
1176
|
+
*/
|
|
1177
|
+
declare function deriveFrames(THREE: typeof THREE_NS, model: FramedModel): ModelFrames;
|
|
1178
|
+
/** The frame of a mount of the model, or undefined for the mounts nothing is drawn on (`stock`, `barrel`). */
|
|
1179
|
+
declare function mountFrame(model: FramedModel, mount: MountKind): MountFrame | undefined;
|
|
1180
|
+
|
|
1181
|
+
/** Distance in metres to what the ray hits, or null when it hits nothing within `maxDistance`: the host's raycast, which the laser asks every frame. */
|
|
1182
|
+
type LaserRaycast = (origin: THREE_NS.Vector3, direction: THREE_NS.Vector3, maxDistance: number) => number | null;
|
|
1183
|
+
/** What a builder is given: the accessory, where it sits on the weapon (`frame`, in the space of the wrapper) and the pieces of the model it may hang from or hide. */
|
|
1184
|
+
interface AttachmentBuildContext {
|
|
1185
|
+
readonly kit: ModelKit;
|
|
1186
|
+
readonly model: WeaponModel;
|
|
1187
|
+
readonly attachment: AttachmentDef;
|
|
1188
|
+
readonly fitted: FittedAttachment;
|
|
1189
|
+
readonly frame: MountFrame;
|
|
1190
|
+
readonly raycast: LaserRaycast | undefined;
|
|
1191
|
+
/** The host's light budget, when it has one: a light asks it for a slot instead of creating a `SpotLight`. */
|
|
1192
|
+
readonly lights: LightBudget | undefined;
|
|
1193
|
+
/** The meshes the magazine pivot had before any accessory (a drum or an extension replaces or extends them). */
|
|
1194
|
+
readonly factoryMagazine: readonly THREE_NS.Object3D[];
|
|
1195
|
+
/** The pivot of the launcher under the barrel, which the reload clip slides (only on a weapon with a place for one). */
|
|
1196
|
+
readonly slide: THREE_NS.Object3D | undefined;
|
|
1197
|
+
}
|
|
1198
|
+
/** What a builder makes: the object (its origin on the frame), and what the rig needs to know about it. */
|
|
1199
|
+
interface AttachmentModel {
|
|
1200
|
+
readonly object: THREE_NS.Object3D;
|
|
1201
|
+
/** Where the object hangs: the wrapper (default), the magazine pivot (it moves with the magazine) or the sliding pivot of the launcher. */
|
|
1202
|
+
readonly hangsFrom?: 'root' | 'magazine';
|
|
1203
|
+
/** Parts of the weapon that are not drawn while this one is on (a drum hides the magazine it replaces). */
|
|
1204
|
+
readonly hides?: readonly THREE_NS.Object3D[];
|
|
1205
|
+
/** How far forward the muzzle moves (a suppressor): the flash and the smoke come out of its end. */
|
|
1206
|
+
readonly muzzleOffset?: number;
|
|
1207
|
+
/** A launcher's muzzle mark, which the shot clip flashes. */
|
|
1208
|
+
readonly muzzle?: THREE_NS.Object3D;
|
|
1209
|
+
/** A light or laser turned on or off. */
|
|
1210
|
+
setOn?(on: boolean): void;
|
|
1211
|
+
/** Every frame, while the weapon is in the hands (the laser measures how far its beam goes). */
|
|
1212
|
+
update?(): void;
|
|
1213
|
+
dispose?(): void;
|
|
1214
|
+
}
|
|
1215
|
+
type AttachmentModelBuilder = (context: AttachmentBuildContext) => AttachmentModel | THREE_NS.Object3D | null;
|
|
1216
|
+
/** Builders by the `model` id of the accessory (`AttachmentDef.model`). A game replaces or adds one with `attachmentModels` of the weapons module. */
|
|
1217
|
+
type AttachmentModelRegistry = Readonly<Record<string, AttachmentModelBuilder>>;
|
|
1218
|
+
|
|
1219
|
+
/** What a weapon or an explosive asks of an item model: the fields of `DrawableItem` of game-items-three that it fills in. */
|
|
1220
|
+
interface ItemModelRequest {
|
|
1221
|
+
id: string;
|
|
1222
|
+
category: string;
|
|
1223
|
+
size: [number, number, number];
|
|
1224
|
+
model?: string;
|
|
1225
|
+
}
|
|
1226
|
+
/**
|
|
1227
|
+
* The item models of game-items-three, lent by the host as `items`; `itemModels` of game-items-three fits it, and the host that passes none gets it as the default.
|
|
1228
|
+
* The default is deprecated and removed in the next major: pass `items`.
|
|
1229
|
+
*/
|
|
1230
|
+
interface ItemModels {
|
|
1231
|
+
has(id: string): boolean;
|
|
1232
|
+
/** `wear`: 0 new, 1 used, 2 spoiled. */
|
|
1233
|
+
build(THREE: typeof THREE_NS, item: ItemModelRequest, options?: {
|
|
1234
|
+
wear?: 0 | 1 | 2;
|
|
1235
|
+
}): {
|
|
1236
|
+
root: THREE_NS.Group;
|
|
1237
|
+
kind: string;
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
interface WeaponFxOptions {
|
|
1242
|
+
/** The item models of game-items-three (`itemModels` there) that draw the weapons the gallery did not model; default `itemModels` there (deprecated: pass it). */
|
|
1243
|
+
items?: ItemModels;
|
|
1244
|
+
THREE: typeof THREE_NS;
|
|
1245
|
+
scene: THREE_NS.Scene;
|
|
1246
|
+
camera: THREE_NS.Camera;
|
|
1247
|
+
arsenal: Arsenal;
|
|
1248
|
+
/** Height things rest on at (x, z): casings and magazines land there. */
|
|
1249
|
+
groundAt: (x: number, z: number) => number;
|
|
1250
|
+
/** Sounds (`createWeaponAudio`); null or absent: silent. */
|
|
1251
|
+
audio?: WeaponAudio | null;
|
|
1252
|
+
/** Seed of the scatter of the effects of the gallery models. */
|
|
1253
|
+
seed?: number;
|
|
1254
|
+
/** The rocket of a launcher flies out of the viewmodel along the barrel (default true). A host that draws the projectile itself (the test room does) sets it to false, so one round flies, not two. */
|
|
1255
|
+
flyRocket?: boolean;
|
|
1256
|
+
/** The tool as it is now (barrel heat, fuel burning). */
|
|
1257
|
+
tool?: () => HostTool;
|
|
1258
|
+
/** Wear of the weapon: `new`, `used`, `worn` or `rusty`. */
|
|
1259
|
+
condition?: string;
|
|
1260
|
+
/** What is drawn: read at the moment of each event, so the bench can change it live. */
|
|
1261
|
+
layers?: FxLayers;
|
|
1262
|
+
/** Metres between the shooter and the listener, for the distance muffling of the shot sound (default 0). */
|
|
1263
|
+
soundDistance?: () => number;
|
|
1264
|
+
/** Whether shots are in a room or in the open (the gunshot tail). Default outdoor. */
|
|
1265
|
+
soundSpace?: () => GunshotSpace;
|
|
1266
|
+
/** The floor material under a point, for the sound of a case landing there. Default concrete. */
|
|
1267
|
+
surfaceAt?: (x: number, z: number) => string | undefined;
|
|
1268
|
+
/** Told at every sound cue of a reload clip, at the moment the clip says it (also with no audio): the weapon, the cue id and the profile it sounds with. */
|
|
1269
|
+
onSound?: (cue: {
|
|
1270
|
+
weapon: string;
|
|
1271
|
+
cue: string;
|
|
1272
|
+
profile: SoundProfile;
|
|
1273
|
+
played?: CuePlayed;
|
|
1274
|
+
}) => void;
|
|
1275
|
+
/** Builders of accessory models that replace or add to the ones the kit ships (by the `model` of the accessory). */
|
|
1276
|
+
attachmentModels?: AttachmentModelRegistry;
|
|
1277
|
+
/** How far a laser beam goes from a point along a direction (metres), or null when it hits nothing: the dot lands where it ends. */
|
|
1278
|
+
raycast?: LaserRaycast;
|
|
1279
|
+
/** Where the world is (distance from a point along a direction to the first surface, or null): the weapon in the hands comes back from a wall it would go through. */
|
|
1280
|
+
contact?: LaserRaycast;
|
|
1281
|
+
/** Where the body holds the tool (`ModuleHost.holdFrame`): third person draws it there at its real size. */
|
|
1282
|
+
bodyHold?: () => HandPose | null;
|
|
1283
|
+
/** The host's effects: the muzzle flash, smoke, backblast and flame jet of the gallery models are recipes it plays; without it the viewmodel makes a world of its own for them. */
|
|
1284
|
+
effects?: EffectSink;
|
|
1285
|
+
/** The most casings and magazines alive at once (`host.particleLimit`), read at each spawn; without it the viewmodel keeps a cap of its own. */
|
|
1286
|
+
particleLimit?: () => number | undefined;
|
|
1287
|
+
/** The host's light budget (`host.lights`): the rocket in flight and the weapon light ask it for a light; without it they create lights of their own (deprecated, removed in the next major). */
|
|
1288
|
+
lights?: LightBudget;
|
|
1289
|
+
/** The host's pools (`host.pools`): the burning droplets and the ground flames of a flamethrower take their geometry and material from them; without them each makes its own (deprecated, removed in the next major). */
|
|
1290
|
+
pools?: RenderPools;
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
/** The weapon in the hands, its fire and reload motion, ejected casings and dropped magazines, and their sounds. */
|
|
1294
|
+
interface WeaponFx {
|
|
1295
|
+
/** Feed every tool event of the host, with the tool as it is after the event. */
|
|
1296
|
+
handle(event: HostEvent, tool: HostTool): void;
|
|
1297
|
+
update(dt: number): void;
|
|
1298
|
+
/** Dresses the weapon for its wear (`new`, `used`, `worn`, `rusty`); the gallery models show it in their metal. */
|
|
1299
|
+
setCondition(condition: string): void;
|
|
1300
|
+
/** Where the hands take the weapon (world space, read every frame after `update`): the grip and the forend of the model, or the handle of the generic prop; null with nothing in the hands. */
|
|
1301
|
+
handTargets(): HandTargets | null;
|
|
1302
|
+
/** What is drawn (casings, magazines, muzzle flash): change a field and the next event follows it. */
|
|
1303
|
+
readonly layers: FxLayers;
|
|
1304
|
+
/** Weapon shown in the hands, or null. */
|
|
1305
|
+
readonly inHand: string | null;
|
|
1306
|
+
/** The clips of the model playing now with the seconds each lasts (scaled to the rule's duration): which reload variant went (`reload` or `reload_empty`...). */
|
|
1307
|
+
readonly clips: ReadonlyArray<{
|
|
1308
|
+
name: string;
|
|
1309
|
+
seconds: number;
|
|
1310
|
+
}>;
|
|
1311
|
+
/** Casings and magazines currently on the floor or in the air. */
|
|
1312
|
+
readonly casings: number;
|
|
1313
|
+
readonly magazines: number;
|
|
1314
|
+
dispose(): void;
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* The presentation of the tool in the hands. The weapons the gallery drew (`MODEL_ENTRIES`) get their model and the clips the rule's events call for
|
|
1318
|
+
* (fire, cycle, jam, clear, safety, the seven reloads); the generic archetypes keep their low-poly prop.
|
|
1319
|
+
*/
|
|
1320
|
+
declare function createWeaponFx(options: WeaponFxOptions): WeaponFx;
|
|
1321
|
+
|
|
1322
|
+
/** How a weapon is drawn from an item model of game-items-three: the item (default the weapon id), and the turns the laying-down rule gets wrong. */
|
|
1323
|
+
interface WeaponItemModel {
|
|
1324
|
+
/** Catalog id of the item model; the weapon id when absent. */
|
|
1325
|
+
readonly item?: string;
|
|
1326
|
+
/** Quarter turns about y after the long axis is laid along x (a crossbow's stock is shorter than its limbs). */
|
|
1327
|
+
readonly turn?: number;
|
|
1328
|
+
/** Turn it end for end after the head is found (the head is the narrow end: a knife's blade, a screwdriver's tip, an extinguisher's nozzle). */
|
|
1329
|
+
readonly flip?: boolean;
|
|
1330
|
+
}
|
|
1331
|
+
/** The weapons whose item model has another id or turns another way, with the draw that reads them: one set, with no other set sharing it. */
|
|
1332
|
+
interface WeaponProps {
|
|
1333
|
+
/** Draws a weapon the gallery did not model with an item model of game-items-three (a game adds its own or corrects one; `null` keeps the low-poly prop). */
|
|
1334
|
+
register(weaponId: string, model: WeaponItemModel | null): void;
|
|
1335
|
+
/** The override of a weapon, if the set has one. */
|
|
1336
|
+
get(weaponId: string): WeaponItemModel | undefined;
|
|
1337
|
+
/** The item model of game-items-three that draws a weapon, or undefined when there is none. */
|
|
1338
|
+
itemModelOf(weaponId: string, items?: ItemModels): string | undefined;
|
|
1339
|
+
/** `buildItemWeaponModel` with this set's overrides. */
|
|
1340
|
+
buildItemModel(THREE: typeof THREE_NS, def: Pick<WeaponDef, 'id'>, items?: ItemModels): THREE_NS.Group | undefined;
|
|
1341
|
+
/** `buildWeaponModel` with this set's overrides. */
|
|
1342
|
+
buildModel(THREE: typeof THREE_NS, def: Pick<WeaponDef, 'id' | 'category' | 'mass'>, items?: ItemModels): THREE_NS.Group;
|
|
1343
|
+
}
|
|
1344
|
+
/** The set behind `registerWeaponItemModel`, `itemModelOfWeapon`, `buildItemWeaponModel` and `buildWeaponModel`, created on first use. */
|
|
1345
|
+
declare const defaultWeaponProps: () => WeaponProps;
|
|
1346
|
+
/** @deprecated use `createWeaponProps(...).register`. */
|
|
1347
|
+
declare const registerWeaponItemModel: (weaponId: string, model: WeaponItemModel | null) => void;
|
|
1348
|
+
/** The item model of game-items-three that draws a weapon (`baseball_bat`, `axe`, `fire_extinguisher`...), or undefined when there is none. @deprecated use `createWeaponProps(...).itemModelOf`. */
|
|
1349
|
+
declare const itemModelOfWeapon: (weaponId: string, items?: ItemModels) => string | undefined;
|
|
1350
|
+
/**
|
|
1351
|
+
* A weapon the gallery did not draw, with the team's item model (Itens do Vale Cinzento: the bat, the axe, the machete, the extinguisher...): its long axis turned
|
|
1352
|
+
* along +x and laid flat, the wider end (the head) at +x unless `registerWeaponItemModel` says otherwise, the origin at the bottom centre, an empty `handle` at the narrow end where the hand closes. Undefined
|
|
1353
|
+
* when `items` (the item models of game-items-three, lent by the host; default `itemModels` there) has none of it.
|
|
1354
|
+
* @deprecated use `createWeaponProps(...).buildItemModel`.
|
|
1355
|
+
*/
|
|
1356
|
+
declare const buildItemWeaponModel: (THREE: typeof THREE_NS, def: Pick<WeaponDef, "id">, items?: ItemModels) => THREE_NS.Group | undefined;
|
|
1357
|
+
/** The model of a weapon for the hands or a shelf: the team's item model when the kit has one (`buildItemWeaponModel`), the low-poly prop the counters show otherwise. @deprecated use `createWeaponProps(...).buildModel`. */
|
|
1358
|
+
declare const buildWeaponModel: (THREE: typeof THREE_NS, def: Pick<WeaponDef, "id" | "category" | "mass">, items?: ItemModels) => THREE_NS.Group;
|
|
1359
|
+
|
|
1360
|
+
interface WeaponsTestModuleOptions {
|
|
1361
|
+
/** `en` or `pt-BR` (default). */
|
|
1362
|
+
locale?: string;
|
|
1363
|
+
/** The arsenal to lay out (default `createArsenal` with the locale). */
|
|
1364
|
+
arsenal?: Arsenal;
|
|
1365
|
+
/** Play sounds (default true; silent anyway where there is no AudioContext). */
|
|
1366
|
+
sound?: boolean;
|
|
1367
|
+
/** The recorded shots and reload steps (game-audio's sfx manifest and where its files are); without it the synthesized sounds play. */
|
|
1368
|
+
samples?: WeaponSampleOptions;
|
|
1369
|
+
/** Wear of the weapon in the hands, which the gallery models show in their metal: `new` (default), `used`, `worn` or `rusty`. */
|
|
1370
|
+
condition?: string;
|
|
1371
|
+
/** Seed of the scatter of casings and smoke (default 1). */
|
|
1372
|
+
seed?: number;
|
|
1373
|
+
/** Builders of accessory models that replace or add to the ones the kit ships (by the `model` of the accessory). */
|
|
1374
|
+
attachmentModels?: AttachmentModelRegistry;
|
|
1375
|
+
/** Folder (ending with a slash) the weapon thumbnails are served from, relative to the page (default `weapon-svg/`); `false` leaves the items without a thumbnail. */
|
|
1376
|
+
thumbnailBase?: string | false;
|
|
1377
|
+
/** The rocket of a launcher flies out of the weapon in the hands (default true). A host that draws the projectile (the test room's `projectileModel`) passes false: one round flies. */
|
|
1378
|
+
flyRocket?: boolean;
|
|
1379
|
+
/** The item models of game-items-three (`itemModels` there): the weapons the gallery did not draw get the team's model instead of the low-poly prop; default `itemModels` there (deprecated: pass it). */
|
|
1380
|
+
items?: ItemModels;
|
|
1381
|
+
/** The weapon item model overrides to draw with (`createWeaponProps(...)`); default the shared set behind `registerWeaponItemModel`. */
|
|
1382
|
+
props?: WeaponProps;
|
|
1383
|
+
}
|
|
1384
|
+
/** Prefix of the item ids of the weapon props (`weapon_pistol_9mm`). */
|
|
1385
|
+
declare const WEAPON_ITEM_PREFIX = "weapon_";
|
|
1386
|
+
declare const COUNTER_ITEM_ID = "counter_weapons";
|
|
1387
|
+
declare const MOUNTED_M134_ITEM_ID = "m134_tripod";
|
|
1388
|
+
/** Where the counters go and where each weapon lies on them: weapons side by side across the counters in order, each taking its strip, until the counter is full. */
|
|
1389
|
+
declare function weaponsLayout(weaponItemIds: string[], pitchOf?: (itemId: string) => number): AreaPlacement[];
|
|
1390
|
+
/**
|
|
1391
|
+
* The weapons test area as a `TestableModule` of @adatechnology/game-contracts: every weapon of the arsenal on counters, the real model of each one the gallery drew (aim at one and
|
|
1392
|
+
* press H to equip it), targets at shooting distance, and, through `attach`, the weapon in the hands with its fire and reload motion,
|
|
1393
|
+
* ejected casings, dropped magazines and sounds, driven by the host's tool events.
|
|
1394
|
+
*/
|
|
1395
|
+
declare function createWeaponsTestModule(options?: WeaponsTestModuleOptions): TestableModule & {
|
|
1396
|
+
readonly audio: WeaponAudio | null;
|
|
1397
|
+
readonly fx: WeaponFx | null;
|
|
1398
|
+
};
|
|
1399
|
+
|
|
1400
|
+
/** The words of the explosives area (the P13 cylinder bench and its narration), by locale (`en` and `pt-BR`). `{name}` marks a value the module fills in. */
|
|
1401
|
+
interface ExplosivesText {
|
|
1402
|
+
group: string;
|
|
1403
|
+
name: string;
|
|
1404
|
+
cylinder: string;
|
|
1405
|
+
actions: Record<'shoot' | 'valve' | 'light' | 'fire' | 'reset', {
|
|
1406
|
+
name: string;
|
|
1407
|
+
hint: string;
|
|
1408
|
+
}>;
|
|
1409
|
+
blastScale: {
|
|
1410
|
+
name: string;
|
|
1411
|
+
hint: string;
|
|
1412
|
+
};
|
|
1413
|
+
layers: Record<'rings', string>;
|
|
1414
|
+
metrics: Record<'gas' | 'clock' | 'phase', string>;
|
|
1415
|
+
phases: Record<'rest' | 'leaking' | 'torch' | 'primed' | 'exploded', string>;
|
|
1416
|
+
rings: {
|
|
1417
|
+
lethal: string;
|
|
1418
|
+
injury: string;
|
|
1419
|
+
};
|
|
1420
|
+
triggers: Record<'shot' | 'fire' | 'explosion', string>;
|
|
1421
|
+
things: Record<string, string>;
|
|
1422
|
+
verdicts: {
|
|
1423
|
+
wall_pieces: string;
|
|
1424
|
+
lost_parts: string;
|
|
1425
|
+
dead: string;
|
|
1426
|
+
hurt: string;
|
|
1427
|
+
unhurt: string;
|
|
1428
|
+
wall_broken: string;
|
|
1429
|
+
wall_cracked: string;
|
|
1430
|
+
wall_intact: string;
|
|
1431
|
+
burning: string;
|
|
1432
|
+
standing: string;
|
|
1433
|
+
};
|
|
1434
|
+
log: {
|
|
1435
|
+
leak_shot: string;
|
|
1436
|
+
leak_valve: string;
|
|
1437
|
+
valve_closed: string;
|
|
1438
|
+
valve_closed_late: string;
|
|
1439
|
+
primed: string;
|
|
1440
|
+
jet_lit: string;
|
|
1441
|
+
jet_lit_by: string;
|
|
1442
|
+
lighter_none: string;
|
|
1443
|
+
lighter_lit: string;
|
|
1444
|
+
fire_set: string;
|
|
1445
|
+
heating: string;
|
|
1446
|
+
explode: string;
|
|
1447
|
+
shell: string;
|
|
1448
|
+
shell_landed: string;
|
|
1449
|
+
residual: string;
|
|
1450
|
+
aftermath_person: string;
|
|
1451
|
+
aftermath_wall: string;
|
|
1452
|
+
aftermath_object: string;
|
|
1453
|
+
reset: string;
|
|
1454
|
+
scale: string;
|
|
1455
|
+
no_room: string;
|
|
1456
|
+
shoot: string;
|
|
1457
|
+
no_vessel: string;
|
|
1458
|
+
};
|
|
1459
|
+
sheet: {
|
|
1460
|
+
kicker: string;
|
|
1461
|
+
title: string;
|
|
1462
|
+
body: string;
|
|
1463
|
+
facts: Record<'energy' | 'lethal' | 'injury' | 'gas' | 'mass' | 'torch' | 'shot_chain' | 'fire_chain', string>;
|
|
1464
|
+
steps: Array<{
|
|
1465
|
+
at: string;
|
|
1466
|
+
text: string;
|
|
1467
|
+
}>;
|
|
1468
|
+
segments: Record<'jet' | 'torch' | 'blast', string>;
|
|
1469
|
+
note: string;
|
|
1470
|
+
};
|
|
1471
|
+
scenarios: {
|
|
1472
|
+
shot: string;
|
|
1473
|
+
shot_leak: string;
|
|
1474
|
+
shot_ignite: string;
|
|
1475
|
+
shot_explode: string;
|
|
1476
|
+
shot_zombie: string;
|
|
1477
|
+
shot_survivor: string;
|
|
1478
|
+
shot_wall: string;
|
|
1479
|
+
valve: string;
|
|
1480
|
+
valve_leak: string;
|
|
1481
|
+
valve_quiet: string;
|
|
1482
|
+
valve_lit: string;
|
|
1483
|
+
valve_explode: string;
|
|
1484
|
+
fire: string;
|
|
1485
|
+
fire_explode: string;
|
|
1486
|
+
chain: string;
|
|
1487
|
+
chain_explode: string;
|
|
1488
|
+
push_p13: string;
|
|
1489
|
+
push_grenade: string;
|
|
1490
|
+
push_found: string;
|
|
1491
|
+
push_told: string;
|
|
1492
|
+
push_outward: string;
|
|
1493
|
+
push_falloff: string;
|
|
1494
|
+
push_person: string;
|
|
1495
|
+
push_sheltered: string;
|
|
1496
|
+
push_heavy: string;
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
declare const EXPLOSIVES_TEXT: Record<string, ExplosivesText>;
|
|
1500
|
+
declare const explosivesTextOf: (locale: string) => ExplosivesText;
|
|
1501
|
+
|
|
1502
|
+
/** Id of the explosives module (`?area=explosives_area` opens it). */
|
|
1503
|
+
declare const EXPLOSIVES_AREA_ID = "explosives_area";
|
|
1504
|
+
/** The parts of a part state the bench reads (structural: `PartState` of the destruction world fits). */
|
|
1505
|
+
interface PartView {
|
|
1506
|
+
readonly liters?: number;
|
|
1507
|
+
readonly temperature: number;
|
|
1508
|
+
readonly status: string;
|
|
1509
|
+
readonly holes: ReadonlyArray<{
|
|
1510
|
+
readonly diameter: number;
|
|
1511
|
+
readonly through: boolean;
|
|
1512
|
+
}>;
|
|
1513
|
+
readonly cracks: readonly unknown[];
|
|
1514
|
+
readonly burning: boolean;
|
|
1515
|
+
}
|
|
1516
|
+
/** What the explosives module needs from the room it drives (structural: the `TestRoom` of game-test-room fits). */
|
|
1517
|
+
interface ExplosivesRoom {
|
|
1518
|
+
readonly world: {
|
|
1519
|
+
readonly time: number;
|
|
1520
|
+
ids(): string[];
|
|
1521
|
+
on(type: '*', fn: (event: DestructionEvent) => void): () => void;
|
|
1522
|
+
hit(objectId: string, hit: Hit): unknown;
|
|
1523
|
+
vent(objectId: string, partId: string, opening?: {
|
|
1524
|
+
point?: Vec3$1;
|
|
1525
|
+
normal?: Vec3$1;
|
|
1526
|
+
diameter?: number;
|
|
1527
|
+
}): boolean;
|
|
1528
|
+
seal(objectId: string, partId: string): number;
|
|
1529
|
+
part(objectId: string, partId: string): PartView | null;
|
|
1530
|
+
state(objectId: string): {
|
|
1531
|
+
readonly parts: readonly (PartView & {
|
|
1532
|
+
readonly id: string;
|
|
1533
|
+
readonly hp: number;
|
|
1534
|
+
readonly maxHp: number;
|
|
1535
|
+
})[];
|
|
1536
|
+
} | null;
|
|
1537
|
+
/** The share of a blast at `point` that reaches `target` through the cover between them (game-destruction `blastReach`). */
|
|
1538
|
+
blastReach?(point: Vec3$1, target: Vec3$1, options?: {
|
|
1539
|
+
readonly ignore?: readonly string[];
|
|
1540
|
+
}): number;
|
|
1541
|
+
};
|
|
1542
|
+
readonly renderer: {
|
|
1543
|
+
impulse(objectId: string, impulse: Vec3$1, point?: Vec3$1): void;
|
|
1544
|
+
};
|
|
1545
|
+
readonly vfx: {
|
|
1546
|
+
spawn(kind: string, point: Vec3$1, velocity: Vec3$1, options?: {
|
|
1547
|
+
color?: number;
|
|
1548
|
+
size?: number;
|
|
1549
|
+
life?: number;
|
|
1550
|
+
alpha?: number;
|
|
1551
|
+
}): void;
|
|
1552
|
+
burst(kind: string, point: Vec3$1, normal: Vec3$1, count: number, speed?: number): void;
|
|
1553
|
+
fire(options: {
|
|
1554
|
+
point: Vec3$1;
|
|
1555
|
+
radius: number;
|
|
1556
|
+
life: number;
|
|
1557
|
+
}): number;
|
|
1558
|
+
stop(handle: number): void;
|
|
1559
|
+
};
|
|
1560
|
+
spawned(): ReadonlyArray<{
|
|
1561
|
+
readonly objectId: string;
|
|
1562
|
+
readonly itemId: string;
|
|
1563
|
+
readonly root: unknown;
|
|
1564
|
+
}>;
|
|
1565
|
+
openArea(group: string): unknown;
|
|
1566
|
+
clear(): void;
|
|
1567
|
+
spawn(itemId: string, position?: Vec3$1, rotationY?: number): {
|
|
1568
|
+
readonly objectId: string;
|
|
1569
|
+
readonly itemId: string;
|
|
1570
|
+
readonly root: unknown;
|
|
1571
|
+
};
|
|
1572
|
+
setTool(weaponId: string): void;
|
|
1573
|
+
waitUntilReady(maxSeconds?: number): number;
|
|
1574
|
+
look(position: Vec3$1, target: Vec3$1): void;
|
|
1575
|
+
use(hold?: number): void;
|
|
1576
|
+
on(type: 'spawn', fn: (data: unknown) => void): () => void;
|
|
1577
|
+
}
|
|
1578
|
+
/** The bench of the explosives area as the module and its scenarios see it. */
|
|
1579
|
+
interface ExplosivesBench {
|
|
1580
|
+
readonly room: ExplosivesRoom | undefined;
|
|
1581
|
+
readonly def: ExplosiveDef;
|
|
1582
|
+
/** The strength multiplier now (the next cylinder laid takes it). */
|
|
1583
|
+
blastScale(): number;
|
|
1584
|
+
/** Called by the module's `area`: the cylinders spawned from now on belong to the area (they get their rings). */
|
|
1585
|
+
areaOpened(): void;
|
|
1586
|
+
controls(): ModuleControl[];
|
|
1587
|
+
layers(): ModuleLayer[];
|
|
1588
|
+
metrics(): ModuleMetric[];
|
|
1589
|
+
attach(host: ModuleHost): () => void;
|
|
1590
|
+
/** The actions of the bench, by the id of their button. Each answers whether it did something. */
|
|
1591
|
+
readonly actions: Readonly<Record<'shoot' | 'valve' | 'light' | 'fire' | 'reset', () => boolean>>;
|
|
1592
|
+
/** The cylinder of the scene (the first one alive), with what the bench knows about it. */
|
|
1593
|
+
vessel(): VesselView | undefined;
|
|
1594
|
+
/** The wall of the scene, the zombie and the survivor, as the aftermath reads them. */
|
|
1595
|
+
/** The last explosion the host told (a part of the world or a thrown explosive): where, how strong and how far; undefined before the first, and after the area is cleared. */
|
|
1596
|
+
lastBlast(): {
|
|
1597
|
+
readonly point: Vec3$1;
|
|
1598
|
+
readonly energy: number;
|
|
1599
|
+
readonly radius: number;
|
|
1600
|
+
readonly cause: string;
|
|
1601
|
+
readonly explosive?: string;
|
|
1602
|
+
} | undefined;
|
|
1603
|
+
witnesses(): Array<{
|
|
1604
|
+
kind: 'person' | 'wall' | 'object';
|
|
1605
|
+
id: string;
|
|
1606
|
+
itemId: string;
|
|
1607
|
+
distance: number;
|
|
1608
|
+
alive?: boolean;
|
|
1609
|
+
vitality?: number;
|
|
1610
|
+
broken?: number;
|
|
1611
|
+
marks?: number;
|
|
1612
|
+
pieces?: number;
|
|
1613
|
+
}>;
|
|
1614
|
+
}
|
|
1615
|
+
interface VesselView {
|
|
1616
|
+
readonly objectId: string;
|
|
1617
|
+
/** World time of the first leak, of the jet catching fire and of the blast (seconds); undefined until they happen. */
|
|
1618
|
+
readonly leakAt: number | undefined;
|
|
1619
|
+
readonly litAt: number | undefined;
|
|
1620
|
+
readonly explodedAt: number | undefined;
|
|
1621
|
+
readonly cause: 'shot' | 'valve' | undefined;
|
|
1622
|
+
readonly valveOpen: boolean;
|
|
1623
|
+
readonly lit: boolean;
|
|
1624
|
+
readonly exploded: boolean;
|
|
1625
|
+
readonly point: Vec3$1 | undefined;
|
|
1626
|
+
}
|
|
1627
|
+
interface ExplosivesBenchOptions {
|
|
1628
|
+
readonly locale: string;
|
|
1629
|
+
readonly text: ExplosivesText;
|
|
1630
|
+
readonly def: ExplosiveDef;
|
|
1631
|
+
readonly scene: {
|
|
1632
|
+
readonly cylinder: Vec3$1;
|
|
1633
|
+
};
|
|
1634
|
+
readonly room: ExplosivesRoom | undefined;
|
|
1635
|
+
readonly blastScale: number;
|
|
1636
|
+
readonly items?: ItemModels;
|
|
1637
|
+
readonly profile: {
|
|
1638
|
+
readonly visualRadius?: number;
|
|
1639
|
+
readonly residualFires?: ReadonlyArray<{
|
|
1640
|
+
readonly radius: number;
|
|
1641
|
+
readonly life: number;
|
|
1642
|
+
}>;
|
|
1643
|
+
} | undefined;
|
|
1644
|
+
}
|
|
1645
|
+
/**
|
|
1646
|
+
* The state and the actions of the explosives area: it follows the world's events of the cylinder (leak, primed, explode), tells each phase in the room's log, plays the torch and the flight
|
|
1647
|
+
* of the shell (the Laboratório de Explosões, `SC.p13`) and drives the destruction world for the bench actions. The module wraps it in a `TestableModule`.
|
|
1648
|
+
*/
|
|
1649
|
+
declare function createExplosivesBench(options: ExplosivesBenchOptions): ExplosivesBench;
|
|
1650
|
+
|
|
1651
|
+
/** Where the things of the scene stand (metres, in the room's world; the brick wall is the room's own at z = -11). The kitchen corner is against the wall; the player looks at it from about 6 m. */
|
|
1652
|
+
interface ExplosivesScene {
|
|
1653
|
+
/** Item ids and positions of the kitchen furniture (items of the household module); one that the room does not know is left out. */
|
|
1654
|
+
readonly furniture: ReadonlyArray<{
|
|
1655
|
+
readonly item: string;
|
|
1656
|
+
readonly at: Vec3$1;
|
|
1657
|
+
readonly rotationY?: number;
|
|
1658
|
+
}>;
|
|
1659
|
+
/** The cylinder. */
|
|
1660
|
+
readonly cylinder: Vec3$1;
|
|
1661
|
+
/** The zombie (about 3 m from the cylinder) and the survivor (about 8 m): item ids of the characters module. */
|
|
1662
|
+
readonly zombie: {
|
|
1663
|
+
readonly item: string;
|
|
1664
|
+
readonly at: Vec3$1;
|
|
1665
|
+
};
|
|
1666
|
+
readonly survivor: {
|
|
1667
|
+
readonly item: string;
|
|
1668
|
+
readonly at: Vec3$1;
|
|
1669
|
+
};
|
|
1670
|
+
/** The player's eye (about 6 m from the cylinder: outside the 5 m lethal ring, the lamp rig of the weather module is behind it). */
|
|
1671
|
+
readonly eye: Vec3$1;
|
|
1672
|
+
}
|
|
1673
|
+
/** The kitchen corner of the default scene: fridge, cabinet, the cylinder and the stove side by side against the wall, a table 2 m away. */
|
|
1674
|
+
declare const DEFAULT_EXPLOSIVES_SCENE: ExplosivesScene;
|
|
1675
|
+
interface ExplosivesTestModuleOptions {
|
|
1676
|
+
/** `en` or `pt-BR` (default). */
|
|
1677
|
+
locale?: string;
|
|
1678
|
+
/** The arsenal to read the P13 from (default `createArsenal` with the locale). */
|
|
1679
|
+
arsenal?: Arsenal;
|
|
1680
|
+
/** The room the module drives: its destruction world, effects and tools. Without it the module still lays the area and the bench shows, but the actions only say they need the room. */
|
|
1681
|
+
room?: ExplosivesRoom;
|
|
1682
|
+
/** Overrides of the default scene (see `ExplosivesScene`). */
|
|
1683
|
+
scene?: Partial<ExplosivesScene>;
|
|
1684
|
+
/** Strength multiplier the bench starts at (default 1: the arsenal's numbers; a game value, see the README). */
|
|
1685
|
+
blastScale?: number;
|
|
1686
|
+
/** The item models of game-items-three (`itemModels` there): the P13 is drawn with the team's model (default `itemModels` there, deprecated: pass it). */
|
|
1687
|
+
items?: ItemModels;
|
|
1688
|
+
}
|
|
1689
|
+
/**
|
|
1690
|
+
* The explosives test area as a `TestableModule`: the P13 cooking gas cylinder in a kitchen corner against a brick wall, with furniture, a zombie at 3 m, a survivor at 8 m and rings on the floor at the
|
|
1691
|
+
* lethal and injury radii. The bench shoots it, opens its valve, lights it with a lighter, throws it in a fire or restarts the scene; every phase is told in the room's log in the locale of the room.
|
|
1692
|
+
* The module reads the sequence (the torch delay, the gas, the flight of the shell) from the arsenal def of `propane_p13` and the blast from its `chain`, so a game changes them with `ArsenalOptions.patch.explosives`.
|
|
1693
|
+
*/
|
|
1694
|
+
declare function createExplosivesTestModule(options?: ExplosivesTestModuleOptions): TestableModule & {
|
|
1695
|
+
readonly bench: ReturnType<typeof createExplosivesBench>;
|
|
1696
|
+
};
|
|
1697
|
+
|
|
1698
|
+
export { type ShotSoundOptions as $, type AttachmentModelRegistry as A, type GunshotInput as B, CLASS_REFERENCE_ENERGY as C, DEFAULT_ENERGY_CURVE as D, EXPLOSIVES_AREA_ID as E, type FlybySound as F, GAME_DISTANCE_CURVE as G, type GunshotPlayed as H, type ItemModels as I, type ItemModelRequest as J, MECHANICAL_SOUNDS as K, type LaserRaycast as L, type ModelKit as M, MODEL_ENTRIES as N, MOUNTED_M134_ITEM_ID as O, type MechanicalSoundId as P, type ModelEntry as Q, type ModelMaterials as R, type ModelOptions as S, type MountFrame as T, RELOAD_SAMPLE as U, RELOAD_SAMPLE_HITS as V, type WeaponProps as W, type ShotExtras as X, type ShotSound as Y, type ShotSoundClass as Z, type ShotSoundInput as _, type WeaponItemModel as a, type SoundClassDef as a0, type SoundStep as a1, WEAPON_ITEM_PREFIX as a2, WEIGHT_INTENSITY as a3, type WeaponAudio as a4, type WeaponAudioOptions as a5, type WeaponFx as a6, type WeaponFxOptions as a7, type WeaponSampleOptions as a8, type WeaponsTestModuleOptions as a9, buildItemWeaponModel as aa, buildWeaponModel as ab, buildWeaponModelById as ac, computeCasingSound as ad, computeFlyby as ae, computeGunshot as af, computeShotSound as ag, createExplosivesTestModule as ah, createWeaponAudio as ai, createWeaponFx as aj, createWeaponsTestModule as ak, defaultWeaponProps as al, deriveFrames as am, explosivesTextOf as an, hasWeaponModel as ao, itemModelOfWeapon as ap, mechanicalSoundOf as aq, modelKit as ar, mountFrame as as, registerWeaponItemModel as at, weaponSampleBank as au, weaponSampleDefaults as av, weaponsLayout as aw, type WeaponModel as b, type ModelParts as c, type ModelFamily as d, ARCHETYPE_MODELS as e, type AttachmentBuildContext as f, type AttachmentModel as g, type AttachmentModelBuilder as h, COUNTER_ITEM_ID as i, CUES_IN_SAMPLE as j, type CasingSound as k, type CuePlayed as l, DEFAULT_EXPLOSIVES_SCENE as m, type DistanceCurve as n, EXPLOSIVES_TEXT as o, type EnergyCurve as p, type ExplosivesRoom as q, type ExplosivesScene as r, type ExplosivesTestModuleOptions as s, type ExplosivesText as t, type FxLayers as u, GAME_SOUND_CLASSES as v, GUNSHOT_PROFILES as w, GUNSHOT_SAMPLE as x, GUNSHOT_SAMPLE_IDS as y, type Gunshot as z };
|