@adatechnology/game-weapons-three 0.2.0 → 0.4.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.
Files changed (179) hide show
  1. package/README.md +14 -0
  2. package/assets/weapon-svg/CREDITS.md +25 -0
  3. package/assets/weapon-svg/LICENSE-NOTE.md +18 -0
  4. package/assets/weapon-svg/commons/ak_47.svg +1 -0
  5. package/assets/weapon-svg/commons/barrett_m82a1.svg +1 -0
  6. package/assets/weapon-svg/commons/benelli_m4.svg +1 -0
  7. package/assets/weapon-svg/commons/beretta_92fs.svg +1 -0
  8. package/assets/weapon-svg/commons/colt_m16a2.svg +1 -0
  9. package/assets/weapon-svg/commons/colt_m1911.svg +1 -0
  10. package/assets/weapon-svg/commons/colt_m4a1.svg +1 -0
  11. package/assets/weapon-svg/commons/desert_eagle_mark_xix.svg +1 -0
  12. package/assets/weapon-svg/commons/glock_19.svg +1 -0
  13. package/assets/weapon-svg/commons/hk_mp5a3.svg +1 -0
  14. package/assets/weapon-svg/commons/hk_mp5k.svg +1 -0
  15. package/assets/weapon-svg/commons/mac_10.svg +1 -0
  16. package/assets/weapon-svg/commons/sako_trg_42.svg +1 -0
  17. package/assets/weapon-svg/commons/steyr_aug_a1.svg +1 -0
  18. package/assets/weapon-svg/commons/svd_dragunov.svg +1 -0
  19. package/assets/weapon-svg/commons/utility_knife.svg +1 -0
  20. package/assets/weapon-svg/commons/uzi.svg +1 -0
  21. package/assets/weapon-svg/commons/vz61.svg +1 -0
  22. package/assets/weapon-svg/commons-sources.json +151 -0
  23. package/assets/weapon-svg/credits.html +36 -0
  24. package/assets/weapon-svg/generated/aa_12.svg +1 -0
  25. package/assets/weapon-svg/generated/accuracy_awm.svg +1 -0
  26. package/assets/weapon-svg/generated/ag36.svg +1 -0
  27. package/assets/weapon-svg/generated/ak_12.svg +1 -0
  28. package/assets/weapon-svg/generated/ak_47.svg +1 -0
  29. package/assets/weapon-svg/generated/ak_74.svg +1 -0
  30. package/assets/weapon-svg/generated/akm.svg +1 -0
  31. package/assets/weapon-svg/generated/anti_materiel_50.svg +1 -0
  32. package/assets/weapon-svg/generated/at4.svg +1 -0
  33. package/assets/weapon-svg/generated/axe.svg +1 -0
  34. package/assets/weapon-svg/generated/barrett_m82a1.svg +1 -0
  35. package/assets/weapon-svg/generated/barrett_mrad.svg +1 -0
  36. package/assets/weapon-svg/generated/baseball_bat.svg +1 -0
  37. package/assets/weapon-svg/generated/benelli_m4.svg +1 -0
  38. package/assets/weapon-svg/generated/beretta_92fs.svg +1 -0
  39. package/assets/weapon-svg/generated/blowtorch.svg +1 -0
  40. package/assets/weapon-svg/generated/boito_double_barrel.svg +1 -0
  41. package/assets/weapon-svg/generated/bow_compound.svg +1 -0
  42. package/assets/weapon-svg/generated/browning_m2.svg +1 -0
  43. package/assets/weapon-svg/generated/c4.svg +1 -0
  44. package/assets/weapon-svg/generated/car_fuel_tank.svg +1 -0
  45. package/assets/weapon-svg/generated/carbine_22.svg +1 -0
  46. package/assets/weapon-svg/generated/carl_gustaf_m4.svg +1 -0
  47. package/assets/weapon-svg/generated/cbc_122.svg +1 -0
  48. package/assets/weapon-svg/generated/cbc_7022.svg +1 -0
  49. package/assets/weapon-svg/generated/cbc_pump_military_3_0.svg +1 -0
  50. package/assets/weapon-svg/generated/cheytac_m200.svg +1 -0
  51. package/assets/weapon-svg/generated/claw_hammer.svg +1 -0
  52. package/assets/weapon-svg/generated/claymore.svg +1 -0
  53. package/assets/weapon-svg/generated/colt_m16a2.svg +1 -0
  54. package/assets/weapon-svg/generated/colt_m1911.svg +1 -0
  55. package/assets/weapon-svg/generated/colt_m4a1.svg +1 -0
  56. package/assets/weapon-svg/generated/crossbow.svg +1 -0
  57. package/assets/weapon-svg/generated/crowbar.svg +1 -0
  58. package/assets/weapon-svg/generated/cutting_torch.svg +1 -0
  59. package/assets/weapon-svg/generated/cz_75.svg +1 -0
  60. package/assets/weapon-svg/generated/cz_scorpion_evo_3.svg +1 -0
  61. package/assets/weapon-svg/generated/desert_eagle_mark_xix.svg +1 -0
  62. package/assets/weapon-svg/generated/dynamite.svg +1 -0
  63. package/assets/weapon-svg/generated/extinguisher.svg +1 -0
  64. package/assets/weapon-svg/generated/flamethrower.svg +1 -0
  65. package/assets/weapon-svg/generated/flashbang.svg +1 -0
  66. package/assets/weapon-svg/generated/fn_fal.svg +1 -0
  67. package/assets/weapon-svg/generated/fn_five_seven.svg +1 -0
  68. package/assets/weapon-svg/generated/fn_m249.svg +1 -0
  69. package/assets/weapon-svg/generated/fn_mag.svg +1 -0
  70. package/assets/weapon-svg/generated/fn_minimi.svg +1 -0
  71. package/assets/weapon-svg/generated/fn_minimi_para.svg +1 -0
  72. package/assets/weapon-svg/generated/fn_p90.svg +1 -0
  73. package/assets/weapon-svg/generated/fn_parafal.svg +1 -0
  74. package/assets/weapon-svg/generated/fn_scar_h.svg +1 -0
  75. package/assets/weapon-svg/generated/frag_grenade.svg +1 -0
  76. package/assets/weapon-svg/generated/franchi_spas_12.svg +1 -0
  77. package/assets/weapon-svg/generated/fuel_barrel.svg +1 -0
  78. package/assets/weapon-svg/generated/glock_17.svg +1 -0
  79. package/assets/weapon-svg/generated/glock_18.svg +1 -0
  80. package/assets/weapon-svg/generated/glock_19.svg +1 -0
  81. package/assets/weapon-svg/generated/gp_25.svg +1 -0
  82. package/assets/weapon-svg/generated/hacksaw.svg +1 -0
  83. package/assets/weapon-svg/generated/hammer.svg +1 -0
  84. package/assets/weapon-svg/generated/hk416.svg +1 -0
  85. package/assets/weapon-svg/generated/hk_g36.svg +1 -0
  86. package/assets/weapon-svg/generated/hk_g36c.svg +1 -0
  87. package/assets/weapon-svg/generated/hk_g36k.svg +1 -0
  88. package/assets/weapon-svg/generated/hk_g3a3.svg +1 -0
  89. package/assets/weapon-svg/generated/hk_mp5a3.svg +1 -0
  90. package/assets/weapon-svg/generated/hk_mp5k.svg +1 -0
  91. package/assets/weapon-svg/generated/hk_mp5sd3.svg +1 -0
  92. package/assets/weapon-svg/generated/hk_mp7a1.svg +1 -0
  93. package/assets/weapon-svg/generated/hk_psg_1.svg +1 -0
  94. package/assets/weapon-svg/generated/hk_ump9.svg +1 -0
  95. package/assets/weapon-svg/generated/hk_ump_45.svg +1 -0
  96. package/assets/weapon-svg/generated/hunting_rifle_30_06.svg +1 -0
  97. package/assets/weapon-svg/generated/imbel_ia2.svg +1 -0
  98. package/assets/weapon-svg/generated/improvised_flamethrower.svg +1 -0
  99. package/assets/weapon-svg/generated/kel_tec_ksg.svg +1 -0
  100. package/assets/weapon-svg/generated/knife.svg +1 -0
  101. package/assets/weapon-svg/generated/knights_sr_25_mk11.svg +1 -0
  102. package/assets/weapon-svg/generated/kriss_vector.svg +1 -0
  103. package/assets/weapon-svg/generated/lighter.svg +1 -0
  104. package/assets/weapon-svg/generated/m134.svg +1 -0
  105. package/assets/weapon-svg/generated/m14_ebr.svg +1 -0
  106. package/assets/weapon-svg/generated/m203.svg +1 -0
  107. package/assets/weapon-svg/generated/m24_sws.svg +1 -0
  108. package/assets/weapon-svg/generated/m2_flamethrower.svg +1 -0
  109. package/assets/weapon-svg/generated/m60.svg +1 -0
  110. package/assets/weapon-svg/generated/m72_law.svg +1 -0
  111. package/assets/weapon-svg/generated/m79.svg +1 -0
  112. package/assets/weapon-svg/generated/mac_10.svg +1 -0
  113. package/assets/weapon-svg/generated/machete.svg +1 -0
  114. package/assets/weapon-svg/generated/makarov_pm.svg +1 -0
  115. package/assets/weapon-svg/generated/mg3.svg +1 -0
  116. package/assets/weapon-svg/generated/mini_uzi.svg +1 -0
  117. package/assets/weapon-svg/generated/molotov.svg +1 -0
  118. package/assets/weapon-svg/generated/mosin_nagant_91_30.svg +1 -0
  119. package/assets/weapon-svg/generated/mossberg_500.svg +1 -0
  120. package/assets/weapon-svg/generated/mossberg_500_cruiser.svg +1 -0
  121. package/assets/weapon-svg/generated/pipe_bomb.svg +1 -0
  122. package/assets/weapon-svg/generated/pistol_22.svg +1 -0
  123. package/assets/weapon-svg/generated/pistol_45.svg +1 -0
  124. package/assets/weapon-svg/generated/pistol_9mm.svg +1 -0
  125. package/assets/weapon-svg/generated/pkm.svg +1 -0
  126. package/assets/weapon-svg/generated/pp19_bizon.svg +1 -0
  127. package/assets/weapon-svg/generated/propane_p13.svg +1 -0
  128. package/assets/weapon-svg/generated/pry_bar.svg +1 -0
  129. package/assets/weapon-svg/generated/remington_700.svg +1 -0
  130. package/assets/weapon-svg/generated/remington_700_300wm.svg +1 -0
  131. package/assets/weapon-svg/generated/remington_870.svg +1 -0
  132. package/assets/weapon-svg/generated/revolver_357.svg +1 -0
  133. package/assets/weapon-svg/generated/revolver_38.svg +1 -0
  134. package/assets/weapon-svg/generated/rifle_5_56.svg +1 -0
  135. package/assets/weapon-svg/generated/rifle_7_62x39.svg +1 -0
  136. package/assets/weapon-svg/generated/rifle_bolt_308.svg +1 -0
  137. package/assets/weapon-svg/generated/rossi_puma.svg +1 -0
  138. package/assets/weapon-svg/generated/rpg_7.svg +1 -0
  139. package/assets/weapon-svg/generated/rpk.svg +1 -0
  140. package/assets/weapon-svg/generated/ruger_10_22.svg +1 -0
  141. package/assets/weapon-svg/generated/saiga_12.svg +1 -0
  142. package/assets/weapon-svg/generated/sako_trg_42.svg +1 -0
  143. package/assets/weapon-svg/generated/screwdriver.svg +1 -0
  144. package/assets/weapon-svg/generated/shotgun_double_12.svg +1 -0
  145. package/assets/weapon-svg/generated/shotgun_pump_12.svg +1 -0
  146. package/assets/weapon-svg/generated/shotgun_semi_12.svg +1 -0
  147. package/assets/weapon-svg/generated/sig_mpx.svg +1 -0
  148. package/assets/weapon-svg/generated/sig_sauer_p226.svg +1 -0
  149. package/assets/weapon-svg/generated/sks.svg +1 -0
  150. package/assets/weapon-svg/generated/sledgehammer.svg +1 -0
  151. package/assets/weapon-svg/generated/smg_9mm.svg +1 -0
  152. package/assets/weapon-svg/generated/sniper_338.svg +1 -0
  153. package/assets/weapon-svg/generated/steyr_aug_a1.svg +1 -0
  154. package/assets/weapon-svg/generated/steyr_ssg_69.svg +1 -0
  155. package/assets/weapon-svg/generated/svd_dragunov.svg +1 -0
  156. package/assets/weapon-svg/generated/sw_686.svg +1 -0
  157. package/assets/weapon-svg/generated/sw_model_29.svg +1 -0
  158. package/assets/weapon-svg/generated/taurus_82.svg +1 -0
  159. package/assets/weapon-svg/generated/taurus_g2c.svg +1 -0
  160. package/assets/weapon-svg/generated/taurus_pt100.svg +1 -0
  161. package/assets/weapon-svg/generated/taurus_smt9.svg +1 -0
  162. package/assets/weapon-svg/generated/taurus_t4.svg +1 -0
  163. package/assets/weapon-svg/generated/taurus_t4_civil.svg +1 -0
  164. package/assets/weapon-svg/generated/taurus_th380.svg +1 -0
  165. package/assets/weapon-svg/generated/taurus_ts9.svg +1 -0
  166. package/assets/weapon-svg/generated/thompson_m1a1.svg +1 -0
  167. package/assets/weapon-svg/generated/utility_knife.svg +1 -0
  168. package/assets/weapon-svg/generated/uzi.svg +1 -0
  169. package/assets/weapon-svg/generated/vz61.svg +1 -0
  170. package/assets/weapon-svg/generated/winchester_1894.svg +1 -0
  171. package/assets/weapon-svg/generated/wrench.svg +1 -0
  172. package/assets/weapon-svg/manifest.json +669 -0
  173. package/dist/index.d.ts +275 -96
  174. package/dist/index.global.js +12761 -4470
  175. package/dist/index.global.js.map +1 -1
  176. package/dist/index.js +2581 -309
  177. package/dist/index.js.map +1 -1
  178. package/package.json +9 -7
  179. package/LICENSE +0 -21
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { HostTool, HostEvent, TestableModule, AreaPlacement, TestableItem, DestructibleSpec, ToolClipSet } from '@adatechnology/game-contracts';
2
- import { CaliberDef, ReloadStageId, WeaponEvent, Arsenal, ExplosiveDef, WeaponDef, CartridgeDims, CaseType, ReloadFamily } from '@adatechnology/game-weapons';
2
+ import { CaliberDef, ReloadStageId, WeaponEvent, MountKind, AttachmentDef, FittedAttachment, Arsenal, ExplosiveDef, WeaponDef, CartridgeDims, CaseType, ReloadFamily } from '@adatechnology/game-weapons';
3
3
  import * as THREE_NS from 'three';
