@adatechnology/game-weapons-three 0.18.0 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { I as ItemModels, W as WeaponProps, a as WeaponItemModel, M as ModelOptions, b as WeaponModel, c as ModelKit, d as ModelParts, e as ModelFamily, A as AttachmentModelRegistry, L as LaserRaycast } from './testing-CRjxCHxK.js';
2
- export { f as AttachmentBuildContext, g as AttachmentModel, h as AttachmentModelBuilder, C as CLASS_REFERENCE_ENERGY, i as COUNTER_ITEM_ID, j as CUES_IN_SAMPLE, k as CasingSound, l as CuePlayed, D as DEFAULT_ENERGY_CURVE, m as DEFAULT_EXPLOSIVES_SCENE, n as DistanceCurve, E as EXPLOSIVES_AREA_ID, o as EXPLOSIVES_TEXT, p as EnergyCurve, q as ExplosivesRoom, r as ExplosivesScene, s as ExplosivesTestModuleOptions, t as ExplosivesText, F as FlybySound, u as FxLayers, G as GAME_DISTANCE_CURVE, v as GAME_SOUND_CLASSES, w as GUNSHOT_PROFILES, x as GUNSHOT_SAMPLE, y as GUNSHOT_SAMPLE_IDS, z as Gunshot, B as GunshotInput, H as GunshotPlayed, J as ItemModelRequest, K as MECHANICAL_SOUNDS, N as MOUNTED_M134_ITEM_ID, O as MechanicalSoundId, P as ModelMaterials, Q as MountFrame, R as RELOAD_SAMPLE, S as RELOAD_SAMPLE_HITS, T as ShotExtras, U as ShotSound, V as ShotSoundClass, X as ShotSoundInput, Y as ShotSoundOptions, Z as SoundClassDef, _ as SoundStep, $ as WEAPON_ITEM_PREFIX, a0 as WEIGHT_INTENSITY, a1 as WeaponAudio, a2 as WeaponAudioOptions, a3 as WeaponFx, a4 as WeaponFxOptions, a5 as WeaponModelDef, a6 as WeaponSampleOptions, a7 as WeaponsTestModuleOptions, a8 as buildHandheldModel, a9 as buildItemWeaponModel, aa as buildThrowableModel, ab as buildWeaponModel, ac as computeCasingSound, ad as computeFlyby, ae as computeGunshot, af as computeShotSound, ag as createExplosivesTestModule, ah as createWeaponAudio, ai as createWeaponFx, aj as createWeaponsTestModule, ak as defaultWeaponProps, al as deriveFrames, am as explosivesTextOf, an as hasHandheldModel, ao as hasThrowableModel, ap as itemModelOfWeapon, aq as mechanicalSoundOf, ar as modelKit, as as mountFrame, at as registerWeaponItemModel, au as weaponSampleBank, av as weaponSampleDefaults, aw as weaponsLayout } from './testing-CRjxCHxK.js';
1
+ import { I as ItemModels, W as WeaponProps, a as WeaponItemModel, M as ModelOptions, b as WeaponModel, c as ModelKit, d as ModelParts, e as ModelFamily, A as AttachmentModelRegistry, L as LaserRaycast } from './testing-I8H8oNSD.js';
2
+ export { f as AttachmentBuildContext, g as AttachmentModel, h as AttachmentModelBuilder, C as CLASS_REFERENCE_ENERGY, i as COUNTER_ITEM_ID, j as CUES_IN_SAMPLE, k as CasingSound, l as CuePlayed, D as DEFAULT_ENERGY_CURVE, m as DEFAULT_EXPLOSIVES_SCENE, n as DistanceCurve, E as EXPLOSIVES_AREA_ID, o as EXPLOSIVES_TEXT, p as EnergyCurve, q as ExplosivesRoom, r as ExplosivesScene, s as ExplosivesTestModuleOptions, t as ExplosivesText, F as FlybySound, u as FxLayers, G as GAME_DISTANCE_CURVE, v as GAME_SOUND_CLASSES, w as GUNSHOT_PROFILES, x as GUNSHOT_SAMPLE, y as GUNSHOT_SAMPLE_IDS, z as Gunshot, B as GunshotInput, H as GunshotPlayed, J as ItemModelRequest, K as LAUNCH_SAMPLE, N as LAUNCH_SOUND_IDS, O as LaunchKind, P as MECHANICAL_SOUNDS, Q as MOUNTED_M134_ITEM_ID, R as MechanicalSoundId, S as ModelMaterials, T as MountFrame, U as RELOAD_SAMPLE, V as RELOAD_SAMPLE_HITS, X as ShotExtras, Y as ShotSound, Z as ShotSoundClass, _ as ShotSoundInput, $ as ShotSoundOptions, a0 as SoundClassDef, a1 as SoundStep, a2 as WEAPON_ITEM_PREFIX, a3 as WEIGHT_INTENSITY, a4 as WeaponAudio, a5 as WeaponAudioOptions, a6 as WeaponFx, a7 as WeaponFxOptions, a8 as WeaponModelDef, a9 as WeaponSampleOptions, aa as WeaponsTestModuleOptions, ab as buildHandheldModel, ac as buildItemWeaponModel, ad as buildThrowableModel, ae as buildWeaponModel, af as computeCasingSound, ag as computeFlyby, ah as computeGunshot, ai as computeShotSound, aj as createExplosivesTestModule, ak as createWeaponAudio, al as createWeaponFx, am as createWeaponsTestModule, an as defaultWeaponProps, ao as deriveFrames, ap as explosivesTextOf, aq as hasHandheldModel, ar as hasThrowableModel, as as itemModelOfWeapon, at as mechanicalSoundOf, au as modelKit, av as mountFrame, aw as registerWeaponItemModel, ax as weaponSampleBank, ay as weaponSampleDefaults, az as weaponsLayout } from './testing-I8H8oNSD.js';
3
3
  import * as THREE_NS from 'three';
