@adatechnology/game-weapons-three 0.18.0 → 0.19.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.
@@ -1874,8 +1874,8 @@ var models_default = {
1874
1874
  h: 0.04,
1875
1875
  gl: 0.125,
1876
1876
  deagle: 1,
1877
- steel: 1,
1878
- rel: 1.8
1877
+ rel: 1.8,
1878
+ chrome: 1
1879
1879
  }
1880
1880
  },
1881
1881
  taurus_82: {
@@ -2202,7 +2202,7 @@ var models_default = {
2202
2202
  barrel: 415,
2203
2203
  options: {
2204
2204
  wood: 1,
2205
- stock: "wood",
2205
+ stock: "ak",
2206
2206
  mag: "curved",
2207
2207
  hg: "wood",
2208
2208
  hgFrac: 0.42,
@@ -2212,7 +2212,8 @@ var models_default = {
2212
2212
  rod: 1,
2213
2213
  bayo: 1,
2214
2214
  rpm: 600,
2215
- rel: 0.4
2215
+ rel: 0.4,
2216
+ kalashnikov: 1
2216
2217
  }
2217
2218
  },
2218
2219
  akm: {
@@ -2222,7 +2223,7 @@ var models_default = {
2222
2223
  barrel: 415,
2223
2224
  options: {
2224
2225
  wood: 1,
2225
- stock: "wood",
2226
+ stock: "ak",
2226
2227
  mag: "curved",
2227
2228
  hg: "wood",
2228
2229
  hgFrac: 0.42,
@@ -2232,7 +2233,8 @@ var models_default = {
2232
2233
  rod: 1,
2233
2234
  rpm: 600,
2234
2235
  magMat: "bakelite",
2235
- rel: 0.45
2236
+ rel: 0.45,
2237
+ kalashnikov: 1
2236
2238
  }
2237
2239
  },
2238
2240
  ak_74: {
@@ -2241,7 +2243,7 @@ var models_default = {
2241
2243
  length: 943,
2242
2244
  barrel: 415,
2243
2245
  options: {
2244
- stock: "fixed",
2246
+ stock: "ak",
2245
2247
  mag: "curved",
2246
2248
  hg: "poly",
2247
2249
  hgFrac: 0.42,
@@ -2251,7 +2253,9 @@ var models_default = {
2251
2253
  ak: 1,
2252
2254
  rod: 1,
2253
2255
  rpm: 650,
2254
- magMat: "bakelite"
2256
+ magMat: "bakelite",
2257
+ kalashnikov: 1,
2258
+ wood: 1
2255
2259
  }
2256
2260
  },
2257
2261
  ak_12: {
@@ -2446,7 +2450,7 @@ var models_default = {
2446
2450
  barrel: 620,
2447
2451
  options: {
2448
2452
  wood: 1,
2449
- stock: "skeleton",
2453
+ stock: "svd",
2450
2454
  stockLen: 0.32,
2451
2455
  mag: "box",
2452
2456
  curve: 0.09,
@@ -2456,7 +2460,8 @@ var models_default = {
2456
2460
  scope: 4,
2457
2461
  brake: 1,
2458
2462
  ak: 1,
2459
- charge: 1
2463
+ charge: 1,
2464
+ svd: 1
2460
2465
  }
2461
2466
  },
2462
2467
  fn_scar_h: {
@@ -2521,7 +2526,7 @@ var models_default = {
2521
2526
  barrel: 650,
2522
2527
  options: {
2523
2528
  olive: 1,
2524
- stock: "trad",
2529
+ stock: "sporter",
2525
2530
  mag: "internal",
2526
2531
  scope: 3,
2527
2532
  bolt: 1,
@@ -2577,7 +2582,7 @@ var models_default = {
2577
2582
  barrel: 610,
2578
2583
  options: {
2579
2584
  wood: 1,
2580
- stock: "trad",
2585
+ stock: "sporter",
2581
2586
  mag: "internal",
2582
2587
  scope: 3,
2583
2588
  bolt: 1,
@@ -2591,7 +2596,7 @@ var models_default = {
2591
2596
  barrel: 610,
2592
2597
  options: {
2593
2598
  olive: 1,
2594
- stock: "trad",
2599
+ stock: "sporter",
2595
2600
  mag: "internal",
2596
2601
  scope: 3,
2597
2602
  bolt: 1,
@@ -2755,7 +2760,7 @@ var models_default = {
2755
2760
  barrel: 560,
2756
2761
  options: {
2757
2762
  wood: 1,
2758
- stock: "trad",
2763
+ stock: "sporter",
2759
2764
  mag: "internal",
2760
2765
  scope: 3,
2761
2766
  bolt: 1,
@@ -2884,13 +2889,12 @@ var models_default = {
2884
2889
  barrel: 610,
2885
2890
  options: {
2886
2891
  wood: 1,
2887
- stock: "trad",
2892
+ stock: "sporter",
2888
2893
  mag: "internal",
2889
2894
  scope: 3,
2890
2895
  bolt: 1,
2891
2896
  round: 1
2892
- },
2893
- variantOf: "remington_700"
2897
+ }
2894
2898
  },
2895
2899
  hk_mp5sd3: {
2896
2900
  builder: "rifle",
@@ -3187,7 +3191,7 @@ var models_default = {
3187
3191
  barrel: 590,
3188
3192
  options: {
3189
3193
  wood: 1,
3190
- stock: "wood",
3194
+ stock: "ak",
3191
3195
  mag: "curved",
3192
3196
  hg: "wood",
3193
3197
  hgFrac: 0.42,
@@ -3199,9 +3203,9 @@ var models_default = {
3199
3203
  rpm: 600,
3200
3204
  rel: 0.4,
3201
3205
  bipod: 1,
3202
- magLen: 1.4
3203
- },
3204
- variantOf: "ak_47"
3206
+ magLen: 1.4,
3207
+ kalashnikov: 1
3208
+ }
3205
3209
  },
3206
3210
  sig_mpx: {
3207
3211
  builder: "rifle",
@@ -3301,9 +3305,9 @@ var models_default = {
3301
3305
  rod: 1,
3302
3306
  rpm: 700,
3303
3307
  magMat: "bakelite",
3304
- stockLen: 0.22
3305
- },
3306
- variantOf: "ak_74"
3308
+ stockLen: 0.22,
3309
+ kalashnikov: 1
3310
+ }
3307
3311
  },
3308
3312
  fn_scar_l: {
3309
3313
  builder: "rifle",
@@ -3663,6 +3667,8 @@ var createMaterials = (THREE) => {
3663
3667
  metal: standard(3422010, 0.42, 0.75),
3664
3668
  steel: standard(7106418, 0.32, 0.85),
3665
3669
  steelL: standard(9080208, 0.28, 0.9),
3670
+ // polished steel: bright and glossy under plain lights too (the rooms have no environment map for a fully metallic surface to mirror)
3671
+ chrome: standard(13949148, 0.16, 0.5),
3666
3672
  dark: standard(1711133, 0.55, 0.5),
3667
3673
  poly: standard(2369058, 0.8, 0.05),
3668
3674
  olive: standard(4936241, 0.8, 0.05),
@@ -4042,6 +4048,108 @@ function fillG36Magazine(context) {
4042
4048
  for (let i = 0; i < 9; i++) kit.cylinderX(parts.mag, 45e-4, 0.042, kit.M.brass, 2e-3 + i * 1e-3, -0.01 - i * 0.0115, i % 2 ? 4e-3 : -4e-3, 8);
4043
4049
  }
4044
4050
 
4051
+ // src/models/wood-profile.ts
4052
+ import { markShared as markShared2 } from "@adatechnology/game-shapes-three";
4053
+ var SLICE_LENGTH = 0.02;
4054
+ var at = (points, x) => {
4055
+ const last = points[points.length - 1];
4056
+ if (x >= last[0]) return [last[1], last[2]];
4057
+ const nextIndex = points.findIndex((point) => point[0] >= x);
4058
+ const next = points[Math.max(nextIndex, 1)];
4059
+ const previous = points[Math.max(nextIndex, 1) - 1];
4060
+ const fraction = (x - previous[0]) / (next[0] - previous[0]);
4061
+ return [previous[1] + (next[1] - previous[1]) * fraction, previous[2] + (next[2] - previous[2]) * fraction];
4062
+ };
4063
+ function profileBlock(kit, parent, points, width, material) {
4064
+ const first = points[0];
4065
+ const last = points[points.length - 1];
4066
+ const count = Math.max(1, Math.ceil((last[0] - first[0]) / SLICE_LENGTH));
4067
+ const step = (last[0] - first[0]) / count;
4068
+ for (let index = 0; index < count; index++) {
4069
+ const [rearTop, rearBottom] = at(points, first[0] + step * index);
4070
+ const [frontTop, frontBottom] = at(points, first[0] + step * (index + 1));
4071
+ const rise = (frontTop + frontBottom - rearTop - rearBottom) / 2;
4072
+ const height = (frontTop - frontBottom + rearTop - rearBottom) / 2;
4073
+ const centre = (rearTop + rearBottom + frontTop + frontBottom) / 4;
4074
+ kit.box(parent, Math.hypot(step, rise) * 1.12, height, width, material, first[0] + step * (index + 0.5), centre, 0, Math.atan2(rise, step));
4075
+ }
4076
+ }
4077
+ var BEVEL = 25e-4;
4078
+ var solids = /* @__PURE__ */ new WeakMap();
4079
+ function profileSolid(kit, parent, points, width, material, hole) {
4080
+ const key = JSON.stringify([points, width, hole ?? null]);
4081
+ const cache = solids.get(kit) ?? /* @__PURE__ */ new Map();
4082
+ solids.set(kit, cache);
4083
+ let geometry = cache.get(key);
4084
+ if (!geometry) {
4085
+ geometry = buildSolid(kit, points, width, hole);
4086
+ markShared2(geometry);
4087
+ cache.set(key, geometry);
4088
+ }
4089
+ const { THREE } = kit;
4090
+ const mesh = new THREE.Mesh(geometry, material);
4091
+ mesh.castShadow = true;
4092
+ mesh.receiveShadow = true;
4093
+ parent.add(mesh);
4094
+ return mesh;
4095
+ }
4096
+ function buildSolid(kit, points, width, hole) {
4097
+ const { THREE } = kit;
4098
+ const top = points.map(([x, y]) => new THREE.Vector2(x, y));
4099
+ const bottom = [...points].reverse().map(([x, , y]) => new THREE.Vector2(x, y));
4100
+ const first = top[0];
4101
+ const shape = new THREE.Shape();
4102
+ shape.moveTo(first.x, first.y);
4103
+ shape.splineThru(top.slice(1));
4104
+ shape.lineTo(bottom[0].x, bottom[0].y);
4105
+ shape.splineThru(bottom.slice(1));
4106
+ shape.closePath();
4107
+ if (hole) {
4108
+ const loop = hole.map(([x, y]) => new THREE.Vector2(x, y));
4109
+ const path = new THREE.Path();
4110
+ path.moveTo(loop[0].x, loop[0].y);
4111
+ path.splineThru([...loop.slice(1), loop[0]]);
4112
+ shape.holes.push(path);
4113
+ }
4114
+ const depth = Math.max(2e-3, width - BEVEL * 2);
4115
+ const geometry = new THREE.ExtrudeGeometry(shape, { depth, curveSegments: 16, bevelEnabled: true, bevelThickness: BEVEL, bevelSize: BEVEL, bevelSegments: 2 });
4116
+ geometry.translate(0, 0, -depth / 2);
4117
+ return geometry;
4118
+ }
4119
+
4120
+ // src/models/rifle-svd.ts
4121
+ function buildSvdStock(context) {
4122
+ const { kit, group, furniture: furn, stockLength: S } = context;
4123
+ const width = 0.034;
4124
+ profileSolid(
4125
+ kit,
4126
+ group,
4127
+ [
4128
+ [6e-3, 0.02, -0.142],
4129
+ [0.07, 0.022, -0.13],
4130
+ [0.16, 0.024, -0.122],
4131
+ [S - 0.03, 0.027, -0.124],
4132
+ [S + 6e-3, 0.028, -0.128],
4133
+ [S + 0.035, -0.02, -0.13]
4134
+ ],
4135
+ width,
4136
+ furn,
4137
+ [[0.125, -0.02], [0.2, -0.018], [S - 0.01, -0.022], [S + 0.012, -0.05], [S - 0.01, -0.094], [0.2, -0.095], [0.125, -0.09], [0.112, -0.055]]
4138
+ );
4139
+ profileSolid(kit, group, [[0.06, 0.044, 0.016], [0.11, 0.05, 0.016], [0.2, 0.046, 0.016]], width * 0.9, furn);
4140
+ buttpad(kit, group, 3e-3, -0.06, 0.16, width);
4141
+ }
4142
+ function buildSvdHandguard(context) {
4143
+ const { kit, group, furniture: furn, receiverEnd: x1, receiverWidth: wR, barrelRadius: r, barrelY: by } = context;
4144
+ const { M, box: box2, cylinderX } = kit;
4145
+ const length = 0.27;
4146
+ profileSolid(kit, group, [[x1, by + 0.024, by - 0.03], [x1 + 0.06, by + 0.026, by - 0.03], [x1 + length, by + 0.02, by - 0.024]], wR * 1.12, furn);
4147
+ for (let i = 0; i < 3; i++) for (const side of [-1, 1]) box2(group, 0.028, 8e-3, 2e-3, M.hole, x1 + 0.07 + i * 0.06, by + 4e-3, side * wR * 0.57);
4148
+ cylinderX(group, wR * 0.5, 0.012, M.metal, x1 + length + 6e-3, by, 0, 16);
4149
+ cylinderX(group, r * 1.2, 0.05, M.metal, x1 + length + 0.035, by + r * 2.4, 0, 12);
4150
+ box2(group, 0.016, r * 3.4, wR * 0.5, M.metal, x1 + length + 0.05, by + r * 1.2, 0);
4151
+ }
4152
+
4045
4153
  // src/models/rifle-forend.ts
4046
4154
  var PI4 = Math.PI;
4047
4155
  function buildForend(context) {
@@ -4051,6 +4159,10 @@ function buildForend(context) {
4051
4159
  buildG36Handguard(context);
4052
4160
  return;
4053
4161
  }
4162
+ if (o.svd) {
4163
+ buildSvdHandguard(context);
4164
+ return;
4165
+ }
4054
4166
  const hasLongScope = (o.scope ?? 0) >= 3;
4055
4167
  if (!context.isTraditional && o.hg !== "none") {
4056
4168
  const handguardLength = (L - x1) * (o.hgFrac || 0.5);
@@ -4131,6 +4243,83 @@ function buildHelicalMagazine(context) {
4131
4243
  return x;
4132
4244
  }
4133
4245
 
4246
+ // src/models/geometry-cache.ts
4247
+ import { markShared as markShared3 } from "@adatechnology/game-shapes-three";
4248
+ var shared = /* @__PURE__ */ new WeakMap();
4249
+ function sharedGeometry(kit, key, build) {
4250
+ const cache = shared.get(kit) ?? /* @__PURE__ */ new Map();
4251
+ shared.set(kit, cache);
4252
+ let geometry = cache.get(key);
4253
+ if (!geometry) {
4254
+ geometry = build();
4255
+ markShared3(geometry);
4256
+ cache.set(key, geometry);
4257
+ }
4258
+ return geometry;
4259
+ }
4260
+
4261
+ // src/models/rifle-kalashnikov.ts
4262
+ function buildKalashnikovReceiver(context) {
4263
+ const { kit, group, receiverStart: x0, receiverEnd: x1, receiverWidth: wR, receiverLength: RL, receiverHeight: hR, barrelY: by } = context;
4264
+ const { M, box: box2, cylinderZ } = kit;
4265
+ const bottom = -hR / 2;
4266
+ profileSolid(kit, group, [[x0, 0.015, bottom + 0.012], [x0 + 0.035, 0.015, bottom], [x1, 0.015, bottom]], wR * 0.9, M.metal);
4267
+ profileSolid(kit, group, [[x0 + 2e-3, 0.021, 0.012], [x0 + RL * 0.5, 0.027, 0.012], [x1 - 4e-3, 0.031, 0.012]], wR * 0.8, M.metal);
4268
+ for (let i = 0; i < 4; i++) box2(group, 4e-3, 3e-3, wR * 0.6, M.dark, x0 + 0.03 + i * 0.012, 0.024 + i * 6e-4, 0);
4269
+ box2(group, 8e-3, 8e-3, 0.01, M.metal, x0 + 4e-3, 0.02, 0);
4270
+ profileSolid(kit, group, [[x1 - 8e-3, 0.034, by - 0.012], [x1 + 0.02, 0.031, by - 0.012], [x1 + 0.046, 0.024, by - 8e-3]], wR * 0.7, M.metal);
4271
+ box2(group, 0.036, 4e-3, wR * 0.5, M.dark, x1 + 0.018, 0.037, 0, -0.04);
4272
+ box2(group, 6e-3, 8e-3, wR * 0.5, M.dark, x1 + 2e-3, 0.039, 0);
4273
+ box2(group, RL * 0.48, 0.011, 3e-3, M.metal, x0 + RL * 0.36, 4e-3, wR * 0.46 + 15e-4, -0.05);
4274
+ box2(group, 0.012, 0.016, 3e-3, M.metal, x0 + RL * 0.62, -6e-3, wR * 0.46 + 15e-4, -0.3);
4275
+ for (const [x, y] of [[x0 + 0.012, -0.012], [x0 + 0.026, -0.012], [x1 - 0.03, -0.014], [x1 - 0.016, -0.014], [x1 - 0.03, 2e-3]]) {
4276
+ cylinderZ(group, 2e-3, wR * 0.9 + 2e-3, M.dark, x, y, 0, 8);
4277
+ }
4278
+ }
4279
+ var arcBand = (kit, parent, centre, radii, angles, depth, material) => {
4280
+ const { THREE } = kit;
4281
+ const geometry = sharedGeometry(kit, `arc:${JSON.stringify([centre, radii, angles, depth])}`, () => {
4282
+ const [inner, outer] = radii;
4283
+ const [start, end] = angles;
4284
+ const shape = new THREE.Shape();
4285
+ shape.absarc(centre[0], centre[1], outer, start, end, false);
4286
+ shape.absarc(centre[0], centre[1], inner, end, start, true);
4287
+ shape.closePath();
4288
+ const bevel = Math.min(12e-4, depth / 6);
4289
+ const extruded = new THREE.ExtrudeGeometry(shape, { depth: depth - bevel * 2, curveSegments: 24, bevelEnabled: true, bevelThickness: bevel, bevelSize: bevel, bevelSegments: 1 });
4290
+ extruded.translate(0, 0, -(depth - bevel * 2) / 2);
4291
+ return extruded;
4292
+ });
4293
+ const mesh = new THREE.Mesh(geometry, material);
4294
+ mesh.castShadow = true;
4295
+ mesh.receiveShadow = true;
4296
+ parent.add(mesh);
4297
+ return mesh;
4298
+ };
4299
+ var CURVE_RADIUS = 0.33;
4300
+ var MAGAZINE_DEPTH2 = 0.052;
4301
+ var MAGAZINE_WIDTH = 0.024;
4302
+ var LENGTH_PER_SCALE = 0.2;
4303
+ function buildBananaMagazine(kit, magazine, material, scale) {
4304
+ const { M, box: box2 } = kit;
4305
+ const length = LENGTH_PER_SCALE * scale;
4306
+ const span = length / CURVE_RADIUS;
4307
+ const centre = [CURVE_RADIUS, 0];
4308
+ const start = Math.PI;
4309
+ const end = Math.PI + span;
4310
+ const half = MAGAZINE_DEPTH2 / 2;
4311
+ arcBand(kit, magazine, centre, [CURVE_RADIUS - half, CURVE_RADIUS + half], [start, end], MAGAZINE_WIDTH, material);
4312
+ for (const radius of [CURVE_RADIUS - half * 0.45, CURVE_RADIUS + half * 0.45]) {
4313
+ arcBand(kit, magazine, centre, [radius - 25e-4, radius + 25e-4], [start + span * 0.08, end - span * 0.06], MAGAZINE_WIDTH + 3e-3, material);
4314
+ }
4315
+ box2(magazine, 0.01, 8e-3, MAGAZINE_WIDTH * 0.7, M.metal, half - 2e-3, 2e-3, 0);
4316
+ const bottom = [centre[0] + CURVE_RADIUS * Math.cos(end), centre[1] + CURVE_RADIUS * Math.sin(end)];
4317
+ const plate3 = box2(magazine, MAGAZINE_DEPTH2 + 6e-3, 6e-3, MAGAZINE_WIDTH + 4e-3, material, bottom[0], bottom[1], 0, span);
4318
+ plate3.position.x += Math.sin(span) * 2e-3;
4319
+ plate3.position.y -= Math.cos(span) * 2e-3;
4320
+ return length + 0.04;
4321
+ }
4322
+
4134
4323
  // src/models/rifle-controls.ts
4135
4324
  function buildGrip(context) {
4136
4325
  const { kit, group, parts, options: o, furniture: furn, receiverStart: x0, receiverHeight: hR, receiverWidth: wR } = context;
@@ -4159,7 +4348,9 @@ function buildMagazine(context, gx) {
4159
4348
  const magazine = kit.pivot(group, mx, -hR / 2, 0);
4160
4349
  parts.mag = magazine;
4161
4350
  const finish = o.magMat === "bakelite" ? M.bakelite : o.magMat === "poly" ? M.polyMag : o.magMat === "smoke" ? M.smoke : void 0;
4162
- if (o.mag === "curved") {
4351
+ if (o.mag === "curved" && o.kalashnikov) {
4352
+ parts.magDrop = buildBananaMagazine(kit, magazine, finish ?? M.metal, scale);
4353
+ } else if (o.mag === "curved") {
4163
4354
  let px = 0;
4164
4355
  let py = 0;
4165
4356
  const material = finish ?? M.metal;
@@ -4282,10 +4473,56 @@ function buildLeverShotgun(kit, options) {
4282
4473
  return { group, parts };
4283
4474
  }
4284
4475
 
4476
+ // src/models/rifle-sporter.ts
4477
+ function buildSporterStock(context, magazineX) {
4478
+ const { kit, group, furniture: furn, length: L, stockLength: S, receiverEnd: x1, receiverHeight: hR } = context;
4479
+ const { M, box: box2 } = kit;
4480
+ const forendTip = x1 + (L - x1) * (context.options.fore ?? 0.5);
4481
+ const bottom = -hR / 2;
4482
+ const bedTop = context.options.round ? context.barrelY - hR * 0.36 + 3e-3 : bottom + 0.012;
4483
+ profileSolid(
4484
+ kit,
4485
+ group,
4486
+ [
4487
+ [6e-3, -0.016, -0.15],
4488
+ [0.14, -0.012, -0.118],
4489
+ [S - 0.11, -0.016, -0.084],
4490
+ [S - 0.05, -0.018, -0.114],
4491
+ [S - 0.01, -0.016, -0.09],
4492
+ [S + 0.03, bedTop, bottom - 0.03],
4493
+ [x1, bedTop, bottom - 0.026],
4494
+ [x1 + 0.08, bedTop, bottom - 0.024],
4495
+ [forendTip, bottom + 0.02, bottom - 0.012]
4496
+ ],
4497
+ 0.04,
4498
+ furn
4499
+ );
4500
+ buttpad(kit, group, 0, -0.083, 0.136, 0.04);
4501
+ box2(group, 0.024, 6e-3, 0.03, M.dark, S - 0.05, -0.116, 0, -0.5);
4502
+ const guard = kit.torus(group, new kit.THREE.TorusGeometry(0.024, 25e-4, 6, 16, Math.PI), M.metal, S + 0.075, bottom - 0.022, 0);
4503
+ guard.rotation.z = Math.PI;
4504
+ box2(group, 0.07, 4e-3, 0.03, M.metal, magazineX, bottom - 0.03, 0);
4505
+ swivel(kit, group, 0.12, -0.12);
4506
+ swivel(kit, group, forendTip - 0.05, bottom - 0.02);
4507
+ }
4508
+ function buildKalashnikovStock(context) {
4509
+ const { kit, group, furniture: furn, stockLength: S, receiverHeight: hR } = context;
4510
+ const { M, box: box2 } = kit;
4511
+ profileSolid(kit, group, [[8e-3, -0.034, -0.15], [S * 0.5, -0.014, -0.1], [S + 4e-3, hR * 0.2, -hR / 2 - 2e-3]], 0.036, furn);
4512
+ box2(group, 8e-3, 0.118, 0.038, M.metal, 4e-3, -0.092, 0, -0.06);
4513
+ const loopX = 0.1;
4514
+ const belly = -0.15 + (loopX - 8e-3) / (S * 0.5 - 8e-3) * 0.05;
4515
+ box2(group, 0.03, 6e-3, 6e-3, M.metal, loopX, belly + 0.032, -0.019, 0.3);
4516
+ }
4517
+
4285
4518
  // src/models/rifle-stock.ts
4286
4519
  function buildStock(context, magazineX) {
4287
4520
  const { kit, group, options: o, furniture: furn, length: L, stockLength: S, receiverStart: x0, receiverEnd: x1, receiverHeight: hR } = context;
4288
4521
  const { M, box: box2, cylinderX } = kit;
4522
+ if (o.stock === "sporter") {
4523
+ buildSporterStock(context, magazineX);
4524
+ return;
4525
+ }
4289
4526
  if (context.isTraditional) {
4290
4527
  buttpad(kit, group, 6e-3, -0.04, 0.13, 0.038);
4291
4528
  box2(group, 0.03, 0.13, 0.038, furn, 0.024, -0.04, 0);
@@ -4317,6 +4554,10 @@ function buildStock(context, magazineX) {
4317
4554
  buttpad(kit, group, 3e-3, -0.025, 0.11, 0.036);
4318
4555
  } else if (o.stock === "g36") {
4319
4556
  buildG36Stock(context);
4557
+ } else if (o.stock === "ak") {
4558
+ buildKalashnikovStock(context);
4559
+ } else if (o.stock === "svd") {
4560
+ buildSvdStock(context);
4320
4561
  } else if (o.stock === "fold") {
4321
4562
  box2(group, S, 6e-3, 6e-3, M.metal, S / 2, 0.01, 0.012);
4322
4563
  box2(group, S, 6e-3, 6e-3, M.metal, S / 2, -0.04, 0.012, -0.12);
@@ -4332,6 +4573,7 @@ function buildReceiver(context) {
4332
4573
  const receiverMaterial = o.tan ? M.tan : M.metal;
4333
4574
  const middle = (x0 + x1) / 2;
4334
4575
  if (o.g36) buildG36Receiver(context);
4576
+ else if (o.kalashnikov) buildKalashnikovReceiver(context);
4335
4577
  else if (o.round) {
4336
4578
  cylinderX(group, hR * 0.36, RL, M.steel, middle, by, 0, 20);
4337
4579
  cylinderX(group, hR * 0.32, 0.05, M.steel, x0 - 0.01, by, 0, 18);
@@ -4344,7 +4586,7 @@ function buildReceiver(context) {
4344
4586
  box2(group, 0.03, 8e-3, 0.012, M.dark, x0 + 0.02, hR / 2 + 4e-3, 0);
4345
4587
  box2(group, 0.012, 6e-3, 4e-3, M.dark, x0 + RL * 0.55, -hR * 0.15, -wR / 2 - 2e-3);
4346
4588
  } else box2(group, RL, hR, wR, receiverMaterial, middle, 0, 0);
4347
- if (o.ak) {
4589
+ if (o.ak && !o.kalashnikov) {
4348
4590
  box2(group, RL * 0.86, hR * 0.28, wR * 0.95, M.metal, middle - 8e-3, hR / 2 + 4e-3, 0);
4349
4591
  for (let i = 0; i < 3; i++) box2(group, 4e-3, hR * 0.3, wR * 0.97, M.dark, x0 + RL * 0.25 + i * 0.02, hR / 2 + 4e-3, 0);
4350
4592
  box2(group, RL * 0.5, 0.012, 3e-3, M.metal, x0 + RL * 0.55, -hR * 0.02, wR / 2 + 15e-4, -0.05);
@@ -4407,7 +4649,7 @@ function buildRifle(kit, options) {
4407
4649
  const parts = { family: "rifle", glow: [] };
4408
4650
  const length = (options.L ?? 0) / 1e3;
4409
4651
  const barrelLength = (options.B ?? 0) / 1e3;
4410
- const isTraditional = options.stock === "trad" || options.stock === "straight";
4652
+ const isTraditional = options.stock === "trad" || options.stock === "straight" || options.stock === "sporter";
4411
4653
  const stockLength = options.stock === "none" ? 0 : options.stockLen || Math.min(0.36, Math.max(0.2, 0.3 * length));
4412
4654
  const receiverStart = stockLength;
4413
4655
  const receiverEnd = Math.max(receiverStart + 0.12, length - barrelLength * 0.92);
@@ -5340,7 +5582,7 @@ function buildP90(kit) {
5340
5582
 
5341
5583
  // src/models/ps90.ts
5342
5584
  var WIDTH = 0.046;
5343
- var BEVEL = 5e-3;
5585
+ var BEVEL2 = 5e-3;
5344
5586
  var BODY_OUTLINE = [
5345
5587
  [0.017, -0.078],
5346
5588
  [0.03, -0.09],
@@ -5382,8 +5624,8 @@ function extrudeProfile(kit, parent, outline, holes, width, material) {
5382
5624
  const toVector = ([x, y]) => new THREE.Vector2(x, y);
5383
5625
  const shape = new THREE.Shape(outline.map(toVector));
5384
5626
  for (const hole of holes) shape.holes.push(new THREE.Path(hole.map(toVector)));
5385
- const geometry = new THREE.ExtrudeGeometry(shape, { depth: width - 2 * BEVEL, bevelEnabled: true, bevelThickness: BEVEL, bevelSize: BEVEL, bevelSegments: 2 });
5386
- geometry.translate(0, 0, -(width - 2 * BEVEL) / 2);
5627
+ const geometry = new THREE.ExtrudeGeometry(shape, { depth: width - 2 * BEVEL2, bevelEnabled: true, bevelThickness: BEVEL2, bevelSize: BEVEL2, bevelSegments: 2 });
5628
+ geometry.translate(0, 0, -(width - 2 * BEVEL2) / 2);
5387
5629
  const mesh = new THREE.Mesh(geometry, material);
5388
5630
  mesh.castShadow = true;
5389
5631
  mesh.receiveShadow = true;
@@ -5656,6 +5898,135 @@ function buildDesignedPistol(kit, options, name) {
5656
5898
  return { group, parts };
5657
5899
  }
5658
5900
 
5901
+ // src/models/pistol-deagle.ts
5902
+ var SLIDE_HEIGHT = 0.036;
5903
+ var WIDTH2 = 0.032;
5904
+ var FRAME_HEIGHT = 0.015;
5905
+ var FRAME_BOTTOM = -SLIDE_HEIGHT / 2 - FRAME_HEIGHT;
5906
+ var GRIP = { angle: -0.314, depth: 0.052, width: 0.034, length: 0.1, rearX: 0.014 };
5907
+ var GUARD = { drop: 0.038, front: 0.064, bar: 65e-4, depth: 0.011 };
5908
+ var SLIDE_SHARE = 0.55;
5909
+ var plate = (kit, parent, outline, hole, depth, material) => {
5910
+ const { THREE } = kit;
5911
+ const geometry = sharedGeometry(kit, `plate:${JSON.stringify([outline, hole, depth])}`, () => {
5912
+ const shape = new THREE.Shape(outline.map(([x, y]) => new THREE.Vector2(x, y)));
5913
+ if (hole) shape.holes.push(new THREE.Path(hole.map(([x, y]) => new THREE.Vector2(x, y))));
5914
+ const extruded = new THREE.ExtrudeGeometry(shape, { depth, bevelEnabled: true, bevelThickness: 8e-4, bevelSize: 8e-4, bevelSegments: 1 });
5915
+ extruded.translate(0, 0, -depth / 2);
5916
+ return extruded;
5917
+ });
5918
+ const mesh = new THREE.Mesh(geometry, material);
5919
+ mesh.castShadow = true;
5920
+ mesh.receiveShadow = true;
5921
+ parent.add(mesh);
5922
+ return mesh;
5923
+ };
5924
+ var buildUpper = (kit, group, slide2, parts, length, metal2) => {
5925
+ const { M, box: box2, cylinderX } = kit;
5926
+ const slideLength = length * SLIDE_SHARE;
5927
+ const barrelLength = length - slideLength;
5928
+ kit.roundness = 0.06;
5929
+ box2(slide2, slideLength, SLIDE_HEIGHT, WIDTH2, metal2, slideLength / 2, 0, 0);
5930
+ const barrel = heatify(parts.glow ?? [], box2(group, barrelLength, SLIDE_HEIGHT, WIDTH2, metal2, slideLength + barrelLength / 2, 0, 0));
5931
+ barrel.name = "barrel";
5932
+ kit.roundness = null;
5933
+ box2(group, 12e-4, SLIDE_HEIGHT * 0.9, WIDTH2 + 4e-4, M.dark, slideLength, 0, 0);
5934
+ for (let i = 0; i < 9; i++) box2(slide2, 22e-4, SLIDE_HEIGHT * 0.66, WIDTH2 + 12e-4, M.dark, 8e-3 + i * 48e-4, -3e-3, 0);
5935
+ box2(slide2, length * 0.08, 3e-3, WIDTH2 * 0.5, M.hole, length * 0.42, SLIDE_HEIGHT / 2, WIDTH2 * 0.12);
5936
+ box2(slide2, 7e-3, 6e-3, 0.014, M.dark, 8e-3, SLIDE_HEIGHT / 2 + 3e-3, 0);
5937
+ box2(slide2, 3e-3, 2e-3, 4e-3, M.hole, 8e-3, SLIDE_HEIGHT / 2 + 5e-3, 0);
5938
+ box2(group, barrelLength * 0.9, 4e-3, WIDTH2 * 0.42, metal2, slideLength + barrelLength * 0.5, SLIDE_HEIGHT / 2 + 2e-3, 0);
5939
+ for (let i = 0; i < 7; i++) box2(group, 4e-3, 15e-4, WIDTH2 * 0.43, M.hole, slideLength + 0.01 + i * 0.013, SLIDE_HEIGHT / 2 + 4e-3, 0);
5940
+ box2(group, 4e-3, 6e-3, 4e-3, M.dark, length - 6e-3, SLIDE_HEIGHT / 2 + 6e-3, 0);
5941
+ const nose = plate(kit, group, [[-WIDTH2 / 2, -SLIDE_HEIGHT / 2 + 2e-3], [WIDTH2 / 2, -SLIDE_HEIGHT / 2 + 2e-3], [WIDTH2 * 0.16, SLIDE_HEIGHT / 2 - 2e-3], [-WIDTH2 * 0.16, SLIDE_HEIGHT / 2 - 2e-3]], null, 3e-3, metal2);
5942
+ nose.rotation.y = Math.PI / 2;
5943
+ nose.position.set(length + 15e-4, 0, 0);
5944
+ const boreY = -SLIDE_HEIGHT * 0.12;
5945
+ cylinderX(group, 64e-4, 4e-3, M.hole, length + 3e-3, boreY, 0, 14);
5946
+ return boreY;
5947
+ };
5948
+ var buildGrip2 = (kit, group, parts, metal2) => {
5949
+ const { M, box: box2 } = kit;
5950
+ const { angle, depth, width, length } = GRIP;
5951
+ const sin = Math.sin(angle);
5952
+ const cos = Math.cos(angle);
5953
+ const topY = FRAME_BOTTOM + 6e-3;
5954
+ const centerX = GRIP.rearX + depth / 2 * cos + length / 2 * sin;
5955
+ const centerY = topY - length / 2 * cos + depth / 2 * sin;
5956
+ const grip = kit.pivot(group, centerX, centerY, 0);
5957
+ grip.rotation.z = angle;
5958
+ parts.grip = grip;
5959
+ kit.roundness = 0.22;
5960
+ box2(grip, depth, length, width * 0.86, metal2, 0, 0, 0);
5961
+ box2(grip, depth * 0.86, length * 0.84, width, M.rubber, -2e-3, 2e-3, 0);
5962
+ kit.roundness = null;
5963
+ for (let i = 0; i < 8; i++) box2(grip, depth * 0.66, 2e-3, width + 12e-4, M.dark, -3e-3, -length * 0.36 + i * 0.0105, 0);
5964
+ const magazine = kit.pivot(grip);
5965
+ parts.mag = magazine;
5966
+ parts.magDrop = length * 1.15;
5967
+ box2(magazine, depth * 0.62, length * 0.94, width * 0.66, M.dark, 2e-3, -4e-3, 0);
5968
+ box2(magazine, depth * 0.98, 6e-3, width * 0.9, metal2, 0, -length / 2 + 3e-3, 0);
5969
+ const frontTopX = centerX + depth / 2 * cos - length / 2 * sin;
5970
+ const frontTopY = centerY + depth / 2 * sin + length / 2 * cos;
5971
+ return (y) => frontTopX + (frontTopY - y) * Math.tan(angle);
5972
+ };
5973
+ var buildGuard = (kit, group, frontStrapAt, metal2) => {
5974
+ const top = FRAME_BOTTOM + 2e-3;
5975
+ const bottom = FRAME_BOTTOM - GUARD.drop;
5976
+ const backTop = frontStrapAt(top) - 4e-3;
5977
+ const backBottom = frontStrapAt(bottom) - 4e-3;
5978
+ const front = backTop + GUARD.front;
5979
+ const bar = GUARD.bar;
5980
+ const corner = 8e-3;
5981
+ const outline = [
5982
+ [backTop, top],
5983
+ [backBottom, bottom],
5984
+ [front - corner, bottom],
5985
+ [front, bottom + corner],
5986
+ [front + 2e-3, top]
5987
+ ];
5988
+ const hole = [
5989
+ [backTop + bar + 2e-3, top - 2e-3],
5990
+ [front - bar + 1e-3, top - 2e-3],
5991
+ [front - bar, bottom + bar + corner * 0.6],
5992
+ [front - bar - corner * 0.6, bottom + bar],
5993
+ [backBottom + bar + 4e-3, bottom + bar]
5994
+ ];
5995
+ plate(kit, group, outline, hole, GUARD.depth, metal2);
5996
+ return bottom;
5997
+ };
5998
+ function buildDeagle(kit, options) {
5999
+ const { M, box: box2, torus, THREE } = kit;
6000
+ const length = (options.L ?? 0) / 1e3 * 0.97;
6001
+ const metal2 = options.chrome ? M.chrome : options.steel ? M.steel : options.stain ? M.steelL : M.metal;
6002
+ const group = kit.group();
6003
+ const parts = { family: "pistol", kick: 1.8, glow: [] };
6004
+ const slide2 = kit.pivot(group);
6005
+ parts.slide = slide2;
6006
+ parts.stroke = length * 0.12;
6007
+ const boreY = buildUpper(kit, group, slide2, parts, length, metal2);
6008
+ kit.roundness = 0.1;
6009
+ box2(group, length * 0.95, FRAME_HEIGHT, WIDTH2 * 0.94, metal2, length * 0.5 - 2e-3, -SLIDE_HEIGHT / 2 - FRAME_HEIGHT / 2, 0);
6010
+ kit.roundness = null;
6011
+ box2(group, length * 0.3, 3e-3, WIDTH2 * 0.94 + 1e-3, M.dark, length * 0.72, -SLIDE_HEIGHT / 2 - FRAME_HEIGHT * 0.6, 0);
6012
+ box2(group, 0.026, 9e-3, WIDTH2 * 0.9, metal2, -2e-3, FRAME_BOTTOM + 4e-3, 0, 0.3);
6013
+ box2(group, 0.016, 5e-3, 4e-3, M.dark, length * 0.36, -SLIDE_HEIGHT / 2 - 5e-3, -WIDTH2 / 2 - 14e-4);
6014
+ const frontStrapAt = buildGrip2(kit, group, parts, metal2);
6015
+ buildGuard(kit, group, frontStrapAt, metal2);
6016
+ const triggerX = frontStrapAt(FRAME_BOTTOM) + 0.02;
6017
+ parts.trigger = box2(group, 6e-3, 0.026, 7e-3, M.steel, triggerX, FRAME_BOTTOM - 8e-3, 0, 0.28);
6018
+ const hammer = kit.pivot(group, 2e-3, SLIDE_HEIGHT * 0.05, 0);
6019
+ parts.hammer = hammer;
6020
+ box2(hammer, 0.012, 0.02, 0.01, M.dark, -4e-3, 4e-3, 0, 0.35);
6021
+ const ring = torus(hammer, new THREE.TorusGeometry(68e-4, 24e-4, 8, 16), M.dark, -0.01, 0.014, 0);
6022
+ ring.scale.z = 2;
6023
+ parts.safety = box2(slide2, 0.014, 8e-3, 4e-3, M.dark, 0.02, SLIDE_HEIGHT * 0.1, -WIDTH2 / 2 - 2e-3, 0.2);
6024
+ box2(slide2, 0.014, 8e-3, 4e-3, M.dark, 0.02, SLIDE_HEIGHT * 0.1, WIDTH2 / 2 + 2e-3, 0.2);
6025
+ parts.muzzle = kit.mark(group, length + 6e-3, boreY, 0);
6026
+ parts.eject = kit.mark(group, length * 0.42, SLIDE_HEIGHT / 2, WIDTH2 * 0.25);
6027
+ return { group, parts };
6028
+ }
6029
+
5659
6030
  // src/models/pistol-slide.ts
5660
6031
  var PI9 = Math.PI;
5661
6032
  function buildSlide(kit, slide2, parts, options, style, size, metal2) {
@@ -5808,6 +6179,7 @@ function buildFrame2(kit, group, parts, options, style, size, materials) {
5808
6179
  }
5809
6180
  function buildPistol(kit, options) {
5810
6181
  if (options.design && isDesignName(options.design)) return buildDesignedPistol(kit, options, options.design);
6182
+ if (options.st === "deagle") return buildDeagle(kit, options);
5811
6183
  const { M, box: box2 } = kit;
5812
6184
  const style = { ...STYLES[options.st ?? "glock"] };
5813
6185
  const group = kit.group();
@@ -5980,32 +6352,6 @@ function buildRevolver(kit, options) {
5980
6352
  return { group, parts };
5981
6353
  }
5982
6354
 
5983
- // src/models/wood-profile.ts
5984
- var SLICE_LENGTH = 0.02;
5985
- var at = (points, x) => {
5986
- const last = points[points.length - 1];
5987
- if (x >= last[0]) return [last[1], last[2]];
5988
- const nextIndex = points.findIndex((point) => point[0] >= x);
5989
- const next = points[Math.max(nextIndex, 1)];
5990
- const previous = points[Math.max(nextIndex, 1) - 1];
5991
- const fraction = (x - previous[0]) / (next[0] - previous[0]);
5992
- return [previous[1] + (next[1] - previous[1]) * fraction, previous[2] + (next[2] - previous[2]) * fraction];
5993
- };
5994
- function profileBlock(kit, parent, points, width, material) {
5995
- const first = points[0];
5996
- const last = points[points.length - 1];
5997
- const count = Math.max(1, Math.ceil((last[0] - first[0]) / SLICE_LENGTH));
5998
- const step = (last[0] - first[0]) / count;
5999
- for (let index = 0; index < count; index++) {
6000
- const [rearTop, rearBottom] = at(points, first[0] + step * index);
6001
- const [frontTop, frontBottom] = at(points, first[0] + step * (index + 1));
6002
- const rise = (frontTop + frontBottom - rearTop - rearBottom) / 2;
6003
- const height = (frontTop - frontBottom + rearTop - rearBottom) / 2;
6004
- const centre = (rearTop + rearBottom + frontTop + frontBottom) / 4;
6005
- kit.box(parent, Math.hypot(step, rise) * 1.12, height, width, material, first[0] + step * (index + 0.5), centre, 0, Math.atan2(rise, step));
6006
- }
6007
- }
6008
-
6009
6355
  // src/models/rifle-kar98.ts
6010
6356
  var RECEIVER_START3 = 0.29;
6011
6357
  var RECEIVER_END3 = 0.5;
@@ -6548,14 +6894,13 @@ function showcasePedestalItem(name) {
6548
6894
  movable: false
6549
6895
  };
6550
6896
  }
6551
- function showcaseSheet(arsenal, text, weapon) {
6552
- const name = arsenal.name(weapon);
6897
+ function showcasePhoto(arsenal, text, weapon) {
6553
6898
  const photo = PHOTOS[weapon];
6554
- if (!photo) return { kicker: text.kicker, title: name, note: text.noPhoto };
6555
- return { kicker: text.kicker, title: name, image: { url: photo.url, alt: fill(text.alt, { weapon: name }), credit: `${photo.author} \xB7 ${photo.license}`, page: photo.page } };
6899
+ if (!photo) return void 0;
6900
+ return { url: photo.url, alt: fill(text.alt, { weapon: arsenal.name(weapon) }), credit: `${photo.author} \xB7 ${photo.license}`, page: photo.page };
6556
6901
  }
6557
6902
  function createWeaponShowcase(options) {
6558
- const { arsenal, host, text } = options;
6903
+ const { arsenal, host, text, referencePhotos = false } = options;
6559
6904
  const THREE = host.THREE;
6560
6905
  const scene = host.scene;
6561
6906
  const centre = [SHOWCASE.at[0], SHOWCASE.height + SHOWCASE.lift, SHOWCASE.at[2]];
@@ -6565,7 +6910,7 @@ function createWeaponShowcase(options) {
6565
6910
  if (!shown) return;
6566
6911
  discardObject3D(shown.root);
6567
6912
  shown = null;
6568
- host.bench?.sheet?.(null);
6913
+ if (referencePhotos) host.cornerImage?.(null);
6569
6914
  };
6570
6915
  const look = () => host.bench?.look([centre[0] + SHOWCASE.eye[0], centre[1] + SHOWCASE.eye[1], centre[2] + SHOWCASE.eye[2]], centre);
6571
6916
  const show = (weapon) => {
@@ -6579,7 +6924,7 @@ function createWeaponShowcase(options) {
6579
6924
  holder.position.set(...centre);
6580
6925
  scene.add(holder);
6581
6926
  shown = { id: weapon, root: holder };
6582
- host.bench?.sheet?.(showcaseSheet(arsenal, text, weapon));
6927
+ if (referencePhotos) host.cornerImage?.(showcasePhoto(arsenal, text, weapon) ?? null);
6583
6928
  host.log(fill(text.shown, { weapon: arsenal.name(weapon) }), { weapon, photo: weapon in PHOTOS });
6584
6929
  look();
6585
6930
  };
@@ -6612,26 +6957,22 @@ var TEXT = {
6612
6957
  en: {
6613
6958
  pedestal: "Weapon showcase",
6614
6959
  weapon: "Showcase",
6615
- weaponHint: "Puts the weapon on the pedestal, turning slowly, takes the camera to it and shows a photo of the real one to compare with",
6960
+ weaponHint: "Puts the weapon on the pedestal, turning slowly, and takes the camera to it",
6616
6961
  none: "None",
6617
6962
  spin: "Turn the weapon",
6618
6963
  look: "Look at the showcase",
6619
- kicker: "The real weapon",
6620
6964
  alt: "Photo of a real {weapon}",
6621
- shown: "{weapon} on the showcase",
6622
- noPhoto: "No free photo of this exact model was found: it is listed in missing of assets/weapon-references.json."
6965
+ shown: "{weapon} on the showcase"
6623
6966
  },
6624
6967
  "pt-BR": {
6625
6968
  pedestal: "Vitrine de armas",
6626
6969
  weapon: "Vitrine",
6627
- weaponHint: "P\xF5e a arma no pedestal, girando devagar, leva a c\xE2mera at\xE9 ela e mostra uma foto da arma real para comparar",
6970
+ weaponHint: "P\xF5e a arma no pedestal, girando devagar, e leva a c\xE2mera at\xE9 ela",
6628
6971
  none: "Nenhuma",
6629
6972
  spin: "Girar a arma",
6630
6973
  look: "Olhar a vitrine",
6631
- kicker: "A arma real",
6632
6974
  alt: "Foto de um(a) {weapon} real",
6633
- shown: "{weapon} na vitrine",
6634
- noPhoto: "N\xE3o h\xE1 foto livre deste modelo exato: ele est\xE1 em missing de assets/weapon-references.json."
6975
+ shown: "{weapon} na vitrine"
6635
6976
  }
6636
6977
  };
6637
6978
  var showcaseTextOf = (locale) => TEXT[locale] ?? TEXT.en;
@@ -8522,6 +8863,8 @@ var GUNSHOT_SAMPLE = {
8522
8863
  priority: 3
8523
8864
  };
8524
8865
  var SUPPRESSED_SAMPLE = { ...GUNSHOT_SAMPLE, gain: 0.55, crossover: { from: 10, to: 50 }, falloff: { model: "inverse_square", k: 4e-3, minGain: 8e-4 } };
8866
+ var LAUNCH_SAMPLE = { bus: "weapons", gain: 0.9, pitch: 0.04, falloff: { model: "inverse_square", k: 1e-3, minGain: 1e-3 }, cutoffK: 0.03, priority: 3 };
8867
+ var LAUNCH_IDS = /* @__PURE__ */ new Set(["launcher_40mm", "rocket_launch"]);
8525
8868
  var RELOAD_SAMPLE = { bus: "weapons", gain: 0.32, pitch: 0.05, falloff: { model: "inverse_square", k: 0.05, minGain: 2e-3 }, cutoffK: 0.02, priority: 2 };
8526
8869
  var CASING_SAMPLE = { bus: "weapons", gain: 0.22, pitch: 0.06, falloff: { model: "inverse_square", k: 0.08, minGain: 3e-3 }, cutoffK: 0.03, priority: 1 };
8527
8870
  var casingSampleId = (sample) => sample.replace(/_(pistol|rifle|shell)$/, "");
@@ -8531,7 +8874,7 @@ var CUES_IN_SAMPLE = { mag_release: "mag_out", mag_insert: "mag_seat" };
8531
8874
  var isGunshot = (id) => GUNSHOT_SAMPLE_IDS.includes(id);
8532
8875
  function weaponSampleDefaults(sound3, overrides = {}) {
8533
8876
  if (sound3.category !== "armas") return void 0;
8534
- const base = sound3.id.startsWith("suppressed_") ? SUPPRESSED_SAMPLE : isGunshot(sound3.id) ? GUNSHOT_SAMPLE : sound3.id.startsWith("casing_drop_") || sound3.id.startsWith("mag_drop_") ? CASING_SAMPLE : RELOAD_SAMPLE;
8877
+ const base = LAUNCH_IDS.has(sound3.id) ? LAUNCH_SAMPLE : sound3.id.startsWith("suppressed_") ? SUPPRESSED_SAMPLE : isGunshot(sound3.id) ? GUNSHOT_SAMPLE : sound3.id.startsWith("casing_drop_") || sound3.id.startsWith("mag_drop_") ? CASING_SAMPLE : RELOAD_SAMPLE;
8535
8878
  return { ...base, ...overrides[sound3.id] };
8536
8879
  }
8537
8880
  function weaponSampleBank(options) {
@@ -8552,6 +8895,8 @@ function weaponSampleBank(options) {
8552
8895
  }
8553
8896
 
8554
8897
  // src/audio.ts
8898
+ var LAUNCH_SOUND_IDS = { grenade: "launcher_40mm", rocket: "rocket_launch" };
8899
+ var LAUNCH_HALF_AT = 40;
8555
8900
  var NOISE_SECONDS = 1.5;
8556
8901
  var DEFAULT_SEED = 1;
8557
8902
  function createWeaponAudio(volume = 0.6, options = {}) {
@@ -8560,15 +8905,15 @@ function createWeaponAudio(volume = 0.6, options = {}) {
8560
8905
  const distanceCurve = { ...GAME_DISTANCE_CURVE, ...options.distance };
8561
8906
  const mechanicalTable = { ...MECHANICAL_SOUNDS, ...options.mechanical };
8562
8907
  const cueTable = { ...RELOAD_CUES, ...options.reloadCues };
8563
- const shared = options.engine;
8564
- if (!shared) warnOnce("game-weapons-three.own-audio-engine", "game-weapons-three made an audio engine of its own because the host lent none (options.engine); pass the host engine so the sounds share one mix and one voice limit");
8565
- const engine = shared ?? createAudioEngine({
8908
+ const shared2 = options.engine;
8909
+ if (!shared2) warnOnce("game-weapons-three.own-audio-engine", "game-weapons-three made an audio engine of its own because the host lent none (options.engine); pass the host engine so the sounds share one mix and one voice limit");
8910
+ const engine = shared2 ?? createAudioEngine({
8566
8911
  seed,
8567
8912
  mix: { ...MIX_PROFILES.game, master: volume, noise: { seconds: NOISE_SECONDS, create: "eager" } },
8568
8913
  maxVoices: Number.POSITIVE_INFINITY,
8569
8914
  ...options.createContext ? { createContext: options.createContext } : {}
8570
8915
  });
8571
- const channel = shared && options.seed !== void 0 ? shared.channel({ seed }) : engine.channel({});
8916
+ const channel = shared2 && options.seed !== void 0 ? shared2.channel({ seed }) : engine.channel({});
8572
8917
  engine.register({ id: `weapons_three@${classBurstId(distanceCurve)}`, sounds: weaponRecipes(distanceCurve) });
8573
8918
  const classBurst = classBurstId(distanceCurve);
8574
8919
  const sampleBank = options.samples ? weaponSampleBank(options.samples) : null;
@@ -8758,13 +9103,24 @@ function createWeaponAudio(volume = 0.6, options = {}) {
8758
9103
  }
8759
9104
  burst({ seconds: 0.09, gain: 0.35 * (input.speed === void 0 ? 1 : Math.min(1, Math.max(0.3, input.speed / 2.5))) * ((input.bounce ?? 0) === 0 ? 1 : 0.5), filter: "lowpass", frequency: 380 });
8760
9105
  },
9106
+ launch(kind, volume2 = 1, distance = 0) {
9107
+ const level = Math.min(1, volume2 / (1 + distance / LAUNCH_HALF_AT));
9108
+ const id = LAUNCH_SOUND_IDS[kind];
9109
+ if (hostReady(id)) {
9110
+ channel.play(id, { volume: level });
9111
+ return;
9112
+ }
9113
+ burst({ seconds: kind === "rocket" ? 0.22 : 0.16, gain: 0.7 * level, filter: "lowpass", frequency: kind === "rocket" ? 220 : 170 });
9114
+ burst({ seconds: 0.035, gain: 0.25 * level, filter: "highpass", frequency: 1800 });
9115
+ if (kind === "rocket") burst({ seconds: 0.8, gain: 0.3 * level, filter: "highpass", frequency: 1100, at: 0.04 });
9116
+ },
8761
9117
  setVolume(next) {
8762
9118
  const level = Math.max(0, Math.min(1, next));
8763
- if (shared) shared.setBus("weapons", { gain: level });
9119
+ if (shared2) shared2.setBus("weapons", { gain: level });
8764
9120
  else engine.setMaster(level);
8765
9121
  },
8766
9122
  dispose() {
8767
- if (!shared) engine.dispose();
9123
+ if (!shared2) engine.dispose();
8768
9124
  }
8769
9125
  };
8770
9126
  }
@@ -9409,7 +9765,7 @@ function buildExplosiveModel(THREE, explosiveId) {
9409
9765
  // src/models/melee.ts
9410
9766
  import { markKitOrigin as markKitOrigin4 } from "@adatechnology/game-contracts";
9411
9767
  var QUARTER = Math.PI / 2;
9412
- var plate = (kit, parent, profile, thickness, y, material) => {
9768
+ var plate2 = (kit, parent, profile, thickness, y, material) => {
9413
9769
  const shape = new kit.THREE.Shape();
9414
9770
  profile.forEach(([x, z], index) => index === 0 ? shape.moveTo(x, -z) : shape.lineTo(x, -z));
9415
9771
  const mesh = new kit.THREE.Mesh(new kit.THREE.ExtrudeGeometry(shape, { depth: thickness, bevelEnabled: false }), material);
@@ -9428,7 +9784,7 @@ var kabar = (kit, group) => {
9428
9784
  box2(group, 7e-3, 0.012, 0.052, M.metal, 0.1325, axis, 0);
9429
9785
  box2(group, 0.012, 0.012, 4e-3, M.metal, 0.136, axis, 0.026);
9430
9786
  box2(group, 0.012, 0.012, 4e-3, M.metal, 0.136, axis, -0.026);
9431
- plate(kit, group, [[0.136, -0.0165], [0.248, -0.0165], [0.272, -0.0135], [0.2995, -6e-3], [0.3, -1e-3], [0.282, 8e-3], [0.255, 0.0165], [0.136, 0.0165]], 45e-4, axis - 225e-5, M.metal);
9787
+ plate2(kit, group, [[0.136, -0.0165], [0.248, -0.0165], [0.272, -0.0135], [0.2995, -6e-3], [0.3, -1e-3], [0.282, 8e-3], [0.255, 0.0165], [0.136, 0.0165]], 45e-4, axis - 225e-5, M.metal);
9432
9788
  box2(group, 0.095, 16e-4, 45e-4, M.dark, 0.19, axis + 23e-4, 6e-3);
9433
9789
  return { handle: [0.07, axis, 0] };
9434
9790
  };
@@ -9463,7 +9819,7 @@ var katana = (kit, group) => {
9463
9819
  spine.push([x, bow(t) + halfWidth(t)]);
9464
9820
  }
9465
9821
  const tip = [KATANA_TIP, bow(1) + 4e-3];
9466
- plate(kit, group, [...edge, tip, ...spine.reverse()], 55e-4, axis - 275e-5, M.steelL);
9822
+ plate2(kit, group, [...edge, tip, ...spine.reverse()], 55e-4, axis - 275e-5, M.steelL);
9467
9823
  return { handle: [0.2, axis, 0], support: [0.07, axis, 0] };
9468
9824
  };
9469
9825
  var RING_Z = [-0.0455, -0.0155, 0.0155, 0.0455];
@@ -12217,13 +12573,14 @@ function createViewmodel(options) {
12217
12573
  else if (tool.suppressed !== void 0) current.suppressed = tool.suppressed;
12218
12574
  else current.suppressed = hasSuppressor(tool.attachments ? fittedOf2(tool.attachments) : current.def.fitted ?? []);
12219
12575
  if (tool.underbarrelActive && current.model.parts.uglMuzzle) {
12220
- audio?.play("explosion", LAUNCH_VOLUME, distance());
12576
+ audio?.launch("grenade", LAUNCH_VOLUME, distance());
12221
12577
  return;
12222
12578
  }
12223
12579
  const action = current.def.action;
12224
12580
  if (action.kind === "launcher") {
12225
- if (current.model.parts.family === "rocket") launchRocket(heavy(current), options.flyRocket !== false);
12226
- audio?.play("explosion", LAUNCH_VOLUME, distance());
12581
+ const isRocket = current.model.parts.family === "rocket";
12582
+ if (isRocket) launchRocket(heavy(current), options.flyRocket !== false);
12583
+ audio?.launch(isRocket ? "rocket" : "grenade", LAUNCH_VOLUME, distance());
12227
12584
  }
12228
12585
  if (action.kind !== "firearm") return;
12229
12586
  const caliber = caliberOf(arsenal, current.def);
@@ -13965,7 +14322,7 @@ function createWeaponsTestModule(options = {}) {
13965
14322
  fx = created;
13966
14323
  const camera = lent.camera;
13967
14324
  const accessories = createAccessoryBench({ arsenal, host: lent, text: accessoryText });
13968
- const showcase = createWeaponShowcase({ arsenal, host: lent, text: showcaseText });
14325
+ const showcase = createWeaponShowcase({ arsenal, host: lent, text: showcaseText, referencePhotos: options.referencePhotos === true });
13969
14326
  const offBench = lent.bench?.onChange((change) => {
13970
14327
  if (accessories.handleChange(change) || showcase.handleChange(change)) return;
13971
14328
  if (change.kind === "layer") {
@@ -15059,12 +15416,14 @@ export {
15059
15416
  computeFlyby,
15060
15417
  GUNSHOT_SAMPLE_IDS,
15061
15418
  GUNSHOT_SAMPLE,
15419
+ LAUNCH_SAMPLE,
15062
15420
  RELOAD_SAMPLE,
15063
15421
  RELOAD_SAMPLE_HITS,
15064
15422
  WEIGHT_INTENSITY,
15065
15423
  CUES_IN_SAMPLE,
15066
15424
  weaponSampleDefaults,
15067
15425
  weaponSampleBank,
15426
+ LAUNCH_SOUND_IDS,
15068
15427
  createWeaponAudio,
15069
15428
  VIEW_HOLD,
15070
15429
  toWorldLens,
@@ -15123,4 +15482,4 @@ export {
15123
15482
  DEFAULT_EXPLOSIVES_SCENE,
15124
15483
  createExplosivesTestModule
15125
15484
  };
15126
- //# sourceMappingURL=chunk-V47DJ55G.js.map
15485
+ //# sourceMappingURL=chunk-SWR4BJMK.js.map