4
4
 
5
5
  /** One sound of the game: [lowpass cutoff Hz, gain, seconds]. Literal from the `P` table of `sfx` in the game (jogo.js L62101-L62104). */
@@ -136,7 +136,7 @@ type SoundStep =
136
136
  readonly gain: number;
137
137
  readonly frequency: number;
138
138
  };
139
- type MechanicalSoundId = ReloadStageId | 'dry_fire' | 'misfire' | 'feed' | 'cycle' | 'mode' | 'safety_on' | 'safety_off' | 'jam' | 'clear_start' | 'clear_end';
139
+ type MechanicalSoundId = ReloadStageId | 'dry_fire' | 'misfire' | 'feed' | 'cycle' | 'mode' | 'safety_on' | 'safety_off' | 'jam' | 'clear_start' | 'clear_end' | 'stock_fold' | 'light_click' | 'attach';
140
140
  /**
141
141
  * 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
142
142
  * reload tick are the game's `vazio` and `recarga` classes (jogo.js L62101-L62104; played at L68644-L68662); the gallery (sources/armas-itens__galeria-3d-arsenal.js)
@@ -186,104 +186,15 @@ interface WeaponAudio {
186
186
  }
187
187
  declare function createWeaponAudio(volume?: number, options?: WeaponAudioOptions): WeaponAudio;
188
188
 
189
- /** What the bench turns on or off in the presentation of the weapon: the ejected casings, the dropped magazines and the muzzle flash. */
189
+ /** 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. */
190
190
  interface FxLayers {
191
191
  casings: boolean;
192
192
  magazines: boolean;
193
193
  muzzleFlash: boolean;
194
+ attachments: boolean;
195
+ beams: boolean;
194
196
  }