4
4
  import { TestableItem, Vec3, HostEvent, EffectSink, DestructibleSpec, DeepPartial, ToolClipSet } from '@adatechnology/game-contracts';
5
5
  import { ExplosiveDef, Arsenal, WeaponDef, CartridgeDims, CaliberDef, CaseType, ReloadFamily, FittedAttachment, AttachmentDef } from '@adatechnology/game-weapons';
@@ -38,6 +38,8 @@ var GameWeaponsThree = (() => {
38
38
  GUNSHOT_PROFILES: () => GUNSHOT_PROFILES,
39
39
  GUNSHOT_SAMPLE: () => GUNSHOT_SAMPLE,
40
40
  GUNSHOT_SAMPLE_IDS: () => GUNSHOT_SAMPLE_IDS,
41
+ LAUNCH_SAMPLE: () => LAUNCH_SAMPLE,
42
+ LAUNCH_SOUND_IDS: () => LAUNCH_SOUND_IDS,
41
43
  MECHANICAL_SOUNDS: () => MECHANICAL_SOUNDS,
42
44
  MODEL_ENTRIES: () => MODEL_ENTRIES,
43
45
  MOUNTED_M134_ITEM_ID: () => MOUNTED_M134_ITEM_ID,
@@ -24634,23 +24636,42 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24634
24636
  const v = table[mat.penetrationClass ?? mat.id] ?? table[mat.id];
24635
24637
  return v === void 0 ? void 0 : v * (mat.penetrationScale ?? 1);
24636
24638
  };
24637
- var capacityScale = (p) => {
24639
+ var BURIED_BLAST_REACH = 0.5;
24640
+ var GIVE_AT_CUT_HP = 0.5;
24641
+ var capacityScale = (p, borne, through) => {
24638
24642
  const residual = p.spec.reinforcement?.residualCapacity ?? RESIDUAL_CAPACITY;
24639
24643
  if (p.st.stripped) return residual;
24640
- const kept = Math.min(p.rt.removed ? 1 - p.rt.removed / p.mass0 : 1, 1 - sectionLoss(p));
24644
+ const kept = Math.min(p.rt.removed ? 1 - p.rt.removed / p.mass0 : 1, sectionKept(p, residual, borne, through));
24641
24645
  return Math.max(p.spec.reinforcement ? residual : 0.05, kept);
24642
24646
  };
24643
- var sectionLoss = (p) => {
24647
+ var sectionKept = (p, residual, borne, through) => {
24648
+ let kept = 1;
24649
+ forEachSection(p, borne, (c, along, gone) => {
24650
+ const share = through?.(c.center, along) ?? 1;
24651
+ if (share <= 0) return;
24652
+ kept = Math.min(kept, Math.max(p.spec.reinforcement ? residual : 0, 1 - gone) / share);
24653
+ });
24654
+ return kept;
24655
+ };
24656
+ var sectionLoss = (p, borne) => {
24657
+ let worst = 0;
24658
+ forEachSection(p, borne, (_c, _along, gone) => {
24659
+ worst = Math.max(worst, gone);
24660
+ });
24661
+ return Math.min(1, worst);
24662
+ };
24663
+ var forEachSection = (p, borne, visit) => {
24644
24664
  const cells = p.st.chipped;
24645
- if (!cells?.length) return 0;
24665
+ if (!cells?.length) return;
24646
24666
  const [u, v] = planeAxes(p.thin);
24647
24667
  const role = p.spec.structure?.role;
24648
24668
  const up = rotateVec(p.q, [0, 0, 0].map((_, k) => k === v ? 1 : 0));
24649
24669
  const upright = Math.abs(up[1]) > 0.7 ? v : Math.abs(rotateVec(p.q, [0, 0, 0].map((_, k) => k === u ? 1 : 0))[1]) > 0.7 ? u : -1;
24650
24670
  const along = (role === "wall" || role === "partition" || role === "column") && upright >= 0 ? upright : p.dims[u] >= p.dims[v] ? u : v;
24651
24671
  const across2 = along === u ? v : u;
24652
- let worst = 0;
24672
+ const lying = along !== upright || upright < 0;
24653
24673
  for (const c of cells) {
24674
+ if (lying && borne?.(c.center, along)) continue;
24654
24675
  const spans = [];
24655
24676
  for (const d of cells) if (Math.abs(d.center[along] - c.center[along]) < d.size[along] / 2 + 1e-6) spans.push([d.center[across2] - d.size[across2] / 2, d.center[across2] + d.size[across2] / 2]);
24656
24677
  spans.sort((a, b) => a[0] - b[0]);
@@ -24660,9 +24681,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24660
24681
  gone += b - Math.max(a, end3);
24661
24682
  end3 = b;
24662
24683
  }
24663
- worst = Math.max(worst, gone / Math.max(p.dims[across2], 1e-6));
24684
+ visit(c, along, Math.min(1, gone / Math.max(p.dims[across2], 1e-6)));
24664
24685
  }
24665
- return Math.min(1, worst);
24666
24686
  };
24667
24687
  var isLost = (p) => p.st.status === "broken" || p.st.status === "melted" || p.st.status === "ashes";
24668
24688
  var clone = (v) => structuredClone(v);
@@ -24973,6 +24993,26 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24973
24993
  byTouching.set(support, { version: poseVersion, box: box5 });
24974
24994
  return box5;
24975
24995
  };
24996
+ const throughOf = (p) => {
24997
+ const load = p.st.load ?? 0;
24998
+ if (load <= 0) return void 0;
24999
+ const above2 = Math.max(0, load - p.st.mass);
25000
+ const up = rotateVec(p.q, [0, 1, 0]);
25001
+ return (local2, along) => {
25002
+ const axis2 = [0, 0, 0];
25003
+ axis2[along] = 1;
25004
+ const sign2 = Math.sign(rotateVec(p.q, axis2)[1]);
25005
+ if (Math.abs(up[1]) < 0.7 && Math.abs(rotateVec(p.q, axis2)[1]) < 0.7) return 1;
25006
+ const half = p.dims[along] / 2;
25007
+ const share = clamp2((half - sign2 * local2[along]) / Math.max(p.dims[along], 1e-6), 0, 1);
25008
+ return (above2 + p.st.mass * share) / load;
25009
+ };
25010
+ };
25011
+ const borneOn = (p, supports) => {
25012
+ if (supports.length === 0) return void 0;
25013
+ const boxes = supports.map((support) => contactBox(p, support));
25014
+ return (local2, along) => boxes.some(([lo, hi]) => local2[along] >= lo[along] - SUPPORT_TOLERANCE && local2[along] <= hi[along] + SUPPORT_TOLERANCE);
25015
+ };
24976
25016
  const measureContact = (p, support) => {
24977
25017
  const A = aabbOf(p.spec.shape, p.pos, p.q), B = aabbOf(support.spec.shape, support.pos, support.q);
24978
25018
  const lo = [0, 0, 0], hi = [0, 0, 0];
@@ -25180,7 +25220,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25180
25220
  o.unsup[i] = o.anyAnchor && !isLost(p) && !p.orphan;
25181
25221
  continue;
25182
25222
  }
25183
- p.st.stress = p.st.load * structureSafety / (p.cap * capacityScale(p));
25223
+ p.st.stress = p.st.load * structureSafety / (p.cap * capacityScale(p, borneOn(p, (lowerOf.get(i) ?? []).map((k) => parts[k])), throughOf(p)));
25184
25224
  if (p.bend) {
25185
25225
  p.bendLoad = p.st.mass + bending[i];
25186
25226
  const bent = restFlexure(o, p, lowerOf.get(i) ?? []);
@@ -26270,6 +26310,27 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26270
26310
  debris2(o, p, p.mat.breakDebris, center, [0, -1, 0], 6, 1, src);
26271
26311
  return loose.length;
26272
26312
  };
26313
+ const giveAtCut = (o, p, src) => {
26314
+ if (!p.spec.reinforcement || !p.spec.units || !p.st.chipped?.length || sectionLoss(p) <= 0) return false;
26315
+ const opened = [];
26316
+ for (const j of o.byPart.get(p.spec.id) ?? []) {
26317
+ if (j.st.open) continue;
26318
+ const onIt = j.bears === "a_on_b" && j.spec.b === p.spec.id || j.bears === "b_on_a" && j.spec.a === p.spec.id;
26319
+ if (!onIt) continue;
26320
+ j.st.open = true;
26321
+ j.st.openedBy = "break";
26322
+ opened.push(j);
26323
+ }
26324
+ if (opened.length === 0) return false;
26325
+ p.st.hp = Math.max(p.st.hp, p.st.maxHp * GIVE_AT_CUT_HP);
26326
+ markDamaged(p);
26327
+ solveStructure(o);
26328
+ recomputeGroups(o);
26329
+ detachEvents(o, opened, "break", src);
26330
+ exposeRebar(o, p, src);
26331
+ collapseCheck(o, src);
26332
+ return true;
26333
+ };
26273
26334
  const stripPart = (o, p, reinforcement, src) => {
26274
26335
  const bars = rebarBars(p.dims, p.thin, reinforcement.spacing);
26275
26336
  p.st.stripped = true;
@@ -26327,6 +26388,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26327
26388
  hingeDrop(o, p, src);
26328
26389
  return;
26329
26390
  }
26391
+ if (!force && giveAtCut(o, p, src)) return;
26330
26392
  const ex = p.spec.explodes;
26331
26393
  const style = force ?? (p.snap ? "snap" : p.mat.fracture === "none" ? "snap" : p.mat.fracture);
26332
26394
  const { c, q } = partXf(o, p);
@@ -26673,7 +26735,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26673
26735
  const dx = local2[0] - p.pos[0];
26674
26736
  const dy = local2[1] - p.pos[1];
26675
26737
  const dz = local2[2] - p.pos[2];
26676
- if (dx * dx + dy * dy + dz * dz < reach * reach) near.push(p);
26738
+ if (dx * dx + dy * dy + dz * dz >= reach * reach) continue;
26739
+ if (p.spec.anchored && p.spec.structure?.role === "foundation" && distToPart(o, p, point) > BURIED_BLAST_REACH) continue;
26740
+ near.push(p);
26677
26741
  }