195
197
 
196
- interface WeaponFxOptions {
197
- THREE: typeof THREE_NS;
198
- scene: THREE_NS.Scene;
199
- camera: THREE_NS.Camera;
200
- arsenal: Arsenal;
201
- /** Height things rest on at (x, z): casings and magazines land there. */
202
- groundAt: (x: number, z: number) => number;
203
- /** Sounds (`createWeaponAudio`); null or absent: silent. */
204
- audio?: WeaponAudio | null;
205
- /** Seed of the scatter of the effects of the gallery models. */
206
- seed?: number;
207
- /** The tool as it is now (barrel heat, fuel burning). */
208
- tool?: () => HostTool;
209
- /** Wear of the weapon: `new`, `used`, `worn` or `rusty`. */
210
- condition?: string;
211
- /** What is drawn: read at the moment of each event, so the bench can change it live. */
212
- layers?: FxLayers;
213
- /** Metres between the shooter and the listener, for the distance muffling of the shot sound (default 0). */
214
- soundDistance?: () => number;
215
- }
216
-
217
- /** The weapon in the hands, its fire and reload motion, ejected casings and dropped magazines, and their sounds. */
218
- interface WeaponFx {
219
- /** Feed every tool event of the host, with the tool as it is after the event. */
220
- handle(event: HostEvent, tool: HostTool): void;
221
- update(dt: number): void;
222
- /** Dresses the weapon for its wear (`new`, `used`, `worn`, `rusty`); the gallery models show it in their metal. */
223
- setCondition(condition: string): void;
224
- /** What is drawn (casings, magazines, muzzle flash): change a field and the next event follows it. */
225
- readonly layers: FxLayers;
226
- /** Weapon shown in the hands, or null. */
227
- readonly inHand: string | null;
228
- /** Casings and magazines currently on the floor or in the air. */
229
- readonly casings: number;
230
- readonly magazines: number;
231
- dispose(): void;
232
- }
233
- /**
234
- * 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
235
- * (fire, cycle, jam, clear, safety, the seven reloads); the generic archetypes keep their low-poly prop.
236
- */
237
- declare function createWeaponFx(options: WeaponFxOptions): WeaponFx;
238
-
239
- interface WeaponsTestModuleOptions {
240
- /** `en` or `pt-BR` (default). */
241
- locale?: string;
242
- /** The arsenal to lay out (default `createArsenal` with the locale). */
243
- arsenal?: Arsenal;
244
- /** Play sounds (default true; silent anyway where there is no AudioContext). */
245
- sound?: boolean;
246
- /** Wear of the weapon in the hands, which the gallery models show in their metal: `new` (default), `used`, `worn` or `rusty`. */
247
- condition?: string;
248
- /** Seed of the scatter of casings and smoke (default 1). */
249
- seed?: number;
250
- }
251
- /** Prefix of the item ids of the weapon props (`weapon_pistol_9mm`). */
252
- declare const WEAPON_ITEM_PREFIX = "weapon_";
253
- declare const COUNTER_ITEM_ID = "counter_weapons";
254
- /** 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. */
255
- declare function weaponsLayout(weaponItemIds: string[], pitchOf?: (itemId: string) => number): AreaPlacement[];
256
- /**
257
- * 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
258
- * press H to equip it), targets at shooting distance, and, through `attach`, the weapon in the hands with its fire and reload motion,
259
- * ejected casings, dropped magazines and sounds, driven by the host's tool events.
260
- */
261
- declare function createWeaponsTestModule(options?: WeaponsTestModuleOptions): TestableModule & {
262
- readonly audio: WeaponAudio | null;
263
- readonly fx: WeaponFx | null;
264
- };
265
-
266
- /** Prefix of the item ids of the explosives that sit in the world (`world_fuel_barrel`). */
267
- declare const WORLD_EXPLOSIVE_PREFIX = "world_";
268
- /** The ids of the explosives of the arsenal that the area puts in the world. */
269
- declare const WORLD_EXPLOSIVE_IDS: readonly string[];
270
- /** An explosive of the arsenal standing in the world: it goes off by a bullet, fire or another blast, after the delay its `chain` gives. */
271
- declare const worldExplosiveItem: (def: ExplosiveDef, name: string) => TestableItem | undefined;
272
-
273
- /** A low-poly prop: its destruction spec (box parts only) and one colour per part. */
274
- interface WeaponProp {
275
- spec: DestructibleSpec;
276
- colors: Record<string, number>;
277
- }
278
- /** Body actions of the arsenal: nothing to hold or lay on a counter. */
279
- declare const BODY_ACTIONS: ReadonlySet<string>;
280
- /** The prop of a weapon: low-poly parts by category, the real mass of the weapon spread over them. */
281
- declare function weaponProp(def: Pick<WeaponDef, 'id' | 'category' | 'mass'>, name?: string): WeaponProp;
282
- /** One mesh per box part, named after the part (what destruction renderers bind to), in a group with its origin on the floor. */
283
- declare function buildProp(THREE: typeof THREE_NS, prop: WeaponProp): THREE_NS.Group;
284
- /** The model of a weapon for the hands or a shelf: the same prop the counters show. */
285
- declare function buildWeaponModel(THREE: typeof THREE_NS, def: Pick<WeaponDef, 'id' | 'category' | 'mass'>): THREE_NS.Group;
286
-
287
198
  /** How the gallery builders describe a weapon: the short keys of `data/models.json` (the page's own option names), all optional. */