26678
26742
  blastProbe.partsTested += o.parts.length;
26679
26743
  blastProbe.partsNear += near.length;
@@ -29873,7 +29937,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29873
29937
  }
29874
29938
  var towerLocales = { en: { labels: en_default.labels }, "pt-BR": { labels: pt_BR_default.labels } };
29875
29939
 
29876
- // ../game-floorplan-three/dist/chunk-JZQA7G63.js
29940
+ // ../game-floorplan-three/dist/chunk-PJ4WEP6U.js
29877
29941
  var __defProp3 = Object.defineProperty;
29878
29942
  var __defNormalProp2 = (obj, key2, value) => key2 in obj ? __defProp3(obj, key2, { enumerable: true, configurable: true, writable: true, value }) : obj[key2] = value;
29879
29943
  var __publicField2 = (obj, key2, value) => __defNormalProp2(obj, typeof key2 !== "symbol" ? key2 + "" : key2, value);
@@ -32772,8 +32836,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32772
32836
  const defined = { electricalStructure, pipe2 };
32773
32837
  Object.assign(K, defined);
32774
32838
  }
32839
+ var BASEBOARD_TILES = { length: 0.6, joint: 3e-3, material: "ceramic", density: 2300 };
32840
+ var SIDEWALK_SLABS = { length: 1.2, joint: 0.01, material: "concrete", density: 2400 };
32775
32841
  function installHouseBaseboard(K, shared2) {
32776
- const { Y0, bx, cursor, sideOf } = K;
32842
+ const { Y0, bx, cursor, pieceRecord, sideOf } = K;
32777
32843
  const sh = (...a) => K.sh(...a);
32778
32844
  function baseboardAndSidewalk() {
32779
32845
  const R = shared2.ctx.r, W = 0.6, t = 0.012, ht = 0.35, color2 = sh(shared2.ctx.colors.facade != null ? shared2.ctx.colors.facade : 14209216, 0.62), y0 = Y0(0), cal = 13947078;
@@ -32795,15 +32861,29 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32795
32861
  };
32796
32862
  for (const A of ws) for (const [side, sd] of [[A.w.sides[0], -1], [A.w.sides[1], 1]]) {
32797
32863
  if (!sideOf(side, false).exterior) continue;
32798
- const strip = (k, y1, y2, o0, o1, mat, c, y1b) => {
32864
+ const strip = (k, y1, y2, o0, o1, mat, c, piece2, laid = BASEBOARD_TILES) => {
32799
32865
  const ea = junction(A, A.a, sd) > 0 ? A.th / 2 + k : junction(A, A.a, sd) < 0 ? -A.th / 2 : 0, eb = junction(A, A.b, sd) > 0 ? A.th / 2 + k : junction(A, A.b, sd) < 0 ? -A.th / 2 : 0;
32800
32866
  const s0 = A.a - ea, s1 = A.b + eb, f0 = A.L + sd * (A.th / 2 + o0), f1 = A.L + sd * (A.th / 2 + o1), lo = Math.min(f0, f1), hi = Math.max(f0, f1);
32801
32867
  if (s1 - s0 < 1e-3) return;
32802
- if (A.au) bx(mat, s0, y1, lo, s1, y2, hi, c);
32803
- else bx(mat, lo, y1, s0, hi, y2, s1, c);
32868
+ const box5 = (a, b) => {
32869
+ if (A.au) bx(mat, a, y1, lo, b, y2, hi, c);
32870
+ else bx(mat, lo, y1, a, hi, y2, b, c);
32871
+ };
32872
+ const tag = laid === BASEBOARD_TILES ? "baseboard" : "sidewalk";
32873
+ const tile = (id, a, b) => {
32874
+ cursor.pc = pieceRecord(id, laid.material, null, { floor: 0, mass: Math.round((b - a) * (y2 - y1) * (hi - lo) * laid.density * 100) / 100, tags: [tag] });
32875
+ box5(a, b);
32876
+ };
32877
+ if (!piece2) box5(s0, s1);
32878
+ else if (shared2.ctx.baseboardBand) tile(piece2, s0, s1);
32879
+ else {
32880
+ const n = Math.max(1, Math.round((s1 - s0) / laid.length)), w = (s1 - s0) / n, j = laid.joint / 2;
32881
+ for (let i = 0; i < n; i++) tile(`${piece2}:${i}`, s0 + i * w + (i > 0 ? j : 0), s0 + (i + 1) * w - (i < n - 1 ? j : 0));
32882
+ }
32883
+ cursor.pc = null;
32804
32884
  };
32805
- strip(t, y0, y0 + ht, 0, t, "plaster", color2);
32806
- strip(W, y0, y0 + 0.045, 0, W, "sidewalk", cal);
32885
+ strip(t, y0, y0 + ht, 0, t, "plaster", color2, A.w.id ? `baseboard:${A.w.id}:${sd < 0 ? 0 : 1}` : void 0);
32886
+ strip(W, y0, y0 + 0.045, 0, W, "sidewalk", cal, A.w.id ? `sidewalk:${A.w.id}:${sd < 0 ? 0 : 1}` : void 0, SIDEWALK_SLABS);
32807
32887
  }
32808
32888
  }
32809
32889
  const defined = { baseboardAndSidewalk };
@@ -36173,7 +36253,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
36173
36253
  if (!b) continue;
36174
36254
  const vol = Math.max(1e-6, (b[3] - b[0]) * (b[4] - b[1]) * (b[5] - b[2]));
36175
36255
  const p = { id, role: "none", material: pc.mat, aabb: [b[0], b[2], b[3], b[5]], y0: b[1], y1: b[4], floor: pc.floor != null ? pc.floor : floorAtY(b[1] + 0.1), mass: pc.mass != null ? pc.mass : Math.max(0.5, vol * (DENSITY[pc.mat] || 800) * (pc.fill != null ? pc.fill : 0.15)), meshes: meshes.get(id).length, extra: true };
36176
- for (const k of ["contains", "explodes", "tags", "form", "thickness", "fill"]) if (pc[k] != null) p[k] = pc[k];
36256
+ for (const k of ["contains", "explodes", "tags", "form", "thickness", "fill", "units"]) if (pc[k] != null) p[k] = pc[k];
36177
36257
  parts.push(p);
36178
36258
  byId.set(id, p);
36179
36259
  }
@@ -36182,7 +36262,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
36182
36262
  return cx >= q.aabb[0] - m && cx <= q.aabb[2] + m && cz >= q.aabb[1] - m && cz <= q.aabb[3] + m && cy >= q.y0 - m && cy <= q.y1 + m;
36183
36263
  };
36184
36264
  for (const p of parts.slice(base)) {
36185
- if (!/^(window|window_pane|door|jamb|pipe|water_tank)/.test(p.id)) continue;
36265
+ if (/^sidewalk:/.test(p.id)) {
36266
+ supports.push({ part: p.id, on: "ground", joint: "mortar", extra: true });
36267
+ continue;
36268
+ }
36269
+ if (!/^(window|window_pane|door|jamb|pipe|water_tank|baseboard)/.test(p.id)) continue;
36186
36270
  const target = /^water_tank/.test(p.id) ? ["slab"] : ["wall", "partition"];
36187
36271
  let m = null, md = 1e9;
36188
36272
  for (const q of parts.slice(0, base)) {
@@ -36193,7 +36277,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
36193
36277
  m = q;
36194
36278
  }
36195
36279
  }
36196
- if (m) supports.push({ part: p.id, on: m.id, joint: /^(window|jamb)/.test(p.id) ? "glue" : "clip", bears: false, extra: true });
36280
+ if (m) supports.push({ part: p.id, on: m.id, joint: /^(window|jamb|baseboard)/.test(p.id) ? "glue" : "clip", bears: false, extra: true });
36197
36281
  }