288
199
  interface ModelOptions {
289
200
  /** Total length and barrel length in mm, and the calibre text, as the weapons table gives them. */
@@ -351,6 +262,26 @@ interface ModelOptions {
351
262
  /** Launcher type: `rpg`, `m72`, `at4`, `carl`, `flame`, `flameDIY`. */
352
263
  lt?: string;
353
264
  }
265
+ /**
266
+ * 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.
267
+ * Written by the rifle and the M134 builders; the others get theirs measured from the model (`deriveFrames`).
268
+ */
269
+ interface ModelFrames {
270
+ length: number;
271
+ barrelY: number;
272
+ barrelRadius: number;
273
+ receiverStart: number;
274
+ receiverEnd: number;
275
+ receiverHeight: number;
276
+ receiverWidth: number;
277
+ handguardEnd: number;
278
+ magazineX: number;
279
+ gripX: number;
280
+ /** The top rail is drawn (an optic sits on it without an adapter). */
281
+ hasRail: boolean;
282
+ /** 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. */
283
+ underbarrel?: readonly [number, number];
284
+ }
354
285
  /** The moving mechanism of a model, which picks its fire, reload and clear motion. */
355
286
  type ModelFamily = 'pistol' | 'revolver' | 'rifle' | 'semiint' | 'semi12' | 'p90' | 'belt' | 'pump' | 'lever' | 'bolt' | 'boltmag' | 'break' | 'rocket' | 'flame';
356
287
  /** The named parts a model exposes to the animation: pivots and marks inside the model, never copies. */
@@ -395,11 +326,29 @@ interface ModelParts {
395
326
  roundRest?: number;
396
327
  makeRound?: () => THREE_NS.Object3D;
397
328
  gauge?: THREE_NS.Object3D;
329
+ /** Where the accessories go (see `ModelFrames`). */
330
+ frames?: ModelFrames;
331
+ /** The meshes of the stock the builder drew, in the order it drew them: `rigStock` moves them into one pivot. */
332
+ stockMeshes?: THREE_NS.Object3D[];
333
+ /** The stock pivot `rigStock` made, and how it moves. */
334
+ stock?: THREE_NS.Object3D;
335
+ stockMove?: StockMove;
336
+ /** The meshes of each part that ships on the weapon, by accessory id (`red_dot`, `bipod`, `muzzle_brake`): taking the accessory off hides them. */
337
+ fittings?: Record<string, THREE_NS.Object3D[]>;
338
+ /** The pivot a launcher under the barrel sits in (made by `rigUnderbarrel`), and its muzzle mark once one is fitted. */
339
+ ugl?: THREE_NS.Object3D;
340
+ uglMuzzle?: THREE_NS.Object3D;
341
+ }
342
+ /** 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). */
343
+ interface StockMove {
344
+ kind: 'fold' | 'retract';
345
+ axis: 'x' | 'y' | 'z';
346
+ travel: number;
398
347
  }
399
348
 
400
349
  /** One weapon of the gallery as `data/models.json` keeps it: the builder, the measures in mm and the builder's options. */
401
350
  interface ModelEntry {
402
- readonly builder: 'pistol' | 'revolver' | 'rifle' | 'bullpup' | 'p90' | 'break' | 'm2' | 'launcher';
351
+ readonly builder: 'pistol' | 'revolver' | 'rifle' | 'bullpup' | 'p90' | 'break' | 'm2' | 'm134' | 'launcher';
403
352
  readonly caliber: string;
404
353
  readonly length: number;
405
354
  readonly barrel: number;
@@ -488,6 +437,190 @@ interface ModelKit {
488
437
  /** One kit per three.js namespace: the materials and the geometry cache are shared by every model built with it. */
489
438
  declare function modelKit(THREE: Three): ModelKit;
490
439
 
440
+ type Vec3 = [number, number, number];
441
+ /** The shape of a model that carries its `inner` and `root` as `buildWeaponModelById` makes them. */
442
+ interface FramedModel {
443
+ readonly root: THREE_NS.Group;
444
+ readonly inner: THREE_NS.Group;
445
+ readonly parts: ModelParts;
446
+ }
447
+ /** 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. */
448
+ interface MountFrame {
449
+ readonly mount: MountKind;
450
+ readonly position: Vec3;
451
+ /** The other end, for what stretches between two points (a sling between its swivels). */
452
+ readonly secondary?: Vec3;
453
+ readonly barrelRadius: number;
454
+ readonly receiverWidth: number;
455
+ readonly receiverHeight: number;
456
+ /** The top rail is drawn: an optic needs no adapter. */
457
+ readonly hasRail: boolean;
458
+ /** The sign of z for a side rail: left is negative, right is positive (z is to the right of the weapon). */
459
+ readonly side: -1 | 0 | 1;
460
+ }
461
+ /**
462
+ * 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.
463
+ * The numbers are in the space of `inner`, like the ones the rifle builder writes.
464
+ */
465
+ declare function deriveFrames(THREE: typeof THREE_NS, model: FramedModel): ModelFrames;
466
+ /** The frame of a mount of the model, or undefined for the mounts nothing is drawn on (`stock`, `barrel`). */
467
+ declare function mountFrame(model: FramedModel, mount: MountKind): MountFrame | undefined;
468
+
469
+ /** 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. */
470
+ type LaserRaycast = (origin: THREE_NS.Vector3, direction: THREE_NS.Vector3, maxDistance: number) => number | null;
471
+ /** 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. */
472
+ interface AttachmentBuildContext {
473
+ readonly kit: ModelKit;
474
+ readonly model: WeaponModel;
475
+ readonly attachment: AttachmentDef;
476
+ readonly fitted: FittedAttachment;
477
+ readonly frame: MountFrame;
478
+ readonly raycast: LaserRaycast | undefined;
479
+ /** The meshes the magazine pivot had before any accessory (a drum or an extension replaces or extends them). */
480
+ readonly factoryMagazine: readonly THREE_NS.Object3D[];
481
+ /** The pivot of the launcher under the barrel, which the reload clip slides (only on a weapon with a place for one). */
482
+ readonly slide: THREE_NS.Object3D | undefined;
483
+ }
484
+ /** What a builder makes: the object (its origin on the frame), and what the rig needs to know about it. */
485
+ interface AttachmentModel {
486
+ readonly object: THREE_NS.Object3D;
487
+ /** Where the object hangs: the wrapper (default), the magazine pivot (it moves with the magazine) or the sliding pivot of the launcher. */
488
+ readonly hangsFrom?: 'root' | 'magazine';
489
+ /** Parts of the weapon that are not drawn while this one is on (a drum hides the magazine it replaces). */
490
+ readonly hides?: readonly THREE_NS.Object3D[];
491
+ /** How far forward the muzzle moves (a suppressor): the flash and the smoke come out of its end. */
492
+ readonly muzzleOffset?: number;
493
+ /** A launcher's muzzle mark, which the shot clip flashes. */
494
+ readonly muzzle?: THREE_NS.Object3D;
495
+ /** A light or laser turned on or off. */
496
+ setOn?(on: boolean): void;
497
+ /** Every frame, while the weapon is in the hands (the laser measures how far its beam goes). */
498
+ update?(): void;
499
+ dispose?(): void;
500
+ }
501
+ type AttachmentModelBuilder = (context: AttachmentBuildContext) => AttachmentModel | THREE_NS.Object3D | null;
502
+ /** Builders by the `model` id of the accessory (`AttachmentDef.model`). A game replaces or adds one with `attachmentModels` of the weapons module. */
503
+ type AttachmentModelRegistry = Readonly<Record<string, AttachmentModelBuilder>>;
504
+
505
+ interface WeaponFxOptions {
506
+ THREE: typeof THREE_NS;
507
+ scene: THREE_NS.Scene;
508
+ camera: THREE_NS.Camera;
509
+ arsenal: Arsenal;
510
+ /** Height things rest on at (x, z): casings and magazines land there. */
511
+ groundAt: (x: number, z: number) => number;
512
+ /** Sounds (`createWeaponAudio`); null or absent: silent. */
513
+ audio?: WeaponAudio | null;
514
+ /** Seed of the scatter of the effects of the gallery models. */
515
+ seed?: number;
516
+ /** The tool as it is now (barrel heat, fuel burning). */
517
+ tool?: () => HostTool;
518
+ /** Wear of the weapon: `new`, `used`, `worn` or `rusty`. */
519
+ condition?: string;
520
+ /** What is drawn: read at the moment of each event, so the bench can change it live. */
521
+ layers?: FxLayers;
522
+ /** Metres between the shooter and the listener, for the distance muffling of the shot sound (default 0). */
523
+ soundDistance?: () => number;
524
+ /** Builders of accessory models that replace or add to the ones the kit ships (by the `model` of the accessory). */
525
+ attachmentModels?: AttachmentModelRegistry;
526
+ /** 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. */
527
+ raycast?: LaserRaycast;
528
+ }
529
+
530
+ /** The weapon in the hands, its fire and reload motion, ejected casings and dropped magazines, and their sounds. */
531
+ interface WeaponFx {
532
+ /** Feed every tool event of the host, with the tool as it is after the event. */
533
+ handle(event: HostEvent, tool: HostTool): void;
534
+ update(dt: number): void;
535
+ /** Dresses the weapon for its wear (`new`, `used`, `worn`, `rusty`); the gallery models show it in their metal. */
536
+ setCondition(condition: string): void;
537
+ /** What is drawn (casings, magazines, muzzle flash): change a field and the next event follows it. */
538
+ readonly layers: FxLayers;
539
+ /** Weapon shown in the hands, or null. */
540
+ readonly inHand: string | null;
541
+ /** Casings and magazines currently on the floor or in the air. */
542
+ readonly casings: number;
543
+ readonly magazines: number;
544
+ dispose(): void;
545
+ }
546
+ /**
547
+ * 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
548
+ * (fire, cycle, jam, clear, safety, the seven reloads); the generic archetypes keep their low-poly prop.
549
+ */
550
+ declare function createWeaponFx(options: WeaponFxOptions): WeaponFx;
551
+
552
+ interface WeaponsTestModuleOptions {
553
+ /** `en` or `pt-BR` (default). */
554
+ locale?: string;
555
+ /** The arsenal to lay out (default `createArsenal` with the locale). */
556
+ arsenal?: Arsenal;
557
+ /** Play sounds (default true; silent anyway where there is no AudioContext). */
558
+ sound?: boolean;
559
+ /** Wear of the weapon in the hands, which the gallery models show in their metal: `new` (default), `used`, `worn` or `rusty`. */
560
+ condition?: string;
561
+ /** Seed of the scatter of casings and smoke (default 1). */
562
+ seed?: number;
563
+ /** Builders of accessory models that replace or add to the ones the kit ships (by the `model` of the accessory). */
564
+ attachmentModels?: AttachmentModelRegistry;
565
+ /** 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. */
566
+ thumbnailBase?: string | false;
567
+ }
568
+ /** Prefix of the item ids of the weapon props (`weapon_pistol_9mm`). */
569
+ declare const WEAPON_ITEM_PREFIX = "weapon_";
570
+ declare const COUNTER_ITEM_ID = "counter_weapons";
571
+ declare const MOUNTED_M134_ITEM_ID = "m134_tripod";
572
+ /** 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. */
573
+ declare function weaponsLayout(weaponItemIds: string[], pitchOf?: (itemId: string) => number): AreaPlacement[];
574
+ /**
575
+ * 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
576
+ * press H to equip it), targets at shooting distance, and, through `attach`, the weapon in the hands with its fire and reload motion,
577
+ * ejected casings, dropped magazines and sounds, driven by the host's tool events.
578
+ */
579
+ declare function createWeaponsTestModule(options?: WeaponsTestModuleOptions): TestableModule & {
580
+ readonly audio: WeaponAudio | null;
581
+ readonly fx: WeaponFx | null;
582
+ };
583
+
584
+ /** Where a thumbnail came from: the model of the kit (`generated`) or a freely licensed drawing of the real weapon (`commons`, with its author and licence). */
585
+ interface WeaponThumbnailEntry {
586
+ readonly source: 'generated' | 'commons';
587
+ /** Path of the SVG inside `assets/weapon-svg`. */
588
+ readonly file: string;
589
+ readonly author?: string;
590
+ readonly license?: string;
591
+ readonly licenseUrl?: string;
592
+ readonly page?: string;
593
+ }
594
+ /** Every weapon (and world explosive) that has a thumbnail, by weapon id: the Commons file when one was kept, else the one generated from the 3D model. */
595
+ declare const WEAPON_THUMBNAILS: Readonly<Record<string, WeaponThumbnailEntry>>;
596
+ /** `Author, licence` of a Commons thumbnail (the credit its licence asks for), or undefined for a generated one. */
597
+ declare function weaponThumbnailCredit(id: string): string | undefined;
598
+ /** The folder of the thumbnails relative to the page that shows them; the site build copies `assets/weapon-svg` there. */
599
+ declare const DEFAULT_THUMBNAIL_BASE = "weapon-svg/";
600
+ /** The URL of a weapon's thumbnail under `base` (which ends with a slash), or undefined when it has none. */
601
+ declare function weaponThumbnailUrl(id: string, base?: string): string | undefined;
602
+
603
+ /** Prefix of the item ids of the explosives that sit in the world (`world_fuel_barrel`). */
604
+ declare const WORLD_EXPLOSIVE_PREFIX = "world_";
605
+ /** The ids of the explosives of the arsenal that the area puts in the world. */
606
+ declare const WORLD_EXPLOSIVE_IDS: readonly string[];
607
+ /** An explosive of the arsenal standing in the world: it goes off by a bullet, fire or another blast, after the delay its `chain` gives. */
608
+ declare const worldExplosiveItem: (def: ExplosiveDef, name: string) => TestableItem | undefined;
609
+
610
+ /** A low-poly prop: its destruction spec (box parts only) and one colour per part. */
611
+ interface WeaponProp {
612
+ spec: DestructibleSpec;
613
+ colors: Record<string, number>;
614
+ }
615
+ /** Body actions of the arsenal: nothing to hold or lay on a counter. */
616
+ declare const BODY_ACTIONS: ReadonlySet<string>;
617
+ /** The prop of a weapon: low-poly parts by category, the real mass of the weapon spread over them. */
618
+ declare function weaponProp(def: Pick<WeaponDef, 'id' | 'category' | 'mass'>, name?: string): WeaponProp;
619
+ /** One mesh per box part, named after the part (what destruction renderers bind to), in a group with its origin on the floor. */
620
+ declare function buildProp(THREE: typeof THREE_NS, prop: WeaponProp): THREE_NS.Group;
621
+ /** The model of a weapon for the hands or a shelf: the same prop the counters show. */
622
+ declare function buildWeaponModel(THREE: typeof THREE_NS, def: Pick<WeaponDef, 'id' | 'category' | 'mass'>): THREE_NS.Group;
623
+
491
624
  /** The shapes the gallery draws: rimfire, straight rimless (`p`), straight rimmed (`rimp`), bottleneck rimless (`r`), bottleneck rimmed (`rr`) and shotgun shell. */
492
625
  type CartridgeShape = 'shell' | 'rim' | 'p' | 'rimp' | 'r' | 'rr';
493
626
  /** The gallery's cartridge type of a calibre, from its case type, rim and dimensions. */
@@ -523,4 +656,50 @@ interface ClipContext {
523
656
  /** Every clip a weapon model brings, by the ids `toolAnimationStep` asks for (`shot`, `cycle`, `reload`, `reload_empty`, `fault_<id>`, `clear_<id>`...). */
524
657
  declare function buildToolClips(context: ClipContext): ToolClipSet;
525
658
 
526
- export { ARCHETYPE_MODELS, BODY_ACTIONS, CLASS_REFERENCE_ENERGY, COUNTER_ITEM_ID, type CartridgeShape, type ClipContext, DEFAULT_ENERGY_CURVE, type DistanceCurve, type EnergyCurve, type FxLayers, GAME_DISTANCE_CURVE, GAME_SOUND_CLASSES, MECHANICAL_SOUNDS, MODEL_ENTRIES, type MechanicalSoundId, type ModelEntry, type ModelFamily, type ModelKit, type ModelMaterials, type ModelOptions, type ModelParts, type ShotExtras, type ShotSound, type ShotSoundClass, type ShotSoundInput, type ShotSoundOptions, type SoundClassDef, type SoundStep, WEAPON_ITEM_PREFIX, WORLD_EXPLOSIVE_IDS, WORLD_EXPLOSIVE_PREFIX, type WeaponAudio, type WeaponAudioOptions, type WeaponFx, type WeaponFxOptions, type WeaponModel, type WeaponProp, type WeaponsTestModuleOptions, applyCondition, buildCartridge, buildCasing, buildProp, buildRound, buildToolClips, buildWeaponModel, buildWeaponModelById, cartridgeShape, computeShotSound, createWeaponAudio, createWeaponFx, createWeaponsTestModule, hasWeaponModel, mechanicalSoundOf, modelKit, partRegistry, weaponProp, weaponsLayout, worldExplosiveItem };
659
+ interface FitAttachmentOptions {
660
+ /** The accessories of the game by id: where each gets its `model`, size and light or laser. */
661
+ readonly catalogue: ReadonlyMap<string, AttachmentDef>;
662
+ /** Builders that replace or add to the ones the kit ships (see `ATTACHMENT_MODELS`). */
663
+ readonly overrides?: AttachmentModelRegistry;
664
+ /** How far the laser beam goes, asked every frame. */
665
+ readonly raycast?: LaserRaycast;
666
+ /** Asked every frame: false hides the models of the accessories the rig drew (the bench layer). */
667
+ readonly isDrawn?: () => boolean;
668
+ /** Asked every frame: false puts the light and laser out whatever they are set to (the bench layer for the beams). */
669
+ readonly areBeamsOn?: () => boolean;
670
+ }
671
+ /** The accessories drawn on one model: it follows the list of fitted parts. */
672
+ interface AttachmentRig {
673
+ /** Puts the models of what is fitted on the weapon and takes the others off: shows or hides what ships on it, switches the lights and lasers. */
674
+ sync(fitted: readonly FittedAttachment[]): void;
675
+ /** Call every frame. */
676
+ update(): void;
677
+ /** Ids of the accessories that have a model on the weapon now. */
678
+ readonly drawn: readonly string[];
679
+ dispose(): void;
680
+ }
681
+ /**
682
+ * Draws the accessories of `fitted` on the model: the ones the builder drew with the weapon (`parts.fittings`) show or hide with the list, the others are built by the registry
683
+ * (`overrides` over `ATTACHMENT_MODELS`) at the frame of their mount and hang from the wrapper (not from `inner`, whose stretch to the real length would stretch them).
684
+ */
685
+ declare function fitAttachmentModels(model: WeaponModel, fitted: readonly FittedAttachment[], kit: ModelKit, options: FitAttachmentOptions): AttachmentRig;
686
+
687
+ /**
688
+ * The model of each accessory by `AttachmentDef.model`. The ports of the gallery (optics, bipod, brakes, drum, belt box, rail) draw what the page draws; the others are creations of the
689
+ * kit. Accessories without a model (the barrel swaps, the integral optics the weapon already draws) are simply not drawn.
690
+ */
691
+ declare const ATTACHMENT_MODELS: AttachmentModelRegistry;
692
+
693
+ /**
694
+ * After the model is built: when the weapon has a place for a launcher under the barrel, adds the empty pivot `ugl` there. The reload clip slides it (the tube of the launcher is drawn
695
+ * inside it when one is fitted); done after the build so that the model the golden hashes is the one the builder made.
696
+ */
697
+ declare function rigUnderbarrel(THREE: typeof THREE_NS, model: WeaponModel, def: Pick<WeaponDef, 'mounts'>): void;
698
+
699
+ /**
700
+ * After the model is built: puts the stock the builder drew into one pivot named `stock`, so that the clips can fold it (a half turn about the side of the rule's `foldAxis`)
701
+ * or slide it in (`dimensions.length - lengthCollapsed`). Done after the build so that the model the golden hashes is the one the builder made. A weapon whose stock does not move is left alone.
702
+ */
703
+ declare function rigStock(THREE: typeof THREE_NS, model: WeaponModel, def: Pick<WeaponDef, 'stock' | 'dimensions'>): void;
704
+
705
+ export { ARCHETYPE_MODELS, ATTACHMENT_MODELS, type AttachmentBuildContext, type AttachmentModel, type AttachmentModelBuilder, type AttachmentModelRegistry, type AttachmentRig, BODY_ACTIONS, CLASS_REFERENCE_ENERGY, COUNTER_ITEM_ID, type CartridgeShape, type ClipContext, DEFAULT_ENERGY_CURVE, DEFAULT_THUMBNAIL_BASE, type DistanceCurve, type EnergyCurve, type FitAttachmentOptions, type FxLayers, GAME_DISTANCE_CURVE, GAME_SOUND_CLASSES, type LaserRaycast, MECHANICAL_SOUNDS, MODEL_ENTRIES, MOUNTED_M134_ITEM_ID, type MechanicalSoundId, type ModelEntry, type ModelFamily, type ModelKit, type ModelMaterials, type ModelOptions, type ModelParts, type MountFrame, type ShotExtras, type ShotSound, type ShotSoundClass, type ShotSoundInput, type ShotSoundOptions, type SoundClassDef, type SoundStep, WEAPON_ITEM_PREFIX, WEAPON_THUMBNAILS, WORLD_EXPLOSIVE_IDS, WORLD_EXPLOSIVE_PREFIX, type WeaponAudio, type WeaponAudioOptions, type WeaponFx, type WeaponFxOptions, type WeaponModel, type WeaponProp, type WeaponThumbnailEntry, type WeaponsTestModuleOptions, applyCondition, buildCartridge, buildCasing, buildProp, buildRound, buildToolClips, buildWeaponModel, buildWeaponModelById, cartridgeShape, computeShotSound, createWeaponAudio, createWeaponFx, createWeaponsTestModule, deriveFrames, fitAttachmentModels, hasWeaponModel, mechanicalSoundOf, modelKit, mountFrame, partRegistry, rigStock, rigUnderbarrel, weaponProp, weaponThumbnailCredit, weaponThumbnailUrl, weaponsLayout, worldExplosiveItem };