36198
36282
  const specParts = parts.slice(), specSupports = supports.slice();
36199
36283
  if (view.panels.length) {
@@ -37289,6 +37373,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
37289
37373
  cursor.separate = opts.pieces === "meshes";
37290
37374
  cursor.pc = null;
37291
37375
  shared2.ctx.showPillars = opts.pillars !== "hidden";
37376
+ shared2.ctx.baseboardBand = opts.baseboard === "band";
37292
37377
  shared2.ctx.apartment = r.template === "apartment_modern";
37293
37378
  shared2.ctx.pa = Math.max(3, Math.min(20, pr.floors != null ? pr.floors : 5));
37294
37379
  shared2.ctx.pf = Math.max(1, Math.min(shared2.ctx.pa, pr.floor != null ? pr.floor : 3));
@@ -45985,7 +46070,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
45985
46070
  return { id: options.id, samples };
45986
46071
  }
45987
46072
 
45988
- // ../game-audio/dist/chunk-UUWKSG4J.js
46073
+ // ../game-audio/dist/chunk-BUYBYP4L.js
45989
46074
  var DISTANCE_CURVES = {
45990
46075
  /** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
45991
46076
  game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
@@ -48380,6 +48465,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
48380
48465
  ["revolver_38_357", 2, "sfx_pistol"],
48381
48466
  ["revolver_44_50ae", 3, "sfx_pistol"],
48382
48467
  ["smg_9mm_auto", 1, "sfx_pistol"],
48468
+ ["launcher_40mm", 2],
48469
+ ["rocket_launch", 2],
48383
48470
  ["shotgun_12", 1, "sfx_shotgun"],
48384
48471
  ["rifle_5_56", 1, "sfx_rifle"],
48385
48472
  ["rifle_7_62x39", 1, "sfx_rifle"],
@@ -51520,6 +51607,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
51520
51607
  priority: 3
51521
51608
  };
51522
51609
  var SUPPRESSED_SAMPLE = { ...GUNSHOT_SAMPLE, gain: 0.55, crossover: { from: 10, to: 50 }, falloff: { model: "inverse_square", k: 4e-3, minGain: 8e-4 } };
51610
+ 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 };
51611
+ var LAUNCH_IDS = /* @__PURE__ */ new Set(["launcher_40mm", "rocket_launch"]);
51523
51612
  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 };
51524
51613
  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 };
51525
51614
  var casingSampleId = (sample) => sample.replace(/_(pistol|rifle|shell)$/, "");
@@ -51529,7 +51618,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
51529
51618
  var isGunshot = (id) => GUNSHOT_SAMPLE_IDS.includes(id);
51530
51619
  function weaponSampleDefaults(sound3, overrides = {}) {
51531
51620
  if (sound3.category !== "armas") return void 0;
51532
- 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;
51621
+ 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;
51533
51622
  return { ...base, ...overrides[sound3.id] };
51534
51623
  }
51535
51624
  function weaponSampleBank(options) {
@@ -51550,6 +51639,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
51550
51639
  }
51551
51640
 
51552
51641
  // src/audio.ts
51642
+ var LAUNCH_SOUND_IDS = { grenade: "launcher_40mm", rocket: "rocket_launch" };
51643
+ var LAUNCH_HALF_AT = 40;
51553
51644
  var NOISE_SECONDS = 1.5;
51554
51645
  var DEFAULT_SEED = 1;
51555
51646
  function createWeaponAudio(volume = 0.6, options = {}) {
@@ -51756,6 +51847,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
51756
51847
  }
51757
51848
  burst2({ 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 });
51758
51849
  },
51850
+ launch(kind, volume2 = 1, distance3 = 0) {
51851
+ const level = Math.min(1, volume2 / (1 + distance3 / LAUNCH_HALF_AT));
51852
+ const id = LAUNCH_SOUND_IDS[kind];
51853
+ if (hostReady(id)) {
51854
+ channel.play(id, { volume: level });
51855
+ return;
51856
+ }
51857
+ burst2({ seconds: kind === "rocket" ? 0.22 : 0.16, gain: 0.7 * level, filter: "lowpass", frequency: kind === "rocket" ? 220 : 170 });
51858
+ burst2({ seconds: 0.035, gain: 0.25 * level, filter: "highpass", frequency: 1800 });
51859
+ if (kind === "rocket") burst2({ seconds: 0.8, gain: 0.3 * level, filter: "highpass", frequency: 1100, at: 0.04 });
51860
+ },
51759
51861
  setVolume(next) {
51760
51862
  const level = Math.max(0, Math.min(1, next));
51761
51863
  if (shared2) shared2.setBus("weapons", { gain: level });
@@ -66851,8 +66953,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
66851
66953
  id: "dust",
66852
66954
  additive: false,
66853
66955
  life: [
66854
- 1,
66855
- 2
66956
+ 2,
66957
+ 5
66856
66958
  ],
66857
66959
  size: [
66858
66960
  0.08,
@@ -66919,8 +67021,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
66919
67021
  id: "chips",
66920
67022
  additive: false,
66921
67023
  life: [
66922
- 0.8,
66923
- 1.5
67024
+ 2,
67025
+ 4
66924
67026
  ],
66925
67027
  size: [
66926
67028
  0.025,
@@ -68336,7 +68438,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
68336
68438
  };
68337
68439
  }
68338
68440
 
68339
- // ../game-vfx-three/dist/chunk-CPRCWTSQ.js
68441
+ // ../game-vfx-three/dist/chunk-IOGYK5RO.js
68340
68442
  var GLOW_VERTEX = `attribute vec4 aP;attribute vec4 aC;varying vec2 vU;varying vec4 vC;
68341
68443
  void main(){vec3 R=vec3(viewMatrix[0][0],viewMatrix[1][0],viewMatrix[2][0]);vec3 Up=vec3(viewMatrix[0][1],viewMatrix[1][1],viewMatrix[2][1]);
68342
68444
  vec3 wp=aP.xyz+(R*position.x+Up*position.y)*aP.w;vU=position.xy;vC=aC;gl_Position=projectionMatrix*viewMatrix*vec4(wp,1.);}`;
@@ -68383,10 +68485,15 @@ void main(){
68383
68485
  if(n<diss*1.08-.04)discard;
68384
68486
  float lam=max(dot(N,uLight),0.);
68385
68487
  float band=lam>.55?1.:lam>.15?.68:.42;
68386
- vec3 col=vC*(vec3(.5,.56,.7)*band*1.05+vec3(.2,.19,.18)+uGround*(.4-.4*N.y));
68488
+ // soot: a dark smoke still scatters some light, so it never goes flat black, and its rim takes the sky so its volume reads (only the dark puffs; the rest as the Lab)
68489
+ float dark=1.-smoothstep(.02,.12,dot(vC,vec3(.2126,.7152,.0722)));
68490
+ vec3 alb=max(vC,vec3(.055)*dark);
68491
+ vec3 col=alb*(vec3(.5,.56,.7)*band*1.05+vec3(.2,.19,.18)+uGround*(.4-.4*N.y));
68492
+ float rim=pow(1.-clamp(abs(dot(N,normalize(cameraPosition-vWP))),0.,1.),2.);
68493
+ col+=dark*rim*(uSky*.9+alb);
68387
68494
  vec3 tg=uGlowPos-vWP;float dg=length(tg)+.001;
68388
68495
  float gi=uGlowI/(1.+dg*dg*.05)*(.3+.7*max(dot(N,tg/dg),0.));
68389
- col+=uGlowCol*gi*vC*1.6;
68496
+ col+=uGlowCol*gi*alb*1.6;
68390
68497
  float h=heat*(.72+.56*n)+heat*(-N.y)*.18;
68391
68498
  if(h>.05){
68392
68499
  float hq=floor(h*5.+.5)/5.;
@@ -71140,13 +71247,14 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
71140
71247
  else if (tool2.suppressed !== void 0) current.suppressed = tool2.suppressed;
71141
71248
  else current.suppressed = hasSuppressor(tool2.attachments ? fittedOf2(tool2.attachments) : current.def.fitted ?? []);
71142
71249
  if (tool2.underbarrelActive && current.model.parts.uglMuzzle) {
71143
- audio?.play("explosion", LAUNCH_VOLUME, distance3());
71250
+ audio?.launch("grenade", LAUNCH_VOLUME, distance3());
71144
71251
  return;
71145
71252
  }
71146
71253
  const action = current.def.action;
71147
71254
  if (action.kind === "launcher") {
71148
- if (current.model.parts.family === "rocket") launchRocket(heavy(current), options.flyRocket !== false);
71149
- audio?.play("explosion", LAUNCH_VOLUME, distance3());
71255
+ const isRocket = current.model.parts.family === "rocket";
71256
+ if (isRocket) launchRocket(heavy(current), options.flyRocket !== false);
71257
+ audio?.launch(isRocket ? "rocket" : "grenade", LAUNCH_VOLUME, distance3());
71150
71258
  }
71151
71259
  if (action.kind !== "firearm") return;
71152
71260
  const caliber = caliberOf(arsenal, current.def);