@adatechnology/game-weapons-three 0.15.0 → 0.17.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.
@@ -44,6 +44,8 @@ var GameWeaponsThree = (() => {
44
44
  P13_VALVE_MESH: () => P13_VALVE_MESH,
45
45
  RELOAD_SAMPLE: () => RELOAD_SAMPLE,
46
46
  RELOAD_SAMPLE_HITS: () => RELOAD_SAMPLE_HITS,
47
+ VIEW_HOLD: () => VIEW_HOLD,
48
+ VIEW_MOTION: () => VIEW_MOTION,
47
49
  WEAPON_ITEM_PREFIX: () => WEAPON_ITEM_PREFIX,
48
50
  WEAPON_THUMBNAILS: () => WEAPON_THUMBNAILS,
49
51
  WEIGHT_INTENSITY: () => WEIGHT_INTENSITY,
@@ -91,6 +93,7 @@ var GameWeaponsThree = (() => {
91
93
  registerWeaponItemModel: () => registerWeaponItemModel,
92
94
  rigStock: () => rigStock,
93
95
  rigUnderbarrel: () => rigUnderbarrel,
96
+ toWorldLens: () => toWorldLens,
94
97
  weaponProp: () => weaponProp,
95
98
  weaponSampleBank: () => weaponSampleBank,
96
99
  weaponSampleDefaults: () => weaponSampleDefaults,
@@ -165,6 +168,7 @@ var GameWeaponsThree = (() => {
165
168
  const flame = flameBase * (1 - rules.flameFillInfluence * (1 - k));
166
169
  return 1 - (1 - Math.min(1, Math.max(0, spark))) * (1 - Math.min(1, Math.max(0, flame)));
167
170
  };
171
+ var FIRST_PERSON_LAYER = 9;
168
172
  var TOOL_CLIP = {
169
173
  DRAW: "draw",
170
174
  SHOT: "shot",
@@ -12148,7 +12152,9 @@ var GameWeaponsThree = (() => {
12148
12152
  dimensions: {
12149
12153
  length: 0.801,
12150
12154
  barrel: 0.559,
12151
- emptyMass: 39
12155
+ emptyMass: 39,
12156
+ barrels: 6,
12157
+ barrelMass: 2
12152
12158
  },
12153
12159
  archetype: "rifle_7_62x39",
12154
12160
  sources: [
@@ -13128,19 +13134,41 @@ var GameWeaponsThree = (() => {
13128
13134
  }
13129
13135
  };
13130
13136
  var DEFAULT_HEAT = {
13131
- cap: 140,
13132
- displayMax: 120,
13133
- decayBase: 1.6,
13134
- decayPerPoint: 0.03,
13135
- faultFrom: 60,
13136
- faultSpan: 40,
13137
- perShot: { shell: 3, big: 6, tiny: 0.5, pistol: 1.2, rifle: 2 },
13137
+ cap: 900,
13138
+ displayMax: 750,
13139
+ faultFrom: 350,
13140
+ faultSpan: 200,
13141
+ specificHeat: 490,
13142
+ barrelShare: { shell: 0.48, big: 0.48, tiny: 0.3, pistol: 0.3, rifle: 0.48 },
13143
+ barrelKilogramsPerMetre: {
13144
+ pistol: 1,
13145
+ revolver: 1.4,
13146
+ smg: 1.2,
13147
+ carbine: 1.6,
13148
+ rifle: 1.6,
13149
+ dmr: 2.4,
13150
+ sniper: 2.4,
13151
+ hunting: 2.4,
13152
+ machine_gun: 3,
13153
+ shotgun: 1.1
13154
+ },
13155
+ barrelFallback: { metres: 0.4, kilogramsPerMetre: 1.6 },
13156
+ cooling: { baseSeconds: 30, secondsPerKilogram: 250 },
13138
13157
  perRocket: 35,
13139
- visual: { smokeFrom: 70, smokeSeconds: 2.5, glowFrom: 80, glowSpan: 40 }
13158
+ visual: { smokeFrom: 250, smokeSpan: 300, smokeSeconds: 2.5, glowFrom: 450, glowSpan: 300 }
13140
13159
  };
13141
13160
  var GALLERY_HEAT = {
13142
13161
  ...DEFAULT_HEAT,
13143
- perShot: { shell: 6, big: 9, tiny: 1.2, pistol: 3, rifle: 4.5 }
13162
+ cap: 140,
13163
+ displayMax: 120,
13164
+ faultFrom: 60,
13165
+ faultSpan: 40,
13166
+ visual: { smokeFrom: 70, smokeSpan: 100, smokeSeconds: 2.5, glowFrom: 80, glowSpan: 40 },
13167
+ gallery: {
13168
+ perShot: { shell: 6, big: 9, tiny: 1.2, pistol: 3, rifle: 4.5 },
13169
+ decayBase: 1.6,
13170
+ decayPerPoint: 0.03
13171
+ }
13144
13172
  };
13145
13173
  var defaultFaultChance = (context) => {
13146
13174
  const factor = context.def.action.kind === "firearm" ? context.def.action.faultFactor ?? 1 : 1;
@@ -13423,17 +13451,76 @@ var GameWeaponsThree = (() => {
13423
13451
  ...explosive.stunSeconds !== void 0 ? { stunSeconds: explosive.stunSeconds } : {}
13424
13452
  };
13425
13453
  };
13454
+ var EPS2 = 1e-9;
13455
+ var MANUAL_MODES = /* @__PURE__ */ new Set(["pump", "bolt", "lever"]);
13456
+ var weaponSpeed = (action, caliber) => action.muzzleSpeed ?? caliber.muzzleSpeed * (action.barrel ?? 1);
13457
+ var weaponNoise = (action, caliber) => action.noise ?? caliber.noise ?? 0;
13458
+ var timingsOf = (action) => "timings" in action ? action.timings : void 0;
13459
+ var drawSeconds = (action, rules) => timingsOf(action)?.draw ?? rules.draw;
13460
+ var clearSeconds = (action, rules) => timingsOf(action)?.clear ?? rules.clear;
13461
+ var manualCycleSeconds = (action, mode) => MANUAL_MODES.has(mode) ? action.timings?.cycle ?? 0 : 0;
13462
+ var planRounds = (action, mode, ammo, firstAt, frameEnd) => {
13463
+ const interval = 60 / action.rpm;
13464
+ const times = [];
13465
+ if (mode === "auto") {
13466
+ for (let t = firstAt; times.length < ammo && (times.length === 0 ? t <= frameEnd + EPS2 : t < frameEnd - EPS2); t += interval) times.push(t);
13467
+ return times;
13468
+ }
13469
+ if (mode === "burst") {
13470
+ const count = Math.min(action.burst ?? 3, ammo);
13471
+ for (let k = 0; k < count; k++) times.push(firstAt + k * interval);
13472
+ return times;
13473
+ }
13474
+ if (mode === "volley") return Array.from({ length: Math.min(action.magazine, ammo) }, () => firstAt);
13475
+ return [firstAt];
13476
+ };
13426
13477
  var SUBSTEP_SECONDS = 1 / 60;
13427
- var decayHeat = (heat, seconds, rules) => {
13478
+ var MAX_ROUNDS_SEARCHED = 1e5;
13479
+ var barrelMassOf = (def, rules) => {
13480
+ const dimensions = def.dimensions;
13481
+ const kilogramsPerMetre = rules.barrelKilogramsPerMetre[def.category] ?? rules.barrelFallback.kilogramsPerMetre;
13482
+ const single = dimensions?.barrelMass ?? (dimensions?.barrel ?? rules.barrelFallback.metres) * kilogramsPerMetre;
13483
+ return single * (dimensions?.barrels ?? 1);
13484
+ };
13485
+ var coolingTimeConstant = (barrelMass, rules) => rules.cooling.baseSeconds + rules.cooling.secondsPerKilogram * barrelMass;
13486
+ var decayHeat = (heat, seconds, barrelMass, rules) => {
13487
+ if (heat <= 0) return 0;
13488
+ if (rules.gallery) return decayGallery(heat, seconds, rules.gallery);
13489
+ return heat * Math.exp(-seconds / coolingTimeConstant(barrelMass, rules));
13490
+ };
13491
+ var decayGallery = (heat, seconds, gallery) => {
13428
13492
  const steps = Math.max(1, Math.ceil(seconds / SUBSTEP_SECONDS - 1e-9));
13429
13493
  const step = seconds / steps;
13430
13494
  let current = heat;
13431
- for (let i = 0; i < steps && current > 0; i++) current = Math.max(0, current - step * (rules.decayBase + current * rules.decayPerPoint));
13495
+ for (let i = 0; i < steps && current > 0; i++) current = Math.max(0, current - step * (gallery.decayBase + current * gallery.decayPerPoint));
13432
13496
  return current;
13433
13497
  };
13434
- var heatPerRound = (action, caliber, rules) => {
13498
+ var heatPerRound = ({ action, caliber, energy, barrelMass, rules }) => {
13435
13499
  if (action.kind === "launcher") return rules.perRocket;
13436
- return caliber?.caseType ? rules.perShot[caliber.caseType] : 0;
13500
+ const caseType = caliber?.caseType;
13501
+ if (!caseType) return 0;
13502
+ if (rules.gallery) return rules.gallery.perShot[caseType];
13503
+ return rules.barrelShare[caseType] * energy / (barrelMass * rules.specificHeat);
13504
+ };
13505
+ var roundsToWarning = ({ def, caliber, energy, rpm, rules }) => {
13506
+ if (def.action.kind !== "firearm" || rpm <= 0) return Infinity;
13507
+ const barrelMass = barrelMassOf(def, rules);
13508
+ const perRound = heatPerRound({ action: def.action, caliber, energy: energy * (caliber.pellets ?? 1), barrelMass, rules });
13509
+ const interval = 60 / rpm;
13510
+ let heat = 0;
13511
+ for (let round5 = 1; round5 <= MAX_ROUNDS_SEARCHED; round5++) {
13512
+ heat = decayHeat(heat, round5 === 1 ? 0 : interval, barrelMass, rules) + perRound;
13513
+ if (heat >= rules.faultFrom) return round5;
13514
+ }
13515
+ return Infinity;
13516
+ };
13517
+ var roundsToWarningOf = (arsenal, weaponId) => {
13518
+ const def = arsenal.weapons.get(weaponId);
13519
+ if (!def || def.action.kind !== "firearm") return Infinity;
13520
+ const caliber = arsenal.calibers.get(def.action.caliber);
13521
+ if (!caliber) return Infinity;
13522
+ const energy = 0.5 * (caliber.bulletGrams / 1e3) * weaponSpeed(def.action, caliber) ** 2;
13523
+ return roundsToWarning({ def, caliber, energy, rpm: def.action.rpm, rules: arsenal.rules.heat });
13437
13524
  };
13438
13525
  var burstNoise = (base, recentShots, rules) => base * (1 + Math.min(rules.cap, rules.step * recentShots));
13439
13526
  var magazineOut = { stage: "magazine_out", at: 0 };
@@ -13560,29 +13647,6 @@ var GameWeaponsThree = (() => {
13560
13647
  return roll2.ammoQuality.faultChance > 0 && roll2.random() < roll2.ammoQuality.faultChance ? "misfire" : null;
13561
13648
  };
13562
13649
  var isDudWithoutJam = (action, fault) => fault === "misfire" && action.kind === "firearm" && MISFIRE_ONLY.has(action.family);
13563
- var EPS2 = 1e-9;
13564
- var MANUAL_MODES = /* @__PURE__ */ new Set(["pump", "bolt", "lever"]);
13565
- var weaponSpeed = (action, caliber) => action.muzzleSpeed ?? caliber.muzzleSpeed * (action.barrel ?? 1);
13566
- var weaponNoise = (action, caliber) => action.noise ?? caliber.noise ?? 0;
13567
- var timingsOf = (action) => "timings" in action ? action.timings : void 0;
13568
- var drawSeconds = (action, rules) => timingsOf(action)?.draw ?? rules.draw;
13569
- var clearSeconds = (action, rules) => timingsOf(action)?.clear ?? rules.clear;
13570
- var manualCycleSeconds = (action, mode) => MANUAL_MODES.has(mode) ? action.timings?.cycle ?? 0 : 0;
13571
- var planRounds = (action, mode, ammo, firstAt, frameEnd) => {
13572
- const interval = 60 / action.rpm;
13573
- const times = [];
13574
- if (mode === "auto") {
13575
- for (let t = firstAt; times.length < ammo && (times.length === 0 ? t <= frameEnd + EPS2 : t < frameEnd - EPS2); t += interval) times.push(t);
13576
- return times;
13577
- }
13578
- if (mode === "burst") {
13579
- const count = Math.min(action.burst ?? 3, ammo);
13580
- for (let k = 0; k < count; k++) times.push(firstAt + k * interval);
13581
- return times;
13582
- }
13583
- if (mode === "volley") return Array.from({ length: Math.min(action.magazine, ammo) }, () => firstAt);
13584
- return [firstAt];
13585
- };
13586
13650
  var activeParts = (fitted, catalogue) => fitted.flatMap((part) => {
13587
13651
  const def = catalogue.get(part.id);
13588
13652
  const isOn = def?.kind !== "light" && def?.kind !== "laser" ? true : part.on === true;
@@ -13815,6 +13879,10 @@ var GameWeaponsThree = (() => {
13815
13879
  get safety() {
13816
13880
  return this._safety;
13817
13881
  }
13882
+ /** Kg of steel that heat up with the shots. */
13883
+ get barrelMass() {
13884
+ return barrelMassOf(this.def, this.rules.heat);
13885
+ }
13818
13886
  get heat() {
13819
13887
  return this._heat;
13820
13888
  }
@@ -13867,7 +13935,7 @@ var GameWeaponsThree = (() => {
13867
13935
  }
13868
13936
  advance(seconds) {
13869
13937
  if (seconds <= 0) return;
13870
- this._heat = decayHeat(this._heat, seconds, this.rules.heat);
13938
+ this._heat = decayHeat(this._heat, seconds, this.barrelMass, this.rules.heat);
13871
13939
  this.clock += seconds;
13872
13940
  }
13873
13941
  /** Complete what falls at or before `t`: scheduled events and the reload steps. */
@@ -14419,7 +14487,7 @@ var GameWeaponsThree = (() => {
14419
14487
  res.shots.push(shot);
14420
14488
  }
14421
14489
  this._ammo -= 1;
14422
- this._heat = Math.min(this.rules.heat.cap, this._heat + heatPerRound(a, cal, this.rules.heat) * this.load.heatFactor);
14490
+ this._heat = Math.min(this.rules.heat.cap, this._heat + heatPerRound({ action: a, caliber: cal, energy: energy * pellets, barrelMass: this.barrelMass, rules: this.rules.heat }) * this.load.heatFactor);
14423
14491
  this.readyAt = t + 60 / a.rpm;
14424
14492
  this.extra = Math.min(bloomNow + (a.bloomDeg ?? 0), a.spreadDeg * (BLOOM_CAP - 1));
14425
14493
  this.extraClock = t;
@@ -14508,7 +14576,7 @@ var GameWeaponsThree = (() => {
14508
14576
  }
14509
14577
  const t = Math.max(start, this.readyAt);
14510
14578
  this._ammo -= 1;
14511
- this._heat = Math.min(this.rules.heat.cap, this._heat + heatPerRound(a, null, this.rules.heat));
14579
+ this._heat = Math.min(this.rules.heat.cap, this._heat + heatPerRound({ action: a, caliber: null, energy: 0, barrelMass: this.barrelMass, rules: this.rules.heat }));
14512
14580
  this.emit({ type: "shot", shots: 0, rounds: 1, mode: this.mode, at: t });
14513
14581
  return result("ok", { uses: launcherUses(a, this.explosive, origin, dir), recoil: [a.recoil[0], a.recoil[1]], noise: a.noise ?? 0, rounds: 1, roundTimes: [t - start] });
14514
14582
  }
@@ -14856,7 +14924,7 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
14856
14924
  shade: () => shade
14857
14925
  });
14858
14926
 
14859
- // ../game-shapes/dist/chunk-M5N2SHNL.js
14927
+ // ../game-shapes/dist/chunk-FZQTELDQ.js
14860
14928
  function canonicalJson(value) {
14861
14929
  if (value === null) return "null";
14862
14930
  if (typeof value === "number") return Object.is(value, -0) ? "-0" : Number.isFinite(value) ? String(value) : JSON.stringify(String(value));
@@ -15768,17 +15836,19 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
15768
15836
  if (p.prevZ) p.prevZ.nextZ = p.nextZ;
15769
15837
  if (p.nextZ) p.nextZ.prevZ = p.prevZ;
15770
15838
  }
15771
- function Node(i, x, y) {
15772
- this.i = i;
15773
- this.x = x;
15774
- this.y = y;
15775
- this.prev = null;
15776
- this.next = null;
15777
- this.z = 0;
15778
- this.prevZ = null;
15779
- this.nextZ = null;
15780
- this.steiner = false;
15781
- }
15839
+ var Node = class {
15840
+ constructor(i, x, y) {
15841
+ this.i = i;
15842
+ this.x = x;
15843
+ this.y = y;
15844
+ this.prev = null;
15845
+ this.next = null;
15846
+ this.z = 0;
15847
+ this.prevZ = null;
15848
+ this.nextZ = null;
15849
+ this.steiner = false;
15850
+ }
15851
+ };
15782
15852
  function signedArea(data, start, end3, dim) {
15783
15853
  let sum2 = 0;
15784
15854
  for (let i = start, j = end3 - dim; i < end3; i += dim) {
@@ -16622,6 +16692,9 @@ ${problems.map((problem) => ` - ${problem}`).join("\n")}`);
16622
16692
  }
16623
16693
  return releaseObject3D(list2, { keep });
16624
16694
  }
16695
+ function isMesh(o) {
16696
+ return !!o && o.isMesh === true;
16697
+ }
16625
16698
 
16626
16699
  // ../game-props3d/dist/index.js
16627
16700
  function rng(seed) {
@@ -21699,6 +21772,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21699
21772
  floor: 60
21700
21773
  }
21701
21774
  },
21775
+ ricochetDeg: 12,
21702
21776
  hitDebris: "chips",
21703
21777
  breakDebris: "dust",
21704
21778
  visual: { innerColor: 10197652 },
@@ -21730,6 +21804,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21730
21804
  0.04,
21731
21805
  0.12
21732
21806
  ],
21807
+ ricochetDeg: 10,
21733
21808
  hitDebris: "chips",
21734
21809
  breakDebris: "dust",
21735
21810
  visual: { innerColor: 12085567 },
@@ -21787,6 +21862,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21787
21862
  0.06,
21788
21863
  0.3
21789
21864
  ],
21865
+ ricochetDeg: 15,
21790
21866
  hitDebris: "chips",
21791
21867
  breakDebris: "dust",
21792
21868
  visual: { innerColor: 9407364 },
@@ -22215,6 +22291,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22215
22291
  0.03,
22216
22292
  0.15
22217
22293
  ],
22294
+ ricochetDeg: 8,
22218
22295
  hitDebris: "chips",
22219
22296
  breakDebris: "dust",
22220
22297
  thermal: {
@@ -22314,6 +22391,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22314
22391
  0.02,
22315
22392
  0.08
22316
22393
  ],
22394
+ ricochetDeg: 8,
22317
22395
  hitDebris: "chips",
22318
22396
  breakDebris: "dust",
22319
22397
  thermal: {
@@ -22408,6 +22486,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22408
22486
  0.05,
22409
22487
  0.15
22410
22488
  ],
22489
+ ricochetDeg: 15,
22411
22490
  hitDebris: "chips",
22412
22491
  breakDebris: "chips",
22413
22492
  thermal: {
@@ -22433,6 +22512,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22433
22512
  0.04,
22434
22513
  0.12
22435
22514
  ],
22515
+ ricochetDeg: 12,
22436
22516
  hitDebris: "chips",
22437
22517
  breakDebris: "chips",
22438
22518
  thermal: {
@@ -27923,7 +28003,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27923
28003
  }
27924
28004
  var towerLocales = { en: { labels: en_default.labels }, "pt-BR": { labels: pt_BR_default.labels } };
27925
28005
 
27926
- // ../game-floorplan-three/dist/chunk-7XVCZF6H.js
28006
+ // ../game-floorplan-three/dist/chunk-Y3Y7NYOL.js
28007
+ var __defProp3 = Object.defineProperty;
28008
+ var __defNormalProp2 = (obj, key2, value) => key2 in obj ? __defProp3(obj, key2, { enumerable: true, configurable: true, writable: true, value }) : obj[key2] = value;
28009
+ var __publicField2 = (obj, key2, value) => __defNormalProp2(obj, typeof key2 !== "symbol" ? key2 + "" : key2, value);
27927
28010
  var en2 = {
27928
28011
  "prompt.open": "E: open {what}",
27929
28012
  "prompt.close": "E: close {what}",
@@ -28007,6 +28090,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28007
28090
  const WITH_MAP = { roughcast: 1, block: 1 };
28008
28091
  class Accumulator {
28009
28092
  constructor() {
28093
+ __publicField2(this, "cv");
28094
+ __publicField2(this, "ci");
28095
+ __publicField2(this, "p");
28096
+ __publicField2(this, "n");
28097
+ __publicField2(this, "c");
28098
+ __publicField2(this, "u");
28099
+ __publicField2(this, "i");
28100
+ __publicField2(this, "nv");
28101
+ __publicField2(this, "ni");
28102
+ __publicField2(this, "lim");
28103
+ __publicField2(this, "cur");
28104
+ __publicField2(this, "piece0");
28105
+ __publicField2(this, "mat", "");
28106
+ __publicField2(this, "group", "");
28010
28107
  this.cv = 2048;
28011
28108
  this.ci = 3072;
28012
28109
  this.p = new Float32Array(this.cv * 3);
@@ -28069,7 +28166,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28069
28166
  g.position.copy(u.pose0.p);
28070
28167
  g.quaternion.copy(u.pose0.q);
28071
28168
  g.scale.copy(u.pose0.s);
28072
- const e = new THREE.Vector3(...a.axis || [0, 1, 0]);
28169
+ const [ax, ay, az] = a.axis || [0, 1, 0];
28170
+ const e = new THREE.Vector3(ax, ay, az);
28073
28171
  if (a.type === "swing" || a.type === "toggle") g.rotateOnAxis(e, (a.angle || 0) * t);
28074
28172
  else if (a.type === "slide") g.translateOnAxis(e, (a.dist || 0) * t);
28075
28173
  else if (a.type === "scale") {
@@ -28164,7 +28262,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28164
28262
  }
28165
28263
  if (uvr) {
28166
28264
  let gu = G.u[k * 2], gv = G.u[k * 2 + 1];
28167
- for (let r = uvr.rot | 0; r > 0; r--) {
28265
+ for (let r = (uvr.rot ?? 0) | 0; r > 0; r--) {
28168
28266
  const t = gu;
28169
28267
  gu = gv;
28170
28268
  gv = 1 - t;
@@ -28262,14 +28360,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28262
28360
  A.nv += n;
28263
28361
  }
28264
28362
  let bxImpl = bxBase;
28265
- function bx(...a) {
28266
- return bxImpl(...a);
28267
- }
28268
- K.getBx = () => bxImpl;
28269
- K.setBx = (f) => {
28363
+ const bx = (...a) => bxImpl(...a);
28364
+ const getBx = () => bxImpl;
28365
+ const setBx = (f) => {
28270
28366
  bxImpl = f;
28271
28367
  };
28272
- Object.assign(K, { GEO, UV_SCALE, WITH_MAP, Accumulator, cursor, PARTS, MIRRORS, part, applyPart, _Y, _qa, _qb, pieceRecord, structurePiece, accFor, _q, _e, _col, rgbOf, put, boxC, bx, cylBase, polyFace });
28368
+ const defined = { GEO, UV_SCALE, WITH_MAP, Accumulator, cursor, PARTS, MIRRORS, part, applyPart, _Y, _qa, _qb, pieceRecord, structurePiece, accFor, _q, _e, _col, rgbOf, put, boxC, bx, getBx, setBx, cylBase, polyFace };
28369
+ Object.assign(K, defined);
28273
28370
  }
28274
28371
  function installKernelNoise(K, _shared) {
28275
28372
  const _h2 = (x, z) => {
@@ -28285,15 +28382,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28285
28382
  const n = 0.5 * vnoise(x / 5.5, z / 5.5) + 0.32 * vnoise(x / 1.9 + 31, z / 1.9) + 0.18 * vnoise(x / 0.8 + 7, z / 0.8), m = vnoise(x / 9 + 100, z / 9 + 50) - 0.5, f = 0.76 + 0.5 * n;
28286
28383
  return type === "dirt" ? [f * (1 + 0.14 * m), f * (1 + 0.03 * m), f * (1 - 0.18 * m)] : [f * (1 + 0.1 * m), f * (1 + 0.05 * m), f * (1 - 0.1 * m)];
28287
28384
  }
28288
- Object.assign(K, { _h2, vnoise, macroGround });
28385
+ const defined = { _h2, vnoise, macroGround };
28386
+ Object.assign(K, defined);
28289
28387
  }
28290
28388
  function installMaterialsTextures(K, _shared) {
28291
28389
  const { DOC, THREE, cfg } = K;
28292
28390
  function texture(n, f, rep = true, rx = 1, ry = 1) {
28391
+ if (!DOC) throw new Error("game-floorplan-three: the procedural textures need a document (options.document)");
28293
28392
  const c = DOC.createElement("canvas");
28294
28393
  c.width = n;
28295
28394
  c.height = n;
28296
28395
  const g = c.getContext("2d");
28396
+ if (!g) throw new Error("game-floorplan-three: no 2d canvas context");
28297
28397
  f(g, n);
28298
28398
  const t = new THREE.CanvasTexture(c);
28299
28399
  t.colorSpace = THREE.SRGBColorSpace;
@@ -28412,7 +28512,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28412
28512
  const TEX = {};
28413
28513
  for (const k of Object.keys(TEXGEN)) TEX[k] = cfg.textures && cfg.textures[k] || TEXGEN[k]();
28414
28514
  const ATLAS = {};
28415
- Object.assign(K, { texture, rngTexture, TEXGEN, TEX, ATLAS });
28515
+ const defined = { texture, rngTexture, TEXGEN, TEX, ATLAS };
28516
+ Object.assign(K, defined);
28517
+ }
28518
+ function context2d(c) {
28519
+ const g = c.getContext("2d");
28520
+ if (!g) throw new Error("game-floorplan-three: no 2d canvas context");
28521
+ return g;
28416
28522
  }
28417
28523
  function installMaterialsMaterials(K, _shared) {
28418
28524
  const { THREE, cfg, ATLAS, TEX, rngTexture } = K;
@@ -28425,7 +28531,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28425
28531
  return t;
28426
28532
  };
28427
28533
  if (!(cfg.atlas && cfg.atlas.floorKind)) {
28428
- const pc = props.atlas("floor").canvas, g = pc.getContext("2d");
28534
+ const pc = props.atlas("floor").canvas, g = context2d(pc);
28429
28535
  for (const c of [0, 1]) {
28430
28536
  g.save();
28431
28537
  g.globalCompositeOperation = "screen";
@@ -28440,7 +28546,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28440
28546
  g.restore();
28441
28547
  }
28442
28548
  if (!(cfg.atlas && cfg.atlas.floorKind)) {
28443
- const pc = props.atlas("floor").canvas, g = pc.getContext("2d");
28549
+ const pc = props.atlas("floor").canvas, g = context2d(pc);
28444
28550
  g.save();
28445
28551
  g.fillStyle = "rgba(128,92,62,0.52)";
28446
28552
  g.fillRect(256, 256, 256, 256);
@@ -28537,7 +28643,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28537
28643
  }
28538
28644
  const ORDER2 = { glass: 3, water: 2, screen: 3, building: 4 };
28539
28645
  const NO_SHADOW = /* @__PURE__ */ new Set(["dirt", "glass", "water", "screen", "building", "picture", "floor", "emissive"]);
28540
- Object.assign(K, { createMaterials: createMaterials2, antiTile, dirtMaterial, CLOTHES_UNIFORMS, clothesMaterial, ORDER: ORDER2, NO_SHADOW });
28646
+ const defined = { createMaterials: createMaterials2, antiTile, dirtMaterial, CLOTHES_UNIFORMS, clothesMaterial, ORDER: ORDER2, NO_SHADOW };
28647
+ Object.assign(K, defined);
28541
28648
  }
28542
28649
  function installKernelCloseScene(K, shared2) {
28543
28650
  const { THREE, NO_SHADOW, ORDER: ORDER2, PARTS, applyPart, cursor } = K;
@@ -28546,15 +28653,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28546
28653
  const assembleVegetation = (...a) => K.assembleVegetation(...a);
28547
28654
  function markMesh(m, A) {
28548
28655
  const L = A.lim, fx = [];
28656
+ const pieces = shared2.ctx.pieces;
28549
28657
  for (let k = 0; k < L.length; k++) {
28550
- if (!L[k].pc) continue;
28551
- const v1 = k + 1 < L.length ? L[k + 1].v : A.nv, i1 = k + 1 < L.length ? L[k + 1].i : A.ni;
28552
- if (v1 > L[k].v) fx.push({ id: L[k].pc.id, v0: L[k].v, v1, i0: L[k].i, i1 });
28658
+ const lim = L[k], pc = lim.pc;
28659
+ if (!pc) continue;
28660
+ const next = L[k + 1];
28661
+ const v1 = next ? next.v : A.nv, i1 = next ? next.i : A.ni;
28662
+ if (v1 > lim.v) fx.push({ id: pc.id, v0: lim.v, v1, i0: lim.i, i1 });
28553
28663
  }
28554
28664
  if (!fx.length) return;
28555
28665
  const u = m.userData, ids = [...new Set(fx.map((f) => f.id))], weight = {};
28556
28666
  for (const f of fx) {
28557
- const mt = shared2.ctx.pieces.get(f.id).mat;
28667
+ const mt = pieces.get(f.id).mat;
28558
28668
  weight[mt] = (weight[mt] || 0) + f.v1 - f.v0;
28559
28669
  }
28560
28670
  u.ranges = fx;
@@ -28562,7 +28672,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28562
28672
  u.destructionMaterial = Object.keys(weight).sort((a, b) => weight[b] - weight[a])[0];
28563
28673
  if (ids.length === 1) {
28564
28674
  u.destructionPart = ids[0];
28565
- const pc = shared2.ctx.pieces.get(ids[0]);
28675
+ const pc = pieces.get(ids[0]);
28566
28676
  if (pc.role) u.structuralRole = pc.role;
28567
28677
  }
28568
28678
  }
@@ -28613,7 +28723,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28613
28723
  assembleVegetation(groups);
28614
28724
  return groups;
28615
28725
  }
28616
- Object.assign(K, { markMesh, closeScene });
28726
+ const defined = { markMesh, closeScene };
28727
+ Object.assign(K, defined);
28617
28728
  }
28618
28729
  function installHouseHelpers(K, shared2) {
28619
28730
  shared2.ctx = {};
@@ -28649,8 +28760,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28649
28760
  for (const h of holes) L = L.flatMap((r) => subRect(r, h));
28650
28761
  return L;
28651
28762
  }
28652
- const wallColor = (c) => c && c.color && colorOf(c.color.wall) != null ? colorOf(c.color.wall) : 14999768;
28653
- const floorColor = (c) => c && c.color && colorOf(c.color.floor) != null ? colorOf(c.color.floor) : 11577496;
28763
+ const wallColor = (c) => {
28764
+ const k = c && c.color ? colorOf(c.color.wall) : null;
28765
+ return k != null ? k : 14999768;
28766
+ };
28767
+ const floorColor = (c) => {
28768
+ const k = c && c.color ? colorOf(c.color.floor) : null;
28769
+ return k != null ? k : 11577496;
28770
+ };
28654
28771
  function stairFootprint(m) {
28655
28772
  const c = Math.cos(m.ry), s = Math.sin(m.ry), pts = [[-m.w / 2, -m.d / 2], [m.w / 2, -m.d / 2], [m.w / 2, m.d / 2], [-m.w / 2, m.d / 2]].map(([a, b]) => [m.x + a * c + b * s, m.z - a * s + b * c]);
28656
28773
  return [Math.min(...pts.map((p) => p[0])), Math.min(...pts.map((p) => p[1])), Math.max(...pts.map((p) => p[0])), Math.max(...pts.map((p) => p[1]))];
@@ -28661,11 +28778,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28661
28778
  const pitch = A[f + 1].y0 - A[f].y0;
28662
28779
  return h > pitch && h - pitch <= 0.45 ? pitch : h;
28663
28780
  }
28664
- Object.assign(K, { OPEN_ROOM_TYPES: OPEN_ROOM_TYPES22, NO_CEILING, OPEN_AREA, EPS: EPS6, Y0, colorOf, rectsOf: rectsOf2, roomAt, subRect, subRects, wallColor, floorColor, stairFootprint, effectiveHeight });
28781
+ const defined = { OPEN_ROOM_TYPES: OPEN_ROOM_TYPES22, NO_CEILING, OPEN_AREA, EPS: EPS6, Y0, colorOf, rectsOf: rectsOf2, roomAt, subRect, subRects, wallColor, floorColor, stairFootprint, effectiveHeight };
28782
+ Object.assign(K, defined);
28665
28783
  }
28666
28784
  function installHouseWalls(K, shared2) {
28667
28785
  const { EPS: EPS6, Y0, boxC, bx, cursor, effectiveHeight, pieceRecord, structurePiece, wallColor } = K;
28668
- const sh = (color2, factor) => K.sh(color2, factor);
28786
+ const sh = (...a) => K.sh(...a);
28669
28787
  function wallBox(alongU, L, a, b, ya, yb, th, cL, cH, mL, mH) {
28670
28788
  if (yb - ya < 1e-4 || b - a < 1e-4) return;
28671
28789
  if (alongU) {
@@ -28711,7 +28829,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28711
28829
  const corners = /* @__PURE__ */ new Map();
28712
28830
  const looks = /* @__PURE__ */ new Map();
28713
28831
  for (const w of R.walls) {
28714
- const f = w.floor;
28832
+ const f = w.floor, colliders = shared2.ctx.colliders;
28715
28833
  cursor.group = "f" + f;
28716
28834
  cursor.pc = pieceOf(w);
28717
28835
  const y0 = Y0(f), pitch = f + 1 < nA ? Y0(f + 1) - y0 : Infinity, th = w.thickness || 0.15, alongU = w.axis === "u";
@@ -28723,7 +28841,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28723
28841
  const face = sideL.exterior ? sideL : sideH;
28724
28842
  looks.set(w.id, { mat: face.mat, color: face.color, top: y0 + hh });
28725
28843
  }
28726
- shared2.ctx.colliders.push({ type: "wall", piece: w.id, f, x0: alongU ? s0 : L - th / 2, z0: alongU ? L - th / 2 : s0, x1: alongU ? s1 : L + th / 2, z1: alongU ? L + th / 2 : s1 });
28844
+ colliders.push({ type: "wall", piece: w.id, f, x0: alongU ? s0 : L - th / 2, z0: alongU ? L - th / 2 : s0, x1: alongU ? s1 : L + th / 2, z1: alongU ? L + th / 2 : s1 });
28727
28845
  if (w.type === "railing") {
28728
28846
  const c0 = shared2.ctx.colors.metal != null ? shared2.ctx.colors.metal : 9080466;
28729
28847
  const sx = alongU ? 1 : 0, sz = alongU ? 0 : 1, len = s1 - s0, n = Math.max(1, Math.round(len / 1.4));
@@ -28789,7 +28907,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28789
28907
  }
28790
28908
  cursor.pc = null;
28791
28909
  }
28792
- Object.assign(K, { wallBox, sideOf, pieceOf, nearestWall, walls, wallPillars });
28910
+ const defined = { wallBox, sideOf, pieceOf, nearestWall, walls, wallPillars };
28911
+ Object.assign(K, defined);
28793
28912
  }
28794
28913
  function installHouseDoors(K, shared2) {
28795
28914
  const seedKey = (id) => K.seedKey(id);
@@ -28806,7 +28925,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28806
28925
  }
28807
28926
  shared2.doorState = /* @__PURE__ */ new Map();
28808
28927
  function doors() {
28809
- shared2.ctx.leaves = [];
28928
+ const leaves = shared2.ctx.leaves = [], doorState = shared2.doorState, colliders = shared2.ctx.colliders;
28810
28929
  const R = shared2.ctx.r, cut = shared2.ctx.cut, C = shared2.ctx.colors, wood = C.wood != null ? C.wood : 8016948, frame2 = sh(wood, 0.55);
28811
28930
  for (const p of R.doors) {
28812
28931
  const f = p.floor;
@@ -28837,21 +28956,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28837
28956
  }
28838
28957
  const leaf = (u0, u1, y_0, y_1, tt, color2, mat = "wood") => alongU ? bx(mat, u0, y0 + y_0, L - tt / 2, u1, y0 + y_1, L + tt / 2, color2) : bx(mat, L - tt / 2, y0 + y_0, u0, L + tt / 2, y0 + y_1, u1, color2);
28839
28958
  const extC = wood;
28840
- const open0 = p.blocked ? false : shared2.doorState.has(p.id) ? shared2.doorState.get(p.id) : !!p.open;
28841
- shared2.doorState.set(p.id, open0);
28959
+ const open0 = p.blocked ? false : doorState.has(p.id) ? doorState.get(p.id) === true : !!p.open;
28960
+ doorState.set(p.id, open0);
28842
28961
  const dc = alongU ? [p.at, L] : [L, p.at];
28843
- const fo = { id: p.id, floor: f, type: p.model === "steel" ? "steel" : "swing", open: open0, t: open0 ? 1 : 0, blockedFlag: !!p.blocked, locked: R.state === "fortified" && !!p.exterior, handleNames: [], hT: 0, cx: dc[0], cz: dc[1], visH, groups: [], col: null };
28962
+ const fo = { id: p.id, floor: f, type: p.model === "steel" ? "steel" : "swing", open: open0, t: open0 ? 1 : 0, blockedFlag: !!p.blocked, locked: R.state === "fortified" && !!p.exterior, handleNames: [], hT: 0, cx: dc[0], cz: dc[1], visH, groups: [], gs: [], col: null };
28844
28963
  const colR = { type: "door", f, x0: alongU ? a : L - th / 2, z0: alongU ? L - th / 2 : a, x1: alongU ? b : L + th / 2, z1: alongU ? L + th / 2 : b, off: open0 };
28845
- shared2.ctx.colliders.push(colR);
28964
+ colliders.push(colR);
28846
28965
  fo.col = colR;
28847
28966
  const leafBox = (hu, d0, d1, y_0, y_1, tt, color2, mat) => alongU ? bx(mat, d0, y_0, -tt / 2, d1, y_1, tt / 2, color2) : bx(mat, -tt / 2, y_0, d0, tt / 2, y_1, d1, color2);
28848
- const newGroup = (k, hu, topY) => {
28967
+ const newGroup2 = (k, hu, topY) => {
28849
28968
  cursor.group = "dyn:" + p.id + ":" + k;
28850
28969
  fo.groups.push({ name: cursor.group, pos: alongU ? [hu, topY != null ? y0 + topY : y0, L] : [L, topY != null ? y0 + topY : y0, hu] });
28851
28970
  };
28852
28971
  if (p.model === "steel") {
28853
- const light = [14276044, 13223615, 14999766], pal = ((R.seed | 0) + p.id.length * 7) % 4, color2 = pal === 3 ? wood : light[pal], mid = (a + b) / 2;
28854
- newGroup(0, mid, visH);
28972
+ const light = [14276044, 13223615, 14999766], pal = ((Number(R.seed) | 0) + p.id.length * 7) % 4, color2 = pal === 3 ? wood : light[pal], mid = (a + b) / 2;
28973
+ newGroup2(0, mid, visH);
28855
28974
  const la = a + jw - mid, lb = b - jw - mid, nSec = Math.max(4, Math.round(visH / 0.5)), hs = visH / nSec, grv = sh(color2, 0.55);
28856
28975
  leafBox(0, la, lb, -visH, 0, 0.05, color2, "metal");
28857
28976
  for (let k = 1; k < nSec; k++) leafBox(0, la, lb, -k * hs - 0.012, -k * hs + 0.012, 0.07, grv, "metal");
@@ -28866,7 +28985,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28866
28985
  for (let k = 0; k < nf; k++) {
28867
28986
  const u0 = nf === 2 ? k ? (aa + bb) / 2 : aa : aa, u1 = nf === 2 ? k ? bb : (aa + bb) / 2 : bb, color2 = p.exterior ? extC : wood;
28868
28987
  const hingeAt = nf === 2 ? k ? u1 : u0 : p.hinge === "end" ? u1 : u0, dir = hingeAt === u0 ? 1 : -1, len = u1 - u0;
28869
- newGroup(k, hingeAt);
28988
+ newGroup2(k, hingeAt);
28870
28989
  const d0 = dir > 0 ? 5e-3 : -len + 5e-3, d1 = dir > 0 ? len - 5e-3 : -5e-3;
28871
28990
  leafBox(hingeAt, d0, d1, 0, visH, 0.04, color2, PMAT);
28872
28991
  {
@@ -28902,7 +29021,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28902
29021
  fo.rot = Math.atan2(n[0] * A[1] - n[1] * A[0], A[0] * n[0] + A[1] * n[1]);
28903
29022
  }
28904
29023
  }
28905
- shared2.ctx.leaves.push(fo);
29024
+ leaves.push(fo);
28906
29025
  cursor.group = "f" + f;
28907
29026
  if (p.blocked) {
28908
29027
  part("window_boards", [0, 0, 0], () => {
@@ -28930,11 +29049,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28930
29049
  }
28931
29050
  }
28932
29051
  }, { id: "boards:" + p.id }, "f" + f);
28933
- shared2.ctx.colliders.push({ type: "board", f, x0: alongU ? a : L - th / 2, z0: alongU ? L - th / 2 : a, x1: alongU ? b : L + th / 2, z1: alongU ? L + th / 2 : b });
29052
+ colliders.push({ type: "board", f, x0: alongU ? a : L - th / 2, z0: alongU ? L - th / 2 : a, x1: alongU ? b : L + th / 2, z1: alongU ? L + th / 2 : b });
28934
29053
  }
28935
29054
  }
28936
29055
  }
28937
- Object.assign(K, { doorLineSides, doors });
29056
+ const defined = { doorLineSides, doors };
29057
+ Object.assign(K, defined);
28938
29058
  }
28939
29059
  function installHouseWindows(K, shared2) {
28940
29060
  const { EPS: EPS6, Y0, boxC, bx, cursor, pieceRecord, roomAt } = K;
@@ -28992,7 +29112,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28992
29112
  }
28993
29113
  }
28994
29114
  }
28995
- Object.assign(K, { FRAME_COLORS, SILL_COLORS, windows });
29115
+ const defined = { FRAME_COLORS, SILL_COLORS, windows };
29116
+ Object.assign(K, defined);
28996
29117
  }
28997
29118
  function installHouseFloors(K, shared2) {
28998
29119
  const { rectsOf: rectsOf2, EPS: EPS6, OPEN_AREA, Y0, bx, cursor, floorColor, stairFootprint, structurePiece, subRects } = K;
@@ -29000,7 +29121,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29000
29121
  if (shared2.ctx._flights && shared2.ctx._flights.r === shared2.ctx.r) return shared2.ctx._flights.l;
29001
29122
  const R = shared2.ctx.r, mp = /* @__PURE__ */ new Map();
29002
29123
  for (const m of R.items) {
29003
- if (m.type !== "stairs" || !m.link) continue;
29124
+ if (m.type !== "stairs" || !m.link || typeof m.link !== "object") continue;
29004
29125
  const k = [m.link.from, m.link.to, m.x.toFixed(2), m.z.toFixed(2), (m.ry || 0).toFixed(2)].join("|");
29005
29126
  if (!mp.has(k)) mp.set(k, { m, from: m.link.from, to: m.link.to, rect: stairFootprint(m) });
29006
29127
  }
@@ -29019,7 +29140,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29019
29140
  }
29020
29141
  const panelRects = (p) => p.footprint && p.footprint.length ? p.footprint : [p.aabb];
29021
29142
  function tilesOf(parent, rc) {
29022
- const ps = parent && shared2.ctx.panelsOf && shared2.ctx.panelsOf.get(parent);
29143
+ const ps = parent ? shared2.ctx.panelsOf && shared2.ctx.panelsOf.get(parent) : void 0;
29023
29144
  if (!ps) return [[parent ? structurePiece(parent) : null, rc]];
29024
29145
  const out = [], taken = [];
29025
29146
  for (const p of ps) for (const q of panelRects(p)) {
@@ -29081,13 +29202,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29081
29202
  const { rectsOf: rectsOf2, Y0, boxC, bx, cursor, flights, stairFootprint, structurePiece } = K;
29082
29203
  const sh = (...a) => K.sh(...a);
29083
29204
  function buildStairs() {
29084
- const R = shared2.ctx.r;
29085
- shared2.ctx.stairs = [];
29205
+ const R = shared2.ctx.r, stairs = shared2.ctx.stairs = [];
29086
29206
  for (const vo of flights()) {
29087
29207
  const m = vo.m, f = vo.from, Dr = m.d - (vo.LP || 0);
29088
29208
  cursor.group = "f" + f;
29089
29209
  cursor.pc = structurePiece("stairs_" + vo.from + "_" + vo.to);
29090
- const y0 = Y0(f), H = Y0(m.link.to) - y0, n = Math.max(8, Math.round(H / 0.18)), c = Math.cos(m.ry), s = Math.sin(m.ry);
29210
+ const y0 = Y0(f), H = Y0(vo.to) - y0, n = Math.max(8, Math.round(H / 0.18)), c = Math.cos(m.ry), s = Math.sin(m.ry);
29091
29211
  const wood = shared2.ctx.colors.wood != null ? shared2.ctx.colors.wood : 9071176, under = sh(wood, 0.7);
29092
29212
  const P = (lx, lz) => [m.x + lx * c + lz * s, m.z - lx * s + lz * c];
29093
29213
  const boxL = (mat, lx, y, lz, w, h, d, color2, rx = 0) => {
@@ -29110,7 +29230,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29110
29230
  }
29111
29231
  }
29112
29232
  cursor.pc = null;
29113
- shared2.ctx.stairs.push({ m, f, to: vo.to, y0, H, rect: stairFootprint(m), landingPoint: (vo.LP || 0) / m.d });
29233
+ stairs.push({ m, f, to: vo.to, y0, H, rect: stairFootprint(m), landingPoint: (vo.LP || 0) / m.d });
29114
29234
  }
29115
29235
  }
29116
29236
  function elevator() {
@@ -29127,7 +29247,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29127
29247
  }
29128
29248
  }
29129
29249
  }
29130
- Object.assign(K, { buildStairs, elevator });
29250
+ const defined = { buildStairs, elevator };
29251
+ Object.assign(K, defined);
29131
29252
  }
29132
29253
  function installLightsFixtures(K, shared2) {
29133
29254
  const seedKey = (id) => K.seedKey(id);
@@ -29165,14 +29286,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29165
29286
  c: (mat, x, y, z, r, h, color2, seg2) => api.cylinder(M, mat, x, y0 + y, z, r, h, color2, 0, 0, seg2),
29166
29287
  e: (mat, x, y, z, r, h, color2) => api.cylinder(M, mat, x, y0 + y - h / 2, z, r, h, color2, 0, 0, "sphere"),
29167
29288
  t(mat, p, q, r, color2, seg2) {
29289
+ const tc = color2 ?? NaN;
29168
29290
  const dx = q[0] - p[0], dy = q[1] - p[1], dz = q[2] - p[2], L = Math.hypot(dx, dy, dz);
29169
29291
  if (L < 1e-5) return;
29170
29292
  const nx = dx / L, ny = dy / L, nz = dz / L;
29171
29293
  if (Math.abs(nx) < 1e-4 && Math.abs(nz) < 1e-4) {
29172
- api.cylinder(M, mat, p[0], y0 + Math.min(p[1], q[1]), p[2], r, L, color2, 0, 0, seg2);
29294
+ api.cylinder(M, mat, p[0], y0 + Math.min(p[1], q[1]), p[2], r, L, tc, 0, 0, seg2);
29173
29295
  return;
29174
29296
  }
29175
- api.cylinder(M, mat, (p[0] + q[0]) / 2, y0 + (p[1] + q[1]) / 2, (p[2] + q[2]) / 2, r, L, color2, Math.atan2(nz, ny), -Math.asin(nx), seg2);
29297
+ api.cylinder(M, mat, (p[0] + q[0]) / 2, y0 + (p[1] + q[1]) / 2, (p[2] + q[2]) / 2, r, L, tc, Math.atan2(nz, ny), -Math.asin(nx), seg2);
29176
29298
  },
29177
29299
  polyFace: (mat, pts, color2, hint) => polyFace(mat, pts.map((p) => W(p[0], p[1], p[2])), color2, hint && [hint[0] * c + hint[2] * s, hint[1], -hint[0] * s + hint[2] * c]),
29178
29300
  part(type, lx, ly, lz, fn, meta) {
@@ -29351,7 +29473,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29351
29473
  K2.part("light_switch", x, 0, 0.011, () => K2.b("plain", x, -0.018, 0.0125, two ? 0.03 : 0.036, 0.034, 8e-3, 16513782, 0, -0.12), { id: "sw_" + M.seed + "_" + i, room: M.room, target: M.target || M.room, opens: { type: "toggle", axis: [1, 0, 0], angle: 0.24 }, on: !!M.on, t0: M.on ? 1 : 0 });
29352
29474
  }
29353
29475
  }
29354
- Object.assign(K, { hashString, rngString, SEED, STYLE, kit2, arcPoints, TEMP_WARM, TEMP_NEUTRAL, TEMP_COOL, colorTemperature, lightStyle, ceilingLamp, tableLamp, floorLamp, sconce, outdoorLamp, lightSwitch });
29476
+ const defined = { hashString, rngString, SEED, STYLE, kit2, arcPoints, TEMP_WARM, TEMP_NEUTRAL, TEMP_COOL, colorTemperature, lightStyle, ceilingLamp, tableLamp, floorLamp, sconce, outdoorLamp, lightSwitch };
29477
+ Object.assign(K, defined);
29355
29478
  }
29356
29479
  function installLightsDecor(K, shared2) {
29357
29480
  const { EPS: EPS6, OPEN_AREA, SEED, Y0, cursor, rngString, roomAt, stairFootprint } = K;
@@ -29416,7 +29539,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29416
29539
  void sd;
29417
29540
  }
29418
29541
  }
29419
- Object.assign(K, { decorLights });
29542
+ const defined = { decorLights };
29543
+ Object.assign(K, defined);
29420
29544
  }
29421
29545
  function installLotTerrain(K, shared2) {
29422
29546
  const { rectsOf: rectsOf2, MIRRORS, PARTS, bx, cursor } = K;
@@ -29467,7 +29591,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29467
29591
  if (x < b) out.push([x, b]);
29468
29592
  return out.filter((q) => q[1] - q[0] > 0.3);
29469
29593
  }
29470
- Object.assign(K, { terrain, freeSpans });
29594
+ const defined = { terrain, freeSpans };
29595
+ Object.assign(K, defined);
29471
29596
  }
29472
29597
  function installLotPerimeter(K, shared2) {
29473
29598
  const { EPS: EPS6, boxC, bx, colorOf, cursor, freeSpans, pieceRecord } = K;
@@ -29485,7 +29610,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29485
29610
  for (const s of lt2.perimeter) {
29486
29611
  const alongU = Math.abs(s.v1 - s.v0) < EPS6, L = alongU ? s.v0 : s.u0, a = Math.min(alongU ? s.u0 : s.v0, alongU ? s.u1 : s.v1), b = Math.max(alongU ? s.u0 : s.v0, alongU ? s.u1 : s.v1);
29487
29612
  cursor.pc = pieceRecord("lot_wall:" + s.id, s.type === "wall" ? "brick" : s.type === "fence" ? "wood_soft" : "steel", null, { tags: ["wall"] });
29488
- const th = s.thickness || 0.15, h = s.height, color2 = colorOf(s.color) != null ? colorOf(s.color) : C.wall || 12104874, len = b - a;
29613
+ const th = s.thickness || 0.15, h = s.height, color2 = colorOf(s.color) ?? (C.wall || 12104874), len = b - a;
29489
29614
  const B = (mat, u0, y0, u1, y1, t, c, off = 0) => alongU ? bx(mat, u0, y0, L + off - t / 2, u1, y1, L + off + t / 2, c) : bx(mat, L + off - t / 2, y0, u0, L + off + t / 2, y1, u1, c);
29490
29615
  const col = { type: "lot_wall", f: -1, x0: alongU ? a : L - th / 2, z0: alongU ? L - th / 2 : a, x1: alongU ? b : L + th / 2, z1: alongU ? L + th / 2 : b };
29491
29616
  shared2.ctx.colliders.push(col);
@@ -29559,7 +29684,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29559
29684
  }
29560
29685
  }
29561
29686
  }
29562
- Object.assign(K, { perimeter, paths });
29687
+ const defined = { perimeter, paths };
29688
+ Object.assign(K, defined);
29563
29689
  }
29564
29690
  function installLotGates(K, shared2) {
29565
29691
  const { bx, colorOf, cursor, cylBase } = K;
@@ -29573,7 +29699,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29573
29699
  cursor.group = "lot";
29574
29700
  const structure = R.style, auto = structure !== "budget", wall = colorOf("wall") || 12104874, cu = (lt2.rect[0] + lt2.rect[2]) / 2, cz = (lt2.rect[1] + lt2.rect[3]) / 2;
29575
29701
  for (const g of lt2.gates) {
29576
- const gc = colorOf(g.color) != null ? colorOf(g.color) : C.gate != null ? C.gate : 2763310, a = g.u - g.width / 2, b = g.u + g.width / 2, v = g.v, h = g.height, t = 0.05, ped = g.model === "pedestrian", tilt = g.model === "tilting";
29702
+ const gc = colorOf(g.color) ?? (C.gate != null ? C.gate : 2763310), a = g.u - g.width / 2, b = g.u + g.width / 2, v = g.v, h = g.height, t = 0.05, ped = g.model === "pedestrian", tilt = g.model === "tilting";
29577
29703
  const sd = cz - v >= 0 ? 1 : -1;
29578
29704
  const pil = (x0, x1, high) => {
29579
29705
  bx("plaster", x0, 0, v - 0.13, x1, high, v + 0.13, wall);
@@ -29645,7 +29771,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29645
29771
  if (!g.open || ped) shared2.ctx.colliders.push({ type: "gate", f: -1, x0: a, z0: v - 0.1, x1: b, z1: v + 0.1 });
29646
29772
  }
29647
29773
  }
29648
- Object.assign(K, { slideDirection, gates });
29774
+ const defined = { slideDirection, gates };
29775
+ Object.assign(K, defined);
29649
29776
  }
29650
29777
  function installRoofRoofs(K, shared2) {
29651
29778
  const { rectsOf: rectsOf2, EPS: EPS6, OPEN_AREA, Y0, bx, cursor } = K;
@@ -29657,13 +29784,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29657
29784
  function roofs() {
29658
29785
  const R = shared2.ctx.r, F = R.facade, C = shared2.ctx.colors, nA = R.floors.length, type = F.roof;
29659
29786
  cursor.group = "roof";
29660
- shared2.ctx.roofRects = [];
29661
- shared2.ctx.gutter = gutterConfig();
29662
- shared2.ctx.gutter.ncond = 0;
29663
- shared2.ctx.gutter.nbuz = 0;
29664
- shared2.ctx.gutter.bz = /* @__PURE__ */ new Set();
29787
+ const roofRects = shared2.ctx.roofRects = [];
29788
+ const G = shared2.ctx.gutter = gutterConfig();
29789
+ G.ncond = 0;
29790
+ G.nbuz = 0;
29791
+ G.bz = /* @__PURE__ */ new Set();
29665
29792
  shared2.ctx.gutterInfo = { gutters: [], downpipes: [], drains: [] };
29666
- const roofColor = C.roof != null ? C.roof : 11031610, gable = (R.seed | 0) % 2 === 0;
29793
+ const roofColor = C.roof != null ? C.roof : 11031610, gable = (Number(R.seed) | 0) % 2 === 0;
29667
29794
  for (let f = 0; f < nA; f++) {
29668
29795
  const rs = R.rooms.filter((c) => c.floor === f && c.type !== "void" && !c.outbuilding && !OPEN_AREA(c)).flatMap(rectsOf2), up = R.rooms.filter((c) => c.floor === f + 1 && c.type !== "void").flatMap(rectsOf2);
29669
29796
  if (!rs.length) continue;
@@ -29685,7 +29812,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29685
29812
  return Y0(f) + Math.max(...cs.map((c) => c.ceiling)) + 0.2;
29686
29813
  };
29687
29814
  if (type === "slab") {
29688
- for (let j = 0; j < nz; j++) for (let i = 0; i < nx; i++) if (O(j, i)) shared2.ctx.roofRects.push({ f, r: [xs[i], zs[j], xs[i + 1], zs[j + 1]], slab: true, yb: pe(xs[i], zs[j], xs[i + 1], zs[j + 1]) + 0.03 });
29815
+ for (let j = 0; j < nz; j++) for (let i = 0; i < nx; i++) if (O(j, i)) roofRects.push({ f, r: [xs[i], zs[j], xs[i + 1], zs[j + 1]], slab: true, yb: pe(xs[i], zs[j], xs[i + 1], zs[j + 1]) + 0.03 });
29689
29816
  slabs(f, xs, zs, O, U, nx, nz, full, pe, C);
29690
29817
  cursor.pc = null;
29691
29818
  continue;
@@ -29708,16 +29835,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29708
29835
  if (U(q.j0 - 1, i)) touchesU[1] = 1;
29709
29836
  if (U(q.j1 + 1, i)) touchesU[3] = 1;
29710
29837
  }
29711
- shared2.ctx.roofRects.push({ f, r: [x0, z0, x1, z1], touchesU });
29838
+ roofRects.push({ f, r: [x0, z0, x1, z1], touchesU });
29712
29839
  const ybq = pe(x0, z0, x1, z1);
29713
29840
  roofRect(type, x0, z0, x1, z1, ybq, roofColor, gable && single, F, touchesU);
29714
29841
  cursor.pc = null;
29715
- if (shared2.ctx.gutter.on) gutter(type, f, x0, z0, x1, z1, ybq, touchesU);
29842
+ if (G.on) gutter(type, f, x0, z0, x1, z1, ybq, touchesU);
29716
29843
  }
29717
29844
  }
29718
29845
  for (const e of shared2.ctx.outbuildingList || []) {
29719
29846
  const [x0, z0, x1, z1] = e.aabb, yb = Y0(0) + (e.ceiling || 2.6) + 0.2;
29720
- shared2.ctx.roofRects.push({ f: 0, r: [x0, z0, x1, z1], outbuilding: e.id });
29847
+ roofRects.push({ f: 0, r: [x0, z0, x1, z1], outbuilding: e.id });
29721
29848
  if (type === "slab") {
29722
29849
  const c = C.facade != null ? C.facade : 14209216;
29723
29850
  bx("plaster", x0 - 0.08, yb, z0 - 0.08, x1 + 0.08, yb + 0.03, z1 + 0.08, sh(C.ceiling != null ? C.ceiling : 12104876, 0.85));
@@ -29728,11 +29855,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29728
29855
  roofRect(type, x0, z0, x1, z1, yb, roofColor, true, F, [0, 0, 0, 0]);
29729
29856
  cursor.pc = null;
29730
29857
  shared2.ctx.noPiece = false;
29731
- if (shared2.ctx.gutter.on) gutter(type, 0, x0, z0, x1, z1, yb, [0, 0, 0, 0]);
29858
+ if (G.on) gutter(type, 0, x0, z0, x1, z1, yb, [0, 0, 0, 0]);
29732
29859
  }
29733
29860
  }
29734
- Object.assign(K, { roofs });
29861
+ const defined = { roofs };
29862
+ Object.assign(K, defined);
29735
29863
  }
29864
+ var paletteMeta = (colors) => colors.meta;
29736
29865
  function installRoofGutters(K, shared2) {
29737
29866
  const { boxC, bx, cursor, roomAt } = K;
29738
29867
  const sh = (...a) => K.sh(...a);
@@ -29749,7 +29878,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29749
29878
  const draw2 = rnd2() < p, light = rnd2() < 0.6;
29750
29879
  void draw2;
29751
29880
  const on = true;
29752
- return { on, rnd: rnd2, color: high ? 3816770 : light ? 15527921 : 10857392, bad: (shared2.ctx.colors.meta && shared2.ctx.colors.meta.state) === "abandoned" || R.state === "abandoned", fallback: false };
29881
+ return { on, rnd: rnd2, color: high ? 3816770 : light ? 15527921 : 10857392, bad: paletteMeta(shared2.ctx.colors)?.state === "abandoned" || R.state === "abandoned", fallback: false };
29753
29882
  }
29754
29883
  function gutter(type, f, X0, Z0, X1, Z1, yb, touchesU) {
29755
29884
  const G = shared2.ctx.gutter, o = type === "fiber_cement" ? 0.3 : 0.45, x0 = X0 - (touchesU[0] ? 0 : o), x1 = X1 + (touchesU[2] ? 0 : o), z0 = Z0 - (touchesU[1] ? 0 : o), z1 = Z1 + (touchesU[3] ? 0 : o), c = G.color, y = yb - 0.05;
@@ -29791,7 +29920,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29791
29920
  const px = cx + sx * 0.06, pz = cz + sz * 0.06;
29792
29921
  if (!freeAt(px, pz, sx, sz)) return false;
29793
29922
  const floats = G.bad && G.ncond === 1, yt = yb - 0.1, ybx = floats ? 0.7 : 0.04;
29794
- G.ncond++;
29923
+ G.ncond = (G.ncond ?? 0) + 1;
29795
29924
  if (run2 >= 2) boxC("plain", (sides[run2][4] + px) / 2, yt, pz, Math.abs(sides[run2][4] - px), 0.07, 0.07, c);
29796
29925
  else boxC("plain", px, yt, (sides[run2][4] + pz) / 2, 0.07, 0.07, Math.abs(sides[run2][4] - pz), c);
29797
29926
  boxC("plain", px, (ybx + yt) / 2, pz, 0.08, yt - ybx, 0.08, c);
@@ -29825,7 +29954,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29825
29954
  function drain(x, z, px, pz, c) {
29826
29955
  const g0 = cursor.group;
29827
29956
  cursor.group = "f0";
29828
- if (px != null) boxC("plain", (px + x) / 2, 0.075, (pz + z) / 2, Math.abs(x - px) + 0.05, 0.05, Math.abs(z - pz) + 0.05, sh(c, 0.85));
29957
+ if (px != null && pz != null && c != null) boxC("plain", (px + x) / 2, 0.075, (pz + z) / 2, Math.abs(x - px) + 0.05, 0.05, Math.abs(z - pz) + 0.05, sh(c, 0.85));
29829
29958
  const t = 0.045;
29830
29959
  bx("plain", x - 0.12, 0, z - 0.12, x + 0.12, t - 6e-3, z + 0.12, 12170668);
29831
29960
  bx("metal", x - 0.11, t, z - 0.11, x + 0.11, t + 0.012, z + 0.11, 5922145);
@@ -29836,7 +29965,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29836
29965
  bx("metal", x - 0.085, t + 0.012, z - 6e-3, x + 0.085, t + 0.02, z + 6e-3, 9080466);
29837
29966
  cursor.group = g0;
29838
29967
  }
29839
- Object.assign(K, { gutterConfig, gutter, drain });
29968
+ const defined = { gutterConfig, gutter, drain };
29969
+ Object.assign(K, defined);
29840
29970
  }
29841
29971
  function installRoofSlabs(K, shared2) {
29842
29972
  const { boxC, bx, cursor, drain, roomAt, structurePiece } = K;
@@ -29868,15 +29998,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29868
29998
  side(free(j, i + 1), x1 + o - t, z0 - ez0, x1 + o, z1 + ez1);
29869
29999
  side(free(j - 1, i), x0 - ex0, z0 - o, x1 + ex1, z0 - o + t);
29870
30000
  side(free(j + 1, i), x0 - ex0, z1 + o - t, x1 + ex1, z1 + o);
29871
- if (shared2.ctx.gutter && shared2.ctx.gutter.on) for (const [ok, dx, dz] of [[free(j - 1, i), 0, -1], [free(j + 1, i), 0, 1], [free(j, i - 1), -1, 0], [free(j, i + 1), 1, 0]]) {
30001
+ const G = shared2.ctx.gutter;
30002
+ if (G && G.on && G.bz) for (const [ok, dx, dz] of [[free(j - 1, i), 0, -1], [free(j + 1, i), 0, 1], [free(j, i - 1), -1, 0], [free(j, i + 1), 1, 0]]) {
29872
30003
  const kd = f + ":" + dx + ":" + dz;
29873
- if (!ok || shared2.ctx.gutter.bz.has(kd)) continue;
29874
- shared2.ctx.gutter.bz.add(kd);
29875
- shared2.ctx.gutter.nbuz++;
29876
- const mx = (x0 + x1) / 2, mz = (z0 + z1) / 2, ex = dx ? dx < 0 ? x0 - o : x1 + o : mx, ez = dz ? dz < 0 ? z0 - o : z1 + o : mz, cc = shared2.ctx.gutter.color;
30004
+ if (!ok || G.bz.has(kd)) continue;
30005
+ G.bz.add(kd);
30006
+ G.nbuz = (G.nbuz ?? 0) + 1;
30007
+ const mx = (x0 + x1) / 2, mz = (z0 + z1) / 2, ex = dx ? dx < 0 ? x0 - o : x1 + o : mx, ez = dz ? dz < 0 ? z0 - o : z1 + o : mz, cc = G.color;
29877
30008
  boxC("plain", ex + dx * 0.15, yb + 0.1, ez + dz * 0.15, dx ? 0.42 : 0.14, 0.1, dz ? 0.42 : 0.14, cc);
29878
30009
  boxC("plain", ex + dx * 0.36, yb + 0.1, ez + dz * 0.36, dx ? 0.04 : 0.18, 0.14, dz ? 0.04 : 0.18, sh(cc, 0.8));
29879
- if (shared2.ctx.gutter.bad) boxC("plain", ex + dx * 0.05, yb + 0.5 * 0, ez + dz * 0.05, dx ? 0.06 : 0.3, 0.02, dz ? 0.06 : 0.3, 4868674);
30010
+ if (G.bad) boxC("plain", ex + dx * 0.05, yb + 0.5 * 0, ez + dz * 0.05, dx ? 0.06 : 0.3, 0.02, dz ? 0.06 : 0.3, 4868674);
29880
30011
  {
29881
30012
  const tx = ex + dx * 0.38, tz = ez + dz * 0.38;
29882
30013
  let lv = true;
@@ -29896,7 +30027,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29896
30027
  }
29897
30028
  }
29898
30029
  }
29899
- Object.assign(K, { slabs });
30030
+ const defined = { slabs };
30031
+ Object.assign(K, defined);
29900
30032
  }
29901
30033
  function installRoofTiles(K, shared2) {
29902
30034
  const { UV_SCALE, _Y, _h2, _q, accFor, cursor, put, rgbOf, structurePiece } = K;
@@ -30027,7 +30159,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30027
30159
  }
30028
30160
  return m ? structurePiece(m.id) : null;
30029
30161
  }
30030
- Object.assign(K, { R_STYLE, tileRelief, ridge, pieceOfPane });
30162
+ const defined = { R_STYLE, tileRelief, ridge, pieceOfPane };
30163
+ Object.assign(K, defined);
30031
30164
  }
30032
30165
  function installRoofRect(K, shared2) {
30033
30166
  const { R_STYLE, bx, cursor, pieceOfPane, polyFace, ridge, tileRelief } = K;
@@ -30071,7 +30204,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30071
30204
  }
30072
30205
  const rm = alongX ? dz / 2 : dx / 2;
30073
30206
  {
30074
- const rr = shared2.ctx.roofRects[shared2.ctx.roofRects.length - 1];
30207
+ const roofRects = shared2.ctx.roofRects, rr = roofRects[roofRects.length - 1];
30075
30208
  if (rr && !rr.yb) Object.assign(rr, { yb, tp, gable: !!gable, alongX, exterior: [x0, z0, x1, z1], rm });
30076
30209
  }
30077
30210
  if (gable) {
@@ -30108,7 +30241,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30108
30241
  }
30109
30242
  }
30110
30243
  }
30111
- Object.assign(K, { roofRect });
30244
+ const defined = { roofRect };
30245
+ Object.assign(K, defined);
30112
30246
  }
30113
30247
  function installMirrors(K, shared2) {
30114
30248
  const { DOC, THREE, Reflector, MIRRORS, Y0, _Y, roomAt } = K;
@@ -30117,9 +30251,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30117
30251
  function mirrorEnv() {
30118
30252
  if (shared2.mirrorEnv) return shared2.mirrorEnv;
30119
30253
  const mk = (f) => {
30254
+ if (!DOC) throw new Error("game-floorplan-three: the mirrors need a document (options.document)");
30120
30255
  const c = DOC.createElement("canvas");
30121
30256
  c.width = c.height = 64;
30122
30257
  const g = c.getContext("2d");
30258
+ if (!g) throw new Error("game-floorplan-three: no 2d canvas context");
30123
30259
  f(g);
30124
30260
  return c;
30125
30261
  };
@@ -30178,7 +30314,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30178
30314
  B.N.push(v.x, v.y, v.z);
30179
30315
  B.U.push(ua.getX(i), ua.getY(i));
30180
30316
  }
30181
- for (const k of geo.index.array) B.I.push(B.nv + k);
30317
+ for (const k of geo.index?.array ?? []) B.I.push(B.nv + k);
30182
30318
  B.nv += pa.count;
30183
30319
  geo.dispose();
30184
30320
  }
@@ -30256,7 +30392,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30256
30392
  m.fake.visible = !on;
30257
30393
  }
30258
30394
  }
30259
- Object.assign(K, { mirrorEnv, newMirrorState, assembleMirrors, floorAtY, chooseMirror });
30395
+ const defined = { mirrorEnv, newMirrorState, assembleMirrors, floorAtY, chooseMirror };
30396
+ Object.assign(K, defined);
30260
30397
  }
30261
30398
  function installCars(K, shared2) {
30262
30399
  const { THREE, FLEET, _Y } = K;
@@ -30267,13 +30404,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30267
30404
  high: ["electric_hatch", "hybrid_suv", "midsize_suv", "v8_coupe", "large_suv", "midsize_pickup", "crossover_pickup", "fastback_sedan"]
30268
30405
  }, K.cfg.carKinds);
30269
30406
  const CAR_CACHE = /* @__PURE__ */ new Map();
30270
- function materialSignature(m) {
30407
+ function materialSignature(material) {
30408
+ const m = material;
30271
30409
  const f = (v) => v == null ? "" : typeof v === "number" ? v.toFixed(3) : v.isColor ? v.getHexString() : v.uuid || String(v);
30272
30410
  return [m.type, f(m.color), f(m.roughness), f(m.metalness), f(m.opacity), m.transparent ? 1 : 0, m.side, f(m.map), f(m.emissive), f(m.emissiveIntensity), m.vertexColors ? 1 : 0, m.flatShading ? 1 : 0, f(m.envMapIntensity), f(m.alphaTest)].join("|");
30273
30411
  }
30274
30412
  const BUCKETS = /* @__PURE__ */ new Map();
30275
- function bucketMaterial(m) {
30276
- if (m.type !== "MeshStandardMaterial" || m.map || m.alphaTest || m.vertexColors || !m.color) return null;
30413
+ function bucketMaterial(material) {
30414
+ if (material.type !== "MeshStandardMaterial") return null;
30415
+ const m = material;
30416
+ if (m.map || m.alphaTest || m.vertexColors || !m.color) return null;
30277
30417
  const mt = m.metalness > 0.5 ? 2 : m.metalness > 0.2 ? 1 : 0, rg = m.roughness < 0.3 ? 0 : m.roughness < 0.6 ? 1 : 2, tr = m.transparent || m.opacity < 1, op = tr ? Math.max(0.2, Math.min(0.9, Math.round(m.opacity * 5) / 5)) : 1, sig = "bucket" + mt + rg + "s" + m.side + (tr ? "t" + op : "");
30278
30418
  let b = BUCKETS.get(sig);
30279
30419
  if (!b) {
@@ -30285,7 +30425,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30285
30425
  }
30286
30426
  function carModel(k, seed) {
30287
30427
  const kc = k + "|" + shared2.quality + "|" + (seed || 0);
30288
- if (CAR_CACHE.has(kc)) return CAR_CACHE.get(kc);
30428
+ if (CAR_CACHE.has(kc)) return CAR_CACHE.get(kc) ?? null;
30289
30429
  if (!FLEET) return null;
30290
30430
  let res = null;
30291
30431
  try {
@@ -30293,8 +30433,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30293
30433
  c.root.updateMatrixWorld(true);
30294
30434
  const inv = new THREE.Matrix4();
30295
30435
  const byMaterial = /* @__PURE__ */ new Map(), tmp = new THREE.Matrix4(), v = new THREE.Vector3(), nm = new THREE.Matrix3(), bb = new THREE.Box3();
30296
- c.g.traverse((o) => {
30297
- if (!o.isMesh || o.isInstancedMesh || o.isSkinnedMesh || !o.geometry || !o.geometry.attributes.position) return;
30436
+ c.g.traverse((node) => {
30437
+ if (!isMesh(node)) return;
30438
+ const o = node;
30439
+ if (o.isInstancedMesh || o.isSkinnedMesh || !o.geometry || !o.geometry.attributes.position) return;
30298
30440
  for (let p = o; p; p = p.parent) if (p.visible === false) return;
30299
30441
  const mats = Array.isArray(o.material) ? o.material : [o.material];
30300
30442
  let geo = o.geometry;
@@ -30308,7 +30450,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30308
30450
  const pa = geo.attributes.position, na = geo.attributes.normal, ua = geo.attributes.uv, total = pa.count;
30309
30451
  const grs = Array.isArray(o.material) && o.geometry.groups.length ? o.geometry.groups : [{ start: 0, count: total, materialIndex: 0 }];
30310
30452
  for (const gr of grs) {
30311
- const m = mats[gr.materialIndex] || mats[0];
30453
+ const m = (gr.materialIndex != null ? mats[gr.materialIndex] : void 0) || mats[0];
30312
30454
  if (!m) continue;
30313
30455
  const a0 = Math.min(gr.start, total), n0 = Math.min(gr.count, total - a0) - Math.min(gr.count, total - a0) % 3;
30314
30456
  if (n0 < 3) continue;
@@ -30409,7 +30551,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30409
30551
  return g;
30410
30552
  }
30411
30553
  function assembleCars(groups) {
30412
- if (shared2.quality === "game") return assembleMergedCars(groups);
30554
+ if (shared2.quality === "game") {
30555
+ assembleMergedCars(groups);
30556
+ return;
30557
+ }
30413
30558
  for (const C of CARS) {
30414
30559
  const g = carGroup(C.k, C.w, C.d, C.seed);
30415
30560
  if (!g) continue;
@@ -30460,7 +30605,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30460
30605
  (groups[B.parent] || (groups[B.parent] = new THREE.Group())).add(m);
30461
30606
  }
30462
30607
  }
30463
- Object.assign(K, { CARS, CAR_BY_STYLE, CAR_CACHE, materialSignature, BUCKETS, bucketMaterial, carModel, carGroup, assembleCars, assembleMergedCars });
30608
+ const defined = { CARS, CAR_BY_STYLE, CAR_CACHE, materialSignature, BUCKETS, bucketMaterial, carModel, carGroup, assembleCars, assembleMergedCars };
30609
+ Object.assign(K, defined);
30464
30610
  }
30465
30611
  function installHouseBuilding(K, shared2) {
30466
30612
  const { bx, cursor } = K;
@@ -30514,12 +30660,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30514
30660
  bx("plaster", Math.min(hall[0] - 3, color2[0]), ytop, Math.min(un[1] ? unitBox(un[1])[1] : 0, el[1]), Math.max(color2[2], un0[2]), ytop + 0.2, Math.max(un0[3], un[1] ? unitBox(un[1])[3] : 0), 11841704);
30515
30661
  shared2.ctx.limits = { x0: Math.min(hall[0] - 3, color2[0]), z0: Math.min(el[1], un[1] ? unitBox(un[1])[1] : 0), x1: Math.max(color2[2], un0[2]), z1: Math.max(un0[3], un[1] ? unitBox(un[1])[3] : 0) };
30516
30662
  }
30517
- Object.assign(K, { building });
30663
+ const defined = { building };
30664
+ Object.assign(K, defined);
30518
30665
  }
30519
30666
  function installUtilitiesWater(K, shared2) {
30520
30667
  const { THREE, _Y, _q, cursor, cylBase, part, pieceRecord, put } = K;
30521
30668
  function createWater(r, state) {
30522
- const H = r.utilities.plumbing, cap = H ? +H.capacityL || 0 : 0, ls = { dry: [], full: [] }, points = {}, itemPoint = {};
30669
+ const H = r.utilities?.plumbing, cap = H ? +H.capacityL || 0 : 0, ls = { dry: [], full: [] }, points = {}, itemPoint = {};
30523
30670
  if (H) for (const p of H.points) {
30524
30671
  points[p.id] = p;
30525
30672
  itemPoint[p.item] = p.id;
@@ -30608,14 +30755,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30608
30755
  }
30609
30756
  const _v3 = new THREE.Vector3();
30610
30757
  function waterPipes() {
30611
- const H = shared2.ctx.r.utilities.plumbing;
30758
+ const H = shared2.ctx.r.utilities?.plumbing;
30612
30759
  if (!H || !H.visibleRuns) return;
30613
30760
  const nA = shared2.ctx.r.floors.length;
30614
30761
  const groupOf = (c) => c && c.floor >= 0 ? "f" + Math.min(c.floor, nA - 1) : "lot", xyz = (p) => [p[0], p[2], p[1]];
30615
30762
  for (const tr of H.visibleRuns) {
30616
30763
  const pts = tr.points.map(xyz), d = tr.diameter || 0.025;
30617
30764
  if (tr.exposed === "wall") {
30618
- const pt = H.points.find((p) => p.run === tr.id), com = shared2.ctx.roomById[tr.to], g2 = groupOf(com || pt && { floor: pt.floor });
30765
+ const pt = H.points.find((p) => p.run === tr.id), com = tr.to != null ? shared2.ctx.roomById[tr.to] : void 0, g2 = groupOf(com || pt && { floor: pt.floor });
30619
30766
  part("wall_pipe", [0, 0, 0], () => {
30620
30767
  for (let i = 0; i + 1 < pts.length; i++) pipe(pts[i], pts[i + 1], d, PIPE_COLOR);
30621
30768
  for (const p of pts) cylBase("plain", p[0], p[1] - d, p[2], d * 0.7, d * 2, PIPE_COLOR);
@@ -30637,16 +30784,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30637
30784
  cursor.pc = null;
30638
30785
  }
30639
30786
  }
30640
- Object.assign(K, { createWater, PIPE_COLOR, pipe, _v3, waterPipes });
30787
+ const defined = { createWater, PIPE_COLOR, pipe, _v3, waterPipes };
30788
+ Object.assign(K, defined);
30641
30789
  }
30642
30790
  function installUtilitiesElectrical(K, shared2) {
30643
30791
  const { _Y, _q, _v3, bx, cursor, cylBase, pieceRecord, put } = K;
30644
30792
  const sh = (...a) => K.sh(...a);
30645
30793
  function electricalStructure() {
30646
- const E = shared2.ctx.r.utilities.electrical;
30794
+ const R = shared2.ctx.r, E = R.utilities?.electrical;
30647
30795
  shared2.ctx.electricalInfo = null;
30648
30796
  if (!E) return;
30649
- const R = shared2.ctx.r, nA = R.floors.length, lotGroup = R.lot ? "lot" : "f0", concreteColor = 11973547, iron = 4869200, wireRun = 1842206, info = { pole: null, meter: null, panel: null, conduits: [], outlets: [], switches: [], circuits: E.circuits || [], exposed: !!E.exposed };
30797
+ const nA = R.floors.length, lotGroup = R.lot ? "lot" : "f0", concreteColor = 11973547, iron = 4869200, wireRun = 1842206, info = { pole: null, meter: null, panel: null, conduits: [], outlets: [], switches: [], circuits: E.circuits || [], exposed: !!E.exposed };
30650
30798
  const en22 = E.serviceEntrance, KV = shared2.ctx.iv ? shared2.ctx.iv.plane : null;
30651
30799
  const wireL = (a, b, r_ = 8e-3) => {
30652
30800
  const L = Math.hypot(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
@@ -30751,7 +30899,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30751
30899
  _q.setFromUnitVectors(_Y, _v3.set(dx / L, dy / L, dz / L));
30752
30900
  put("plain", "cyl", (a[0] + b[0]) / 2, (a[1] + b[1]) / 2, (a[2] + b[2]) / 2, _q, diameter, L, diameter, color2);
30753
30901
  }
30754
- Object.assign(K, { electricalStructure, pipe2 });
30902
+ const defined = { electricalStructure, pipe2 };
30903
+ Object.assign(K, defined);
30755
30904
  }
30756
30905
  function installHouseBaseboard(K, shared2) {
30757
30906
  const { Y0, bx, cursor, sideOf } = K;
@@ -30787,7 +30936,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30787
30936
  strip(W, y0, y0 + 0.045, 0, W, "sidewalk", cal);
30788
30937
  }
30789
30938
  }
30790
- Object.assign(K, { baseboardAndSidewalk });
30939
+ const defined = { baseboardAndSidewalk };
30940
+ Object.assign(K, defined);
30791
30941
  }
30792
30942
  function installUtilitiesSolar(K, shared2) {
30793
30943
  const { Y0, boxC, bx, cursor, cylBase } = K;
@@ -30800,6 +30950,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30800
30950
  if (u >= a - 0.05 && u <= c + 0.05 && v >= b - 0.05 && v <= d + 0.05) y = Math.max(y == null ? -1e9 : y, rr.yb);
30801
30951
  continue;
30802
30952
  }
30953
+ if (!rr.exterior || rr.tp == null || rr.rm == null) continue;
30803
30954
  const [x0, z0, x1, z1] = rr.exterior;
30804
30955
  if (u < x0 || u > x1 || v < z0 || v > z1) continue;
30805
30956
  const dz = Math.min(v - z0, z1 - v), dx = Math.min(u - x0, x1 - u), dd = rr.gable ? rr.alongX ? dz : dx : Math.min(dx, dz), h = rr.yb + rr.tp * Math.min(dd, rr.rm);
@@ -30808,7 +30959,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30808
30959
  return y;
30809
30960
  }
30810
30961
  function solar() {
30811
- const R = shared2.ctx.r, S = R.utilities.solar;
30962
+ const R = shared2.ctx.r, S = R.utilities?.solar;
30812
30963
  shared2.ctx.solarInfo = null;
30813
30964
  if (!S || !S.panels || !S.panels.length) return;
30814
30965
  cursor.group = "roof";
@@ -30851,13 +31002,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30851
31002
  bx("plain", iv.u - W * 0.6, y0 + 0.05, iv.v + fa0, iv.u + W * 0.6, y0 + 0.17, iv.v + fa1, 2106924);
30852
31003
  bx("emissive", iv.u - 0.03, y0 - 0.12, iv.v + fa0, iv.u + 0.03, y0 - 0.09, iv.v + fa1, 6479994);
30853
31004
  }
30854
- const top = Math.max(...(shared2.ctx.roofRects || []).filter((t2) => t2.yb != null).map((t2) => t2.yb), Y0(fa) + 2.8);
31005
+ const top = Math.max(...(shared2.ctx.roofRects || []).flatMap((t2) => t2.yb != null ? [t2.yb] : []), Y0(fa) + 2.8);
30855
31006
  cylBase("plain", iv.u, y0 + h / 2, iv.v, 0.016, Math.max(0.2, top - 0.2 - (y0 + h / 2)), 15262936);
30856
31007
  info.inverter = { id: iv.id, pos: [iv.u, y0, iv.v], side: iv.side, link: iv.link };
30857
31008
  }
30858
31009
  shared2.ctx.solarInfo = info;
30859
31010
  }
30860
- Object.assign(K, { roofHeightAt, solar });
31011
+ const defined = { roofHeightAt, solar };
31012
+ Object.assign(K, defined);
30861
31013
  }
30862
31014
  function installHouseOutbuildings(K, shared2) {
30863
31015
  const { t, bx, cursor, floorColor } = K;
@@ -30870,7 +31022,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30870
31022
  counts.set(w.floor, i + 1);
30871
31023
  return w.id ? w : Object.assign({}, w, { id: `wall_${w.floor}_${i}` });
30872
31024
  }) });
30873
- const E = (r.outbuildings || []).filter((e) => e && e.walls && e.walls.length && e.interior && e.interior.length);
31025
+ const E = (r.outbuildings || []).filter((e) => !!(e && e.walls && e.walls.length && e.interior && e.interior.length));
30874
31026
  if (!E.length) return r;
30875
31027
  const rooms = r.rooms.slice(), walls = r.walls.slice(), doors = r.doors.slice(), windows = r.windows.slice(), items = r.items.filter((m) => m.type !== "outbuilding");
30876
31028
  for (const e of E) {
@@ -30884,7 +31036,22 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30884
31036
  const alongU = p.axis === "u", below = p.pos < (alongU ? cz : cx);
30885
31037
  doors.push({ id: p.id, floor: 0, u: p.u, v: p.v, axis: p.axis, pos: p.pos, at: p.at, width: p.width, a: below ? "outside" : e.id, b: below ? e.id : "outside", opensTo: e.id, exterior: true, side: p.side, leaves: 1, model: "single", hinge: "start", zones: [], blocked: false, outbuilding: e.id });
30886
31038
  }
30887
- for (const j of e.windows || []) windows.push({ id: j.id, floor: 0, u: j.u, v: j.v, axis: j.axis, pos: j.pos, at: j.at, width: j.width, y0: j.y0, y1: j.y1, room: e.id, side: j.side, outbuilding: e.id });
31039
+ for (const j of e.windows || []) windows.push({
31040
+ id: j.id,
31041
+ floor: 0,
31042
+ u: j.u,
31043
+ v: j.v,
31044
+ axis: j.axis,
31045
+ pos: j.pos,
31046
+ at: j.at,
31047
+ width: j.width,
31048
+ y0: j.y0 ?? 1,
31049
+ y1: j.y1 ?? 2,
31050
+ /* the structure always gives a window its sill and head (1.0, 2.0) */
31051
+ room: e.id,
31052
+ side: j.side,
31053
+ outbuilding: e.id
31054
+ });
30888
31055
  (e.items || []).forEach((m, i) => items.push({ id: e.id + "." + m.type + i, type: m.type, category: m.category, x: m.u, z: m.v, ry: m.ry || 0, w: m.w, d: m.d, h: m.h, y: 0.04, frontU: m.frontU, frontV: m.frontV, room: e.id, floor: 0, outdoor: false, aabb: m.aabb, color: "wood" }));
30889
31056
  items.push({ id: e.id + ".ceiling_light", type: "ceiling_light", category: "ceiling_light", x: cx, z: cz, ry: 0, w: 0.35, d: 0.35, h: 0.1, y: pe - 0.1, room: e.id, floor: 0, outdoor: false, assembly: "ceiling", color: "metal", decor: true });
30890
31057
  }
@@ -30905,7 +31072,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30905
31072
  }
30906
31073
  }
30907
31074
  }
30908
- Object.assign(K, { OUTBUILDING_USE, applyOutbuildings, outbuildings });
31075
+ const defined = { OUTBUILDING_USE, applyOutbuildings, outbuildings };
31076
+ Object.assign(K, defined);
30909
31077
  }
30910
31078
  function installFurnitureApi(K, _shared) {
30911
31079
  const { _e, _h2, _q, boxC, cursor, macroGround, polyFace, put } = K;
@@ -30968,7 +31136,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
30968
31136
  return { b: (mat, x, y, z, w, h, d, color2, ry, rx, rz) => A.box(M, mat, x, y0 + y, z, w, h, d, color2, ry || 0, rx || 0, rz || 0), c: (mat, x, y, z, r, h, color2, rx, rz, seg2) => A.cylinder(M, mat, x, y0 + y, z, r, h, color2, rx || 0, rz || 0, seg2), rnd: rngOf(M), wood: paletteColor(M, "wood", 8016948), met: paletteColor(M, "metal", 10133154) };
30969
31137
  }
30970
31138
  const PE = Math.PI / 2;
30971
- Object.assign(K, { MATERIAL_MAP: MATERIAL_MAP2, mm, LIGHTS, makeApi, sh, paletteColor, rngOf, kk, PE });
31139
+ const defined = { MATERIAL_MAP: MATERIAL_MAP2, mm, LIGHTS, makeApi, sh, paletteColor, rngOf, kk, PE };
31140
+ Object.assign(K, defined);
30972
31141
  }
30973
31142
  function installFurnitureBuilders(K, _shared) {
30974
31143
  const { PE, _q, kit2, kk, paletteColor, put, rngOf, sh } = K;
@@ -31094,7 +31263,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
31094
31263
  for (let s = 0; s < np; s++) lb("fabric", np === 1 ? 0 : (s ? 1 : -1) * w * 0.23, 0.5, -d / 2 + 0.3, w * (np === 1 ? 0.6 : 0.4), 0.12, 0.34, 15789798, (s ? 1 : -1) * 0.08);
31095
31264
  },
31096
31265
  wardrobe(M, A) {
31097
- const { b: lb } = kk(M, A), w = M.w, d = M.d, h = M.h, wood = M.color != null && false ? M.color : paletteColor(M, "wood", 5980208), np = Math.max(2, Math.round(w / 0.7));
31266
+ const { b: lb } = kk(M, A), w = M.w, d = M.d, h = M.h, wood = paletteColor(M, "wood", 5980208), np = Math.max(2, Math.round(w / 0.7));
31098
31267
  lb("wood", 0, 0.06, 0, w, h - 0.06, d, wood);
31099
31268
  lb("wood", 0, h, 0, w + 0.04, 0.04, d + 0.04, sh(wood, 0.8));
31100
31269
  lb("wood", 0, 0, 0, w - 0.04, 0.06, d - 0.04, sh(wood, 0.4));
@@ -31486,7 +31655,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
31486
31655
  lb("metal", 0, h - 0.04, d / 2, w, 0.03, 0.03, 3815994);
31487
31656
  }
31488
31657
  };
31489
- Object.assign(K, { FURNITURE });
31658
+ const defined = { FURNITURE };
31659
+ Object.assign(K, defined);
31490
31660
  }
31491
31661
  function installFurnitureTypeTable(K, _shared) {
31492
31662
  const { FURNITURE, kk, paletteColor } = K;
@@ -31494,7 +31664,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
31494
31664
  function typeTable(props) {
31495
31665
  const B = props.builders, T2 = {};
31496
31666
  const mv = (type, id) => {
31497
- if (B[id || type]) T2[type] = { f: B[id || type], source: "props3d" };
31667
+ const f = B[id || type];
31668
+ if (f) T2[type] = { f, source: "props3d" };
31498
31669
  };
31499
31670
  const mine = (type, f, source = "game") => {
31500
31671
  T2[type] = { f, source };
@@ -31633,7 +31804,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
31633
31804
  extraTypes(T2, props);
31634
31805
  return T2;
31635
31806
  }
31636
- Object.assign(K, { typeTable });
31807
+ const defined = { typeTable };
31808
+ Object.assign(K, defined);
31637
31809
  }
31638
31810
  function installFurnitureTaps(K, shared2) {
31639
31811
  shared2.tapCount = 0;
@@ -31695,7 +31867,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
31695
31867
  }, { id: id + "_a", target: id, hidden: true, fluid: "water" });
31696
31868
  return id;
31697
31869
  }
31698
- Object.assign(K, { counterTap, wallTap });
31870
+ const defined = { counterTap, wallTap };
31871
+ Object.assign(K, defined);
31699
31872
  }
31700
31873
  function installFurnitureFixtures(K, _shared) {
31701
31874
  const seedKey = (id) => K.seedKey(id);
@@ -31804,7 +31977,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
31804
31977
  const a = rnd2() * 6.283, u = Math.sqrt(rnd2()), ph = (rnd2() - 0.2) * 1.2, dx = Math.cos(a) * u * R * 0.75, dz = Math.sin(a) * u * R * 0.75, dy = (o.flatten ? 0.35 : 0.55) * R * (Math.sin(ph) * 0.5 + 0.5) * 1.5 - R * 0.15;
31805
31978
  const r = R * (0.34 + rnd2() * 0.22) * (1 - u * 0.25), alt = r * 2 * (o.flatten ? 0.75 : 0.95), f = 0.72 + Math.min(1, (dy + R * 0.2) / (R * 1.2)) * 0.32 + rnd2() * 0.12;
31806
31979
  K2.e("plant", cx + dx, cy + dy + r * 0.5, cz + dz, r, alt, sh(green2, f));
31807
- if (o.flower && rnd2() < o.flower) {
31980
+ if (o.flower && o.flowers && rnd2() < o.flower) {
31808
31981
  const fa = rnd2() * 6.283;
31809
31982
  K2.e("plain", cx + dx + Math.cos(fa) * r * 0.78, cy + dy + r * 0.5 + rnd2() * r * 0.5, cz + dz + Math.sin(fa) * r * 0.78, 0.028 + rnd2() * 0.012, 0.05, o.flowers[rnd2() * o.flowers.length | 0]);
31810
31983
  }
@@ -31917,7 +32090,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
31917
32090
  else blobs(K2, x, bh - 0.05, z, 0.24 + rnd2() * 0.08, 6, green2, rnd2, { flatten: true, flower: tp === "flower" ? 0.9 : 0.25, flowers: FLOWERS.slice(i % 3, i % 3 + 3) });
31918
32091
  }
31919
32092
  }
31920
- Object.assign(K, { GREENS: GREENS2, FLOWERS, blobs, potModel, arcLeaf, tuft, palm_tree, treeModel, shrubModel, potPlant, tablePot, planterModel });
32093
+ const defined = { GREENS: GREENS2, FLOWERS, blobs, potModel, arcLeaf, tuft, palm_tree, treeModel, shrubModel, potPlant, tablePot, planterModel };
32094
+ Object.assign(K, defined);
31921
32095
  }
31922
32096
  function installFurnitureYard(K, shared2) {
31923
32097
  const seedKey = (id) => K.seedKey(id);
@@ -32071,7 +32245,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32071
32245
  };
32072
32246
  FURNITURE.mailbox = function(M, A) {
32073
32247
  const K2 = kit2(M, A, 0), w = M.w || 0.3, d = M.d || 0.22, h = M.h || 0.3, y = M.y != null && M.y > 0 ? M.y : 1, structure = STYLE(), pc = structure === "high" ? 2763824 : structure === "mid" ? 13676640 : 13126202, rnd2 = rngString(SEED() + "|" + seedKey(M.seed) + "|correio");
32074
- if (M.pole !== false && !(M.y > 0)) {
32248
+ if (M.pole !== false && !(M.y != null && M.y > 0)) {
32075
32249
  K2.b("plain", 0, 0, -d / 2 - 0.1, 0.12, y, 0.12, 12104874);
32076
32250
  }
32077
32251
  K2.b("metal", 0, y, 0, w, h * 0.78, d, pc);
@@ -32091,7 +32265,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32091
32265
  );
32092
32266
  K2.b("plain", 0, y + h * 0.62, d / 2 + 4e-3, 0.08, 0.05, 4e-3, 15921386);
32093
32267
  };
32094
- Object.assign(K, { CLOTHES_COLORS, strip, garment: garment2 });
32268
+ const defined = { CLOTHES_COLORS, strip, garment: garment2 };
32269
+ Object.assign(K, defined);
32095
32270
  }
32096
32271
  function installFurnitureExtraTypes(K, _shared) {
32097
32272
  const seedKey = (id) => K.seedKey(id);
@@ -32149,7 +32324,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32149
32324
  tuft(K2, 0, 0, 0, Math.max(0.2, (M.w || 0.4) / 2), 16, 5212738, rnd2);
32150
32325
  });
32151
32326
  }
32152
- Object.assign(K, { extraTypes });
32327
+ const defined = { extraTypes };
32328
+ Object.assign(K, defined);
32153
32329
  }
32154
32330
  function installFurniturePlaceItems(K, shared2) {
32155
32331
  const { THREE, Y0, _col, boxC, colorOf, cursor, decorLights, makeApi, structurePiece } = K;
@@ -32169,8 +32345,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32169
32345
  if (m.type === "stairs") continue;
32170
32346
  const exterior = m.outdoor || m.floor < 0, f = exterior ? -1 : Math.min(m.floor, R.floors.length - 1);
32171
32347
  cursor.group = exterior ? "lot" : "f" + f;
32172
- const com = shared2.ctx.roomById[m.room], base = exterior ? 0 : Y0(f);
32173
- const M = { x: m.x, z: m.z, ry: m.ry || 0, w: m.w, d: m.d, h: m.h, y: m.y || 0, base, floor: exterior ? -1 : f, palette: shared2.ctx.colors, color: m.category === "ground_cover" ? void 0 : colorOf(m.color) != null ? colorOf(m.color) : void 0, seed: m.id, room: m.room, typeWith: com ? com.type : null, ceiling: com ? com.ceiling : 2.9, on: shared2.ctx.night, light: shared2.ctx.night, lit: shared2.ctx.night, open: !!m.doorOpen, overhead: m.overhead, assembly: m.assembly, hose: m.hose };
32348
+ const com = m.room != null ? shared2.ctx.roomById[m.room] : void 0, base = exterior ? 0 : Y0(f);
32349
+ const M = { x: m.x, z: m.z, ry: m.ry || 0, w: m.w, d: m.d, h: m.h, y: m.y || 0, base, floor: exterior ? -1 : f, palette: shared2.ctx.colors, color: m.category === "ground_cover" ? void 0 : colorOf(m.color) ?? void 0, seed: m.id, room: m.room, typeWith: com ? com.type : null, ceiling: com ? com.ceiling : 2.9, on: shared2.ctx.night, light: shared2.ctx.night, lit: shared2.ctx.night, open: !!m.doorOpen, overhead: m.overhead, assembly: m.assembly, hose: m.hose };
32174
32350
  if (m.category === "ground_cover" && m.polygon) {
32175
32351
  const xs = m.polygon.map((p) => p[0]), zs = m.polygon.map((p) => p[1]);
32176
32352
  M.x = (Math.min(...xs) + Math.max(...xs)) / 2;
@@ -32247,7 +32423,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32247
32423
  boxC("plain", m.x, M.base + (m.y || 0) + h / 2, m.z, m.w, h, m.d, color2, 0, m.ry || 0, 0);
32248
32424
  shared2.ctx.labels.push({ pos: new THREE.Vector3(m.x, M.base + (m.y || 0) + h + 0.15, m.z), text: m.type, group, type: "no_model" });
32249
32425
  }
32250
- Object.assign(K, { houseItems, waterTankOfHouse, hashColor, labeledBox });
32426
+ const defined = { houseItems, waterTankOfHouse, hashColor, labeledBox };
32427
+ Object.assign(K, defined);
32251
32428
  }
32252
32429
  function installVegetationBridge(K, shared2) {
32253
32430
  const seedKey = (id) => K.seedKey(id);
@@ -32280,7 +32457,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32280
32457
  const ids = VEG_MAP[m.type], can2 = VEG_PLANTER[m.type];
32281
32458
  if (!ids && !can2) return false;
32282
32459
  const rnd2 = rngString(SEED() + "|" + seedKey(m.id) + "|veg"), pick3 = (l) => l[Math.min(l.length - 1, rnd2() * l.length | 0)], ok = (id) => {
32283
- if (V3.ok.has(id)) return V3.ok.get(id);
32460
+ if (V3.ok.has(id)) return V3.ok.get(id) === true;
32284
32461
  let r = true;
32285
32462
  try {
32286
32463
  V3.S.toSpec(id);
@@ -32326,7 +32503,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32326
32503
  obj.position.y = G.y;
32327
32504
  obj.name = "vegetation";
32328
32505
  obj.traverse((o) => {
32329
- if (o.isMesh) {
32506
+ if (isMesh(o)) {
32330
32507
  o.castShadow = true;
32331
32508
  o.receiveShadow = true;
32332
32509
  o.name = "veg/" + o.name;
@@ -32341,7 +32518,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32341
32518
  }
32342
32519
  shared2.ctx.vegInfo = { plants: pl, triangles: tri, colliders: col, lodCounts: lod, materials: mats };
32343
32520
  }
32344
- Object.assign(K, { VEG_POT, VEG_CACTUS, VEG_MAP, VEG_PLANTER, vegItem, assembleVegetation });
32521
+ const defined = { VEG_POT, VEG_CACTUS, VEG_MAP, VEG_PLANTER, vegItem, assembleVegetation };
32522
+ Object.assign(K, defined);
32345
32523
  }
32346
32524
  function installInteractionState(K, shared2) {
32347
32525
  const { THREE, cfg, colliderChanged, invalidateShadow, invalidate, UV_SCALE, applyPart, texture } = K;
@@ -32407,12 +32585,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32407
32585
  shared2.inter.msg = { text, until: performance.now() + MESSAGE_MS };
32408
32586
  if (cfg.onMessage) cfg.onMessage(text);
32409
32587
  };
32410
- function definePiece(name, def) {
32588
+ const I = () => shared2.inter;
32589
+ function definePiece(name, definition) {
32590
+ const def = definition;
32411
32591
  def.name = name;
32412
32592
  def.meshes = [];
32413
32593
  def.t = def.target = shared2.partState.has(name) ? shared2.partState.get(name) : def.t0 || 0;
32414
- shared2.inter.defs.set(name, def);
32415
- shared2.inter.pieces.push(def);
32594
+ I().defs.set(name, def);
32595
+ I().pieces.push(def);
32416
32596
  return def;
32417
32597
  }
32418
32598
  const localOf = (M, lx, lz) => {
@@ -32424,17 +32604,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32424
32604
  return true;
32425
32605
  }
32426
32606
  function assembleInteractive(gs) {
32427
- for (const [name, def] of shared2.inter.defs) {
32607
+ const inter = I();
32608
+ for (const [name, def] of inter.defs) {
32428
32609
  const g = gs[name];
32429
32610
  if (!g) continue;
32430
32611
  delete gs[name];
32431
32612
  const outer = new THREE.Group();
32432
- outer.position.set(...def.pivot);
32613
+ outer.position.fromArray(def.pivot);
32433
32614
  outer.rotation.y = def.ry || 0;
32434
32615
  outer.updateMatrix();
32435
- const inv = new THREE.Matrix4().compose(new THREE.Vector3(...def.pivot), new THREE.Quaternion().setFromAxisAngle(_EY, def.ry || 0), _UM3).invert();
32616
+ const inv = new THREE.Matrix4().compose(new THREE.Vector3().fromArray(def.pivot), new THREE.Quaternion().setFromAxisAngle(_EY, def.ry || 0), _UM3).invert();
32436
32617
  g.traverse((o) => {
32437
- if (o.isMesh) {
32618
+ if (isMesh(o)) {
32438
32619
  o.geometry.applyMatrix4(inv);
32439
32620
  o.userData.piece = def;
32440
32621
  def.meshes.push(o);
@@ -32446,13 +32627,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32446
32627
  const parent = def.leaf ? def.leaf.gs[def.k] : gs[def.parent] || (gs[def.parent] = new THREE.Group());
32447
32628
  if (parent) parent.add(outer);
32448
32629
  if (def.roomId) {
32449
- if (!shared2.inter.lights.has(def.roomId)) shared2.inter.lights.set(def.roomId, []);
32450
- shared2.inter.lights.get(def.roomId).push(def);
32630
+ let lamps = inter.lights.get(def.roomId);
32631
+ if (!lamps) inter.lights.set(def.roomId, lamps = []);
32632
+ lamps.push(def);
32451
32633
  }
32452
32634
  applyPiece(def);
32453
32635
  }
32454
- for (const roomId of shared2.inter.litRooms) applyLight(roomId);
32455
- shared2.inter.defs.forEach((d) => {
32636
+ for (const roomId of inter.litRooms) applyLight(roomId);
32637
+ inter.defs.forEach((d) => {
32456
32638
  if (d.col) d.col.off = d.t > 0.5;
32457
32639
  });
32458
32640
  }
@@ -32460,6 +32642,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32460
32642
  const n = p.inner;
32461
32643
  if (!n) return;
32462
32644
  switch (p.kind) {
32645
+ /* each kind always sets its dimensions (sgn, angle, travel, k, axis) */
32463
32646
  case "swing":
32464
32647
  n.rotation.y = p.sgn * p.t * p.angle;
32465
32648
  break;
@@ -32492,8 +32675,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32492
32675
  }
32493
32676
  const DURATION = { swing: 0.55, drawer: 0.4, curtain: 0.9, gate_swing: 0.9, gate_tilt: 1.4, gate_slide: 1.6, lightSwitch: 0.12, part: 0.4 };
32494
32677
  function animateInteractive(dt) {
32495
- if (!shared2.inter.anim.size) return;
32496
- for (const p of shared2.inter.anim) {
32678
+ const inter = I();
32679
+ if (!inter.anim.size) return;
32680
+ for (const p of inter.anim) {
32497
32681
  const step = dt / (DURATION[p.kind] || 0.5), d = p.target - p.t;
32498
32682
  p.t = Math.abs(d) <= step ? p.target : p.t + Math.sign(d) * step;
32499
32683
  applyPiece(p);
@@ -32501,7 +32685,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32501
32685
  p.col.off = p.target > 0.5;
32502
32686
  colliderChanged(p.col);
32503
32687
  }
32504
- if (p.t === p.target) shared2.inter.anim.delete(p);
32688
+ if (p.t === p.target) inter.anim.delete(p);
32505
32689
  }
32506
32690
  invalidateShadow();
32507
32691
  }
@@ -32512,7 +32696,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32512
32696
  p.col.off = p.target > 0.5;
32513
32697
  colliderChanged(p.col);
32514
32698
  }
32515
- shared2.inter.anim.add(p);
32699
+ I().anim.add(p);
32516
32700
  }
32517
32701
  const lightBase = (roomId) => roomId == null ? true : shared2.partState.has("light:" + roomId) ? !!shared2.partState.get("light:" + roomId) : !!shared2.ctx.night;
32518
32702
  const lightOn = (roomId) => {
@@ -32520,20 +32704,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32520
32704
  return S ? S.ef : lightBase(roomId);
32521
32705
  };
32522
32706
  function applyLight(roomId) {
32523
- const on = lightOn(roomId);
32524
- for (const d of shared2.inter.lights.get(roomId) || []) for (const m of d.meshes) if (m.name.endsWith("/emissive")) m.material = on ? shared2.mats.emissive : shared2.mats.off;
32525
- const sw = shared2.inter.defs.get("ix:int:" + roomId);
32707
+ const on = lightOn(roomId), inter = I(), mats = shared2.mats;
32708
+ for (const d of inter.lights.get(roomId) || []) for (const m of d.meshes) if (m.name.endsWith("/emissive")) m.material = on ? mats.emissive : mats.off;
32709
+ const sw = inter.defs.get("ix:int:" + roomId);
32526
32710
  if (sw) {
32527
32711
  sw.target = on ? 1 : 0;
32528
- if (sw.t !== sw.target) shared2.inter.anim.add(sw);
32712
+ if (sw.t !== sw.target) inter.anim.add(sw);
32529
32713
  }
32530
32714
  invalidate();
32531
32715
  }
32532
32716
  function toggleLight(roomId) {
32533
32717
  const S = shared2.ctx.iv && shared2.ctx.iv.roomStates.get(roomId);
32534
32718
  if (S) {
32535
- ivRoomLight(shared2.ctx.iv, roomId, !S.ef);
32536
- const ef = ivRoomEffective(shared2.ctx.iv, S);
32719
+ const IV = shared2.ctx.iv;
32720
+ ivRoomLight(IV, roomId, !S.ef);
32721
+ const ef = ivRoomEffective(IV, S);
32537
32722
  if (ef !== S.ef) {
32538
32723
  S.ef = ef;
32539
32724
  applyLight(roomId);
@@ -32545,9 +32730,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32545
32730
  applyLight(roomId);
32546
32731
  if (cfg.onLight) cfg.onLight(roomId, lightOn(roomId));
32547
32732
  }
32548
- Object.assign(K, { newInteractiveState, MESSAGE_MS, createInteractiveMaterials, _EY, _UM3, hudMessage, definePiece, localOf, visibleChain, assembleInteractive, applyPiece, DURATION, animateInteractive, togglePiece, lightBase, lightOn, applyLight, toggleLight });
32733
+ const defined = { newInteractiveState, MESSAGE_MS, createInteractiveMaterials, _EY, _UM3, hudMessage, definePiece, localOf, visibleChain, assembleInteractive, applyPiece, DURATION, animateInteractive, togglePiece, lightBase, lightOn, applyLight, toggleLight };
32734
+ Object.assign(K, defined);
32549
32735
  }
32550
32736
  function installInteractionCollision(K, shared2) {
32737
+ const inter = () => shared2.inter;
32551
32738
  const NO_COLLIDE = /(^|_)(rug|floor|concrete|dirt|lawn|deck|ceiling_light|pendant|chandelier|spot|picture|curtain|blinds|wall_shelving|plank_shelf|wall_ac|ac_condenser|pool|soaking_tub|pergola|stairs|mirror)/;
32552
32739
  function registerCollision(m, M) {
32553
32740
  const h = m.h || 0, y = M.y || 0;
@@ -32557,7 +32744,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32557
32744
  w = Math.min(w, 0.5);
32558
32745
  d = Math.min(d, 0.5);
32559
32746
  }
32560
- shared2.inter.objs.push({ f: M.floor, cx: m.x, cz: m.z, c: Math.cos(M.ry), s: Math.sin(M.ry), hw: w / 2, hd: d / 2, type: m.type });
32747
+ inter().objs.push({ f: M.floor, cx: m.x, cz: m.z, c: Math.cos(M.ry), s: Math.sin(M.ry), hw: w / 2, hd: d / 2, type: m.type });
32561
32748
  }
32562
32749
  function objectDistance(o, x, z) {
32563
32750
  const dx = x - o.cx, dz = z - o.cz, lx = dx * o.c - dz * o.s, lz = dx * o.s + dz * o.c, ex = Math.abs(lx) - o.hw, ez = Math.abs(lz) - o.hd;
@@ -32565,7 +32752,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32565
32752
  }
32566
32753
  function collideObject(x, z, fx, fz, floor2) {
32567
32754
  const R = 0.2;
32568
- for (const o of shared2.inter.objs) {
32755
+ for (const o of inter().objs) {
32569
32756
  if (o.f !== -1 ? o.f !== floor2 : floor2 !== 0) continue;
32570
32757
  const d1 = objectDistance(o, x, z);
32571
32758
  if (d1 < R && d1 < objectDistance(o, fx, fz) - 1e-6) return true;
@@ -32585,13 +32772,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32585
32772
  const de = opt.from || [x + 1e4, z + 1e4];
32586
32773
  return collideObject(x, z, de[0], de[1], floor2);
32587
32774
  }
32588
- Object.assign(K, { NO_COLLIDE, registerCollision, objectDistance, collideObject, collideAt });
32775
+ const defined = { NO_COLLIDE, registerCollision, objectDistance, collideObject, collideAt };
32776
+ Object.assign(K, defined);
32589
32777
  }
32590
32778
  function installInteractionItems(K, shared2) {
32591
32779
  const { t, LIGHTS, cursor, definePiece, localOf, registerCollision, togglePiece } = K;
32592
32780
  const DOOR_ITEM = /^(tv_unit|tv_unit_small|tv_unit_large|sideboard|china_cabinet|filing_cabinet|pantry|laundry_cabinet|wardrobe|wardrobe_small|wardrobe_large|closet_wardrobe|kitchen_cabinet|kitchen_cabinet_large|kitchen_cabinet_small|fridge|fridge_large|display_fridge_medium|display_fridge)$/;
32593
32781
  const DRAWER_ITEM = /^(console_table|dresser|nightstand|vanity_table)$/;
32594
32782
  const LIGHT_TYPES = /* @__PURE__ */ new Set(["ceiling_light", "pendant", "chandelier", "track_spot", "hanging_plant"]);
32783
+ const I = () => shared2.inter;
32595
32784
  function objectName(type, drawer) {
32596
32785
  return drawer ? "drawer" : /^wardrobe/.test(type) ? "wardrobe" : /fridge|refrig|freezer/.test(type) ? "fridge" : /pantry/.test(type) ? "pantry" : "cabinet";
32597
32786
  }
@@ -32620,8 +32809,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32620
32809
  cursor.group = parent;
32621
32810
  }
32622
32811
  for (let i = n0; i < LIGHTS.length; i++) LIGHTS[i].roomId = m.room;
32623
- if (!shared2.inter.defs.has(name)) definePiece(name, { kind: "light", pivot: [0, 0, 0], ry: 0, parent, roomId: m.room });
32624
- shared2.inter.litRooms.add(m.room);
32812
+ if (!I().defs.has(name)) definePiece(name, { kind: "light", pivot: [0, 0, 0], ry: 0, parent, roomId: m.room });
32813
+ I().litRooms.add(m.room);
32625
32814
  }
32626
32815
  function curtainItem(m, M, ent, api, parent) {
32627
32816
  M.open = false;
@@ -32649,12 +32838,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32649
32838
  for (const c of body) api[c[0]](M, ...c[1]);
32650
32839
  if (!parts.length) return;
32651
32840
  const [ax, az] = localOf(M, 0, 0.2);
32652
- shared2.inter.items.push({ type: "curtain", id: m.id, floor: M.floor, anchor: [ax, M.base + (M.y || 0) + (m.h || 2) * 0.5, az], range: 2.4, angle: 1, pieces: parts, text: () => t(parts[0].target > 0.5 ? "prompt.close" : "prompt.open", { what: t("what.curtain") }), action: () => {
32653
- const al = parts[0].target > 0.5 ? 0 : 1;
32841
+ const first = parts[0];
32842
+ I().items.push({ type: "curtain", id: m.id, floor: M.floor, anchor: [ax, M.base + (M.y || 0) + (m.h || 2) * 0.5, az], range: 2.4, angle: 1, pieces: parts, text: () => t(first.target > 0.5 ? "prompt.close" : "prompt.open", { what: t("what.curtain") }), action: () => {
32843
+ const al = first.target > 0.5 ? 0 : 1;
32654
32844
  for (const p of parts) {
32655
32845
  p.target = al;
32656
32846
  shared2.partState.set(p.name, al);
32657
- shared2.inter.anim.add(p);
32847
+ I().anim.add(p);
32658
32848
  }
32659
32849
  } });
32660
32850
  }
@@ -32675,7 +32865,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32675
32865
  calls.forEach((c, i) => {
32676
32866
  if (owner.has(i)) return;
32677
32867
  const a = c[1];
32678
- let x0, x1, y0, y1, ok = false, grip = 0, wide2 = false;
32868
+ let x0 = 0, x1 = 0, y0 = 0, y1 = 0, ok = false, grip = 0, wide2 = false;
32679
32869
  if (c[0] === "box") {
32680
32870
  const [mat, x, y, z, w, h, d, , ry, rx, rz] = a;
32681
32871
  if (ry || rx || rz || d > 0.05 || z + d / 2 < front - 5e-3 || w > M.w * 1.01) return;
@@ -32707,8 +32897,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32707
32897
  return;
32708
32898
  }
32709
32899
  candidate.sort((p, q) => overlap(x0, x1, q.x0, q.x1) - overlap(x0, x1, p.x0, p.x1));
32710
- owner.set(i, candidate[0]);
32711
- if (grip) candidate[0].grip = grip;
32900
+ const best = candidate[0];
32901
+ owner.set(i, best);
32902
+ if (grip) best.grip = grip;
32712
32903
  });
32713
32904
  const name = objectName(m.type, drawer), parts = [];
32714
32905
  panels.forEach((p, k) => {
@@ -32724,8 +32915,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32724
32915
  p.def = def;
32725
32916
  parts.push(def);
32726
32917
  const [ax, az] = localOf(M, cx, front + 0.08);
32727
- shared2.inter.items.push({ type: drawer ? "drawer" : "cabinet", id: m.id, floor: M.floor, anchor: [ax, M.base + (M.y || 0) + (p.y0 + p.y1) / 2, az], range: 1.6, angle: 0.4, pieces: [def], text: () => t(def.target > 0.5 ? "prompt.close" : "prompt.open", { what: t("what." + name) }), action: () => togglePiece(def) });
32728
- def.item = shared2.inter.items[shared2.inter.items.length - 1];
32918
+ I().items.push({ type: drawer ? "drawer" : "cabinet", id: m.id, floor: M.floor, anchor: [ax, M.base + (M.y || 0) + (p.y0 + p.y1) / 2, az], range: 1.6, angle: 0.4, pieces: [def], text: () => t(def.target > 0.5 ? "prompt.close" : "prompt.open", { what: t("what." + name) }), action: () => togglePiece(def) });
32919
+ def.item = I().items[I().items.length - 1];
32729
32920
  });
32730
32921
  calls.forEach((c, i) => {
32731
32922
  const p = owner.get(i);
@@ -32739,12 +32930,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32739
32930
  }
32740
32931
  cursor.group = parent;
32741
32932
  }
32742
- Object.assign(K, { DOOR_ITEM, DRAWER_ITEM, LIGHT_TYPES, objectName, recordApi, buildItem: buildItem2, lightItem, curtainItem, furnitureItem });
32933
+ const defined = { DOOR_ITEM, DRAWER_ITEM, LIGHT_TYPES, objectName, recordApi, buildItem: buildItem2, lightItem, curtainItem, furnitureItem };
32934
+ Object.assign(K, defined);
32743
32935
  }
32744
32936
  function installInteractionFittings(K, shared2) {
32745
32937
  const { t, EPS: EPS6, OPEN_AREA, Y0, applyPiece, bx, cursor, definePiece, gates, lightOn, roomAt, slideDirection, toggleLight, togglePiece } = K;
32938
+ const I = () => shared2.inter;
32939
+ const house = () => shared2.ctx.r;
32746
32940
  function gatesInteractive() {
32747
- const lt2 = shared2.ctx.r.lot;
32941
+ const lt2 = house().lot;
32748
32942
  if (!lt2) return;
32749
32943
  const cz0 = (lt2.rect[1] + lt2.rect[3]) / 2;
32750
32944
  const orig = K.getBx(), gs = lt2.gates, opening = gs.map((g) => g.open), reg = gs.map((g) => {
@@ -32764,9 +32958,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32764
32958
  return;
32765
32959
  }
32766
32960
  }
32767
- return orig(mat, x0, y0, z0, x1, y1, z1, color2);
32961
+ orig(mat, x0, y0, z0, x1, y1, z1, color2);
32768
32962
  });
32769
- const n0 = shared2.ctx.colliders.length;
32963
+ const colliders = shared2.ctx.colliders, n0 = colliders.length;
32770
32964
  try {
32771
32965
  gs.forEach((g) => {
32772
32966
  g.open = false;
@@ -32778,7 +32972,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32778
32972
  g.open = opening[i];
32779
32973
  });
32780
32974
  }
32781
- const cols = shared2.ctx.colliders.slice(n0), cz = (lt2.rect[1] + lt2.rect[3]) / 2, cu = (lt2.rect[0] + lt2.rect[2]) / 2;
32975
+ const cols = colliders.slice(n0), cz = (lt2.rect[1] + lt2.rect[3]) / 2, cu = (lt2.rect[0] + lt2.rect[2]) / 2;
32782
32976
  reg.forEach((r, i) => {
32783
32977
  const g = r.g;
32784
32978
  if (!isFinite(r.x0)) return;
@@ -32787,25 +32981,25 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32787
32981
  const p = ped ? definePiece(name, Object.assign(base, { kind: "gate_swing", pivot: [r.x0, 0, g.v], angle: -sd * 1.65 })) : tilt ? definePiece(name, Object.assign(base, { kind: "gate_tilting", pivot: [(r.x0 + r.x1) / 2, r.y1, g.v], angle: -sd * 1.45 })) : definePiece(name, Object.assign(base, { kind: "gate_sliding", pivot: [r.x0, 0, r.zm], travel: r.dx * g.width }));
32788
32982
  if (p.col) p.col.off = p.target > 0.5;
32789
32983
  const text = () => t(p.target > 0.5 ? "prompt.close" : "prompt.open", { what: t(ped ? "what.pedestrianGate" : "what.garageGate") });
32790
- shared2.inter.items.push({ type: "gate", id: g.id, floor: -1, anchor: [g.u, 1, g.v + sd * 0.4], range: 2.8, angle: 0.9, pieces: [p], text, action: () => togglePiece(p), noWall: true });
32984
+ I().items.push({ type: "gate", id: g.id, floor: -1, anchor: [g.u, 1, g.v + sd * 0.4], range: 2.8, angle: 0.9, pieces: [p], text, action: () => togglePiece(p), noWall: true });
32791
32985
  });
32792
32986
  }
32793
32987
  function mailboxInteractive() {
32794
- for (const m of shared2.ctx.r.items) {
32988
+ for (const m of house().items) {
32795
32989
  if (m.type !== "mailbox") continue;
32796
32990
  const g = shared2.ctx.parts && shared2.ctx.parts["mailbox_" + m.id];
32797
32991
  if (!g) continue;
32798
32992
  const name = "ix:correio:" + m.id, def = definePiece(name, { kind: "part", pivot: [0, 0, 0], ry: 0, parent: "lot" });
32799
32993
  def.inner = g;
32800
32994
  const fx = Math.sin(m.ry || 0), fz = Math.cos(m.ry || 0), ay = (m.y || 1) + (m.h || 0.3) * 0.4;
32801
- shared2.inter.items.push({ type: "mailbox", id: m.id, floor: -1, anchor: [m.x + fx * 0.2, ay, m.z + fz * 0.2], range: 2.2, angle: 0.7, pieces: [def], text: () => t(def.target > 0.5 ? "prompt.close" : "prompt.open", { what: t("what.mailbox") }), action: () => togglePiece(def), noWall: true });
32995
+ I().items.push({ type: "mailbox", id: m.id, floor: -1, anchor: [m.x + fx * 0.2, ay, m.z + fz * 0.2], range: 2.2, angle: 0.7, pieces: [def], text: () => t(def.target > 0.5 ? "prompt.close" : "prompt.open", { what: t("what.mailbox") }), action: () => togglePiece(def), noWall: true });
32802
32996
  applyPiece(def);
32803
32997
  }
32804
32998
  }
32805
32999
  function placeSwitches() {
32806
- const R = shared2.ctx.r, used = /* @__PURE__ */ new Set();
33000
+ const R = house(), used = /* @__PURE__ */ new Set();
32807
33001
  for (const c of R.rooms) {
32808
- if (c.type === "void" || OPEN_AREA(c) || !shared2.inter.litRooms.has(c.id) || used.has(c.id) || shared2.ctx.iv && shared2.ctx.iv.switchRooms.has(c.id)) continue;
33002
+ if (c.type === "void" || OPEN_AREA(c) || !I().litRooms.has(c.id) || used.has(c.id) || shared2.ctx.iv && shared2.ctx.iv.switchRooms.has(c.id)) continue;
32809
33003
  const doors = R.doors.filter((p) => p.floor === c.floor && (p.a === c.id || p.b === c.id));
32810
33004
  doors.sort((p, q) => ((q.exterior ? 1 : 0) - (p.exterior ? 1 : 0)) * (c.type === "living" ? 1 : -1));
32811
33005
  for (const p of doors) if (putSwitch(c, p)) {
@@ -32815,11 +33009,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32815
33009
  }
32816
33010
  }
32817
33011
  function putSwitch(c, p) {
32818
- const R = shared2.ctx.r, f = p.floor, alongU = p.axis === "u", L = p.pos, a = p.at - p.width / 2, b = p.at + p.width / 2;
33012
+ const R = house(), f = p.floor, alongU = p.axis === "u", L = p.pos, a = p.at - p.width / 2, b = p.at + p.width / 2;
32819
33013
  const wref = R.walls.find((w) => w.floor === f && w.axis === p.axis && Math.abs((alongU ? w.v0 : w.u0) - L) < EPS6), th = wref ? wref.thickness || 0.15 : 0.15;
32820
33014
  const inside2 = (sd2) => {
32821
33015
  const cc = roomAt(f, alongU ? p.at : L + sd2 * 0.4, alongU ? L + sd2 * 0.4 : p.at);
32822
- return cc && cc.id === c.id;
33016
+ return !!cc && cc.id === c.id;
32823
33017
  };
32824
33018
  const sd = inside2(1) ? 1 : inside2(-1) ? -1 : 0;
32825
33019
  if (!sd) return false;
@@ -32842,17 +33036,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32842
33036
  const piece2 = definePiece("ix:int:" + roomId, { kind: "light_switch", pivot: pv, ry: 0, parent: "f" + f, axis: alongU ? "x" : "z", sgn: alongU ? sd : -sd, t0: lightOn(roomId) ? 1 : 0 });
32843
33037
  piece2.t = piece2.target = lightOn(roomId) ? 1 : 0;
32844
33038
  const an = alongU ? [u, yc, face + sd * 0.12] : [face + sd * 0.12, yc, u];
32845
- shared2.inter.items.push({ type: "light_switch", id: roomId, floor: f, anchor: an, range: 1.5, angle: 0.45, pieces: [piece2], text: () => t(lightOn(roomId) ? "prompt.lightOff" : "prompt.lightOn"), action: () => toggleLight(roomId) });
33039
+ I().items.push({ type: "light_switch", id: roomId, floor: f, anchor: an, range: 1.5, angle: 0.45, pieces: [piece2], text: () => t(lightOn(roomId) ? "prompt.lightOff" : "prompt.lightOn"), action: () => toggleLight(roomId) });
32846
33040
  return true;
32847
33041
  }
32848
33042
  return false;
32849
33043
  }
32850
- Object.assign(K, { gatesInteractive, mailboxInteractive, placeSwitches, putSwitch });
33044
+ const defined = { gatesInteractive, mailboxInteractive, placeSwitches, putSwitch };
33045
+ Object.assign(K, defined);
32851
33046
  }
32852
33047
  function installInteractionDoors(K, shared2) {
32853
33048
  const { t, colliderChanged, invalidateShadow, applyPiece, hudMessage } = K;
33049
+ const leaves = () => shared2.ctx.leaves;
32854
33050
  function linkDoorLeaves() {
32855
- for (const fo of shared2.ctx.leaves) fo.handles = (fo.handleNames || []).map((n) => shared2.inter.defs.get(n)).filter(Boolean);
33051
+ const I = shared2.inter;
33052
+ for (const fo of leaves()) fo.handles = (fo.handleNames || []).map((n) => I.defs.get(n)).filter((d) => !!d);
32856
33053
  }
32857
33054
  function handleApply(fo) {
32858
33055
  for (const mc of fo.handles || []) {
@@ -32862,11 +33059,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32862
33059
  }
32863
33060
  function toggleDoor(fo) {
32864
33061
  if (fo.phase === "rattle") return;
33062
+ const col = fo.col;
32865
33063
  if (fo.phase === "handle" || fo.phase === "swing") {
32866
33064
  fo.open = !fo.open;
32867
33065
  shared2.doorState.set(fo.id, fo.open);
32868
- fo.col.off = fo.open;
32869
- colliderChanged(fo.col);
33066
+ col.off = fo.open;
33067
+ colliderChanged(col);
32870
33068
  fo.anim = true;
32871
33069
  fo.phase = "swing";
32872
33070
  return;
@@ -32880,8 +33078,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32880
33078
  }
32881
33079
  fo.open = !fo.open;
32882
33080
  shared2.doorState.set(fo.id, fo.open);
32883
- fo.col.off = fo.open;
32884
- colliderChanged(fo.col);
33081
+ col.off = fo.open;
33082
+ colliderChanged(col);
32885
33083
  fo.anim = true;
32886
33084
  shared2.ctx.animateDoorsOn = true;
32887
33085
  if (fo.handles && fo.handles.length) {
@@ -32892,7 +33090,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32892
33090
  function animateDoors(dt) {
32893
33091
  if (!shared2.ctx.animateDoorsOn) return;
32894
33092
  let active = false;
32895
- for (const fo of shared2.ctx.leaves) {
33093
+ for (const fo of leaves()) {
32896
33094
  if (!fo.phase) continue;
32897
33095
  active = true;
32898
33096
  if (fo.phase === "handle") {
@@ -32912,7 +33110,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32912
33110
  handleApply(fo);
32913
33111
  if (fo.hT <= 0) fo.phase = null;
32914
33112
  } else if (fo.phase === "rattle") {
32915
- fo.jig -= dt;
33113
+ fo.jig = (fo.jig ?? 0) - dt;
32916
33114
  fo.hT = fo.jig > 0 ? 0.55 * Math.abs(Math.sin(fo.jig * 26)) : 0;
32917
33115
  handleApply(fo);
32918
33116
  if (fo.jig <= 0) {
@@ -32926,9 +33124,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32926
33124
  invalidateShadow();
32927
33125
  }
32928
33126
  function wallBlocks(ex, ez, ax, az, floor2) {
32929
- const n = shared2.ctx.wallColliders != null ? shared2.ctx.wallColliders : 0;
33127
+ const n = shared2.ctx.wallColliders != null ? shared2.ctx.wallColliders : 0, colliders = shared2.ctx.colliders;
32930
33128
  for (let i = 0; i < n; i++) {
32931
- const c = shared2.ctx.colliders[i];
33129
+ const c = colliders[i];
32932
33130
  if (c.f !== floor2 && !(c.f === -1 && floor2 === 0)) continue;
32933
33131
  let t0 = 0, t1 = 1;
32934
33132
  const dx = ax - ex, dz = az - ez;
@@ -32958,7 +33156,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32958
33156
  g.updateMatrix();
32959
33157
  }
32960
33158
  }
32961
- Object.assign(K, { linkDoorLeaves, handleApply, toggleDoor, animateDoors, wallBlocks, doorText, applyLeaf });
33159
+ const defined = { linkDoorLeaves, handleApply, toggleDoor, animateDoors, wallBlocks, doorText, applyLeaf };
33160
+ Object.assign(K, defined);
32962
33161
  }
32963
33162
  function installInteractionTarget(K, shared2) {
32964
33163
  const { doorText, toggleDoor, visibleChain, wallBlocks } = K;
@@ -32966,6 +33165,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32966
33165
  function targetOf(o, opt) {
32967
33166
  if (!o) return null;
32968
33167
  opt = opt || {};
33168
+ const I = shared2.inter;
32969
33169
  const ex = o.x, ey = o.y, ez = o.z, floor2 = o.floor, cp = Math.cos(o.pitch || 0), vx2 = Math.sin(o.yaw) * cp, vy2 = Math.sin(o.pitch || 0), vz2 = Math.cos(o.yaw) * cp;
32970
33170
  let best = null;
32971
33171
  const tries = (score, text, action, target) => {
@@ -32979,16 +33179,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32979
33179
  if (angle > 1.35 && d > 0.9) continue;
32980
33180
  tries(angle * 1.6 + d * 0.5 + (angle < 0.25 ? 0 : 0.6), doorText(fo), () => toggleDoor(fo), fo);
32981
33181
  }
32982
- const vis = shared2.inter.pieces.flatMap((p) => p.meshes).filter(visibleChain), hit = vis.length && opt.strike ? opt.strike(vis) : null;
33182
+ const vis = I.pieces.flatMap((p) => p.meshes).filter(visibleChain), hit = vis.length && opt.strike ? opt.strike(vis) : null;
32983
33183
  const kitA = shared2.ctx.iv ? ivTarget(shared2.ctx.iv, o, opt && opt.interactives) : null;
32984
33184
  const nearKit = kitA && hit && Math.hypot(kitA.target.pos[0] - ex, kitA.target.pos[1] - ey, kitA.target.pos[2] - ez) < hit.distance + 0.1;
32985
33185
  const pieceHit = hit && !nearKit && hit.object.userData.piece;
32986
- for (const it of shared2.inter.items) {
33186
+ for (const it of I.items) {
32987
33187
  if (it.floor !== floor2 && !(it.floor === -1 && floor2 === 0)) continue;
32988
33188
  const [ax, ay, az] = it.anchor, dx = ax - ex, dy = ay - ey, dz = az - ez, d = Math.hypot(dx, dy, dz), dh = Math.hypot(dx, dz);
32989
33189
  if (dh > it.range + 0.4) continue;
32990
33190
  const angle = Math.acos(Math.max(-1, Math.min(1, (dx * vx2 + dy * vy2 + dz * vz2) / (d || 1))));
32991
- const byRay = pieceHit && it.pieces.includes(pieceHit) && hit.distance <= it.range + 0.5;
33191
+ const byRay = !!hit && pieceHit && it.pieces.includes(pieceHit) && hit.distance <= it.range + 0.5;
32992
33192
  if (!byRay && !(dh <= it.range && angle <= it.angle)) continue;
32993
33193
  if (!it.noWall && wallBlocks(ex, ez, ax, az, it.floor < 0 ? 0 : it.floor)) continue;
32994
33194
  tries((byRay ? 0 : angle * 2) + d * 0.3 - (byRay ? 1.5 : 0), it.text(), it.action, it);
@@ -32996,7 +33196,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
32996
33196
  if (kitA) tries(kitA.score - (nearKit ? 0.5 : 0), kitA.text, kitA.action, kitA.target);
32997
33197
  return best;
32998
33198
  }
32999
- Object.assign(K, { targetOf });
33199
+ const defined = { targetOf };
33200
+ Object.assign(K, defined);
33000
33201
  }
33001
33202
  function installInteractablesBridge(K, shared2) {
33002
33203
  const { t, THREE, invalidate, invalidateShadow, cfg, DOC, LIGHT_TYPES, _Y, _q, _v3, accFor, applyLight, cursor, hashString, hudMessage, lightBase, pieceRecord, put, rgbOf, sh, wallBlocks } = K;
@@ -33051,7 +33252,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33051
33252
  function ivBuild(h, water) {
33052
33253
  const ik = K.IVK, r = shared2.ctx.r, A = ik.A, world0 = null;
33053
33254
  void world0;
33054
- const plane2 = A.plan(r, { seed: r.seed });
33255
+ const source = r;
33256
+ const plane2 = A.plan(source, { seed: r.seed });
33055
33257
  const IV = { k: ik, plane: plane2, world: null, water, entries: /* @__PURE__ */ new Map(), roots: [], replace: /* @__PURE__ */ new Set(), roomStates: /* @__PURE__ */ new Map(), lampRoom: /* @__PURE__ */ new Map(), anim: /* @__PURE__ */ new Map(), screens: /* @__PURE__ */ new Map(), efx: null, items: null, itemsDirty: true, itemsT: 0, dirty: true, list: null, listT: 0, t: 0, circuits: [], switchRooms: /* @__PURE__ */ new Set(), warnings: [], tBuild: 0 };
33056
33258
  h.IV = IV;
33057
33259
  const t0 = performance.now();
@@ -33070,9 +33272,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33070
33272
  const wants = (roomId) => lightBase(roomId);
33071
33273
  const entById = new Map(plane2.items.map((e) => [e.id, e]));
33072
33274
  const entByItem = new Map(plane2.items.map((e) => [e.item, e]));
33073
- IV.mats = { plain: shared2.mats.plain, metal: shared2.mats.metal, wood: shared2.mats.wood, glass: shared2.mats.glass, fabric: shared2.mats.fabric, plant: shared2.mats.plant, water: shared2.mats.water, emissive: shared2.mats.emissive, atlas_picture: shared2.mats.picture, atlas_floor: shared2.mats.floor };
33275
+ const mats = shared2.mats;
33276
+ IV.mats = { plain: mats.plain, metal: shared2.mats.metal, wood: shared2.mats.wood, glass: shared2.mats.glass, fabric: shared2.mats.fabric, plant: shared2.mats.plant, water: shared2.mats.water, emissive: shared2.mats.emissive, atlas_picture: shared2.mats.picture, atlas_floor: shared2.mats.floor };
33074
33277
  const ev = (e) => ivEvent(h, e);
33075
- const world = IV.world = A.createWorld(r, { water, seed: r.seed, onEvent: ev });
33278
+ const world = IV.world = A.createWorld(source, { water, seed: r.seed, onEvent: ev });
33076
33279
  const add0 = world.add;
33077
33280
  world.add = (id, spec, tr) => {
33078
33281
  const e = entById.get(id);
@@ -33089,7 +33292,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33089
33292
  }
33090
33293
  return add0(id, spec, tr);
33091
33294
  };
33092
- const added = A.add(world, plane2, { isBlocked: A.blockedOf(r), build: (type, item) => ivDraw(IV, entByItem.get(item), type, item) });
33295
+ const added = A.add(world, plane2, { isBlocked: A.blockedOf(source), build: (type, item) => ivDraw(IV, entByItem.get(item), type, item) });
33093
33296
  world.add = add0;
33094
33297
  IV.warnings = added.warnings;
33095
33298
  IV.added = added;
@@ -33136,14 +33339,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33136
33339
  }
33137
33340
  function ivDraw(IV, ent, type, item) {
33138
33341
  const ik = IV.k, loc = Object.assign({}, item, { x: 0, z: 0, ry: 0 });
33342
+ const ix = item.x, iz = item.z, iry = item.ry;
33139
33343
  const mesh3 = ik.gfx.createMeshApi({ quality: "game", materials: IV.mats, shadows: true, mergeParts: true, swayAmplitude: 0.03 });
33140
33344
  const spec = ik.A.household.build(type, loc, mesh3.api);
33141
33345
  const out = mesh3.finish(spec);
33142
33346
  for (const l of out.lights) l.removeFromParent();
33143
33347
  const group = ivGroup(ent), g0 = cursor.group, root = new THREE.Group();
33144
33348
  root.name = "iv:" + ent.id;
33145
- root.position.set(item.x, ent.floorY, item.z);
33146
- root.rotation.y = item.ry;
33349
+ root.position.set(ix, ent.floorY, iz);
33350
+ root.rotation.y = iry;
33147
33351
  root.userData.iv = ent.id;
33148
33352
  const screen2 = spec.devices && spec.devices.some((d) => d.kind === "screen");
33149
33353
  let body = null;
@@ -33152,7 +33356,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33152
33356
  if (type === "gas_bottle") {
33153
33357
  cursor.pc = pieceRecord("gas_cylinder:" + ent.id, "steel", null, { floor: ent.floor, mass: 11, form: "cyl", thickness: 3e-3, fill: 0.03, contains: { fluid: "gas", liters: 13, pressurized: true }, explodes: { energy: 12e4, radius: 5, atC: 300 }, tags: ["gas_bottle"] });
33154
33358
  for (const m of out.group.children) if (!m.name.startsWith("static:")) m.traverse((o) => {
33155
- if (o.isMesh) {
33359
+ if (isMesh(o)) {
33156
33360
  o.userData.destructionPart = cursor.pc.id;
33157
33361
  o.userData.destructionMaterial = "steel";
33158
33362
  }
@@ -33160,13 +33364,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33160
33364
  }
33161
33365
  try {
33162
33366
  for (const m of out.group.children.slice()) {
33163
- if (m.isMesh && m.name.startsWith("static:")) {
33367
+ if (isMesh(m) && m.name.startsWith("static:")) {
33164
33368
  if (screen2 && m.userData.material === "emissive") {
33165
33369
  body = m;
33166
33370
  root.add(m);
33167
33371
  continue;
33168
33372
  }
33169
- ivAccumulate(IV_MATERIAL[m.userData.material] || "plain", m.geometry, item.x, ent.floorY, item.z, item.ry, null);
33373
+ ivAccumulate(IV_MATERIAL[m.userData.material] || "plain", m.geometry, ix, ent.floorY, iz, iry, null);
33170
33374
  m.geometry.dispose();
33171
33375
  } else root.add(m);
33172
33376
  }
@@ -33176,7 +33380,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33176
33380
  }
33177
33381
  const base = new Set(Object.values(IV.mats));
33178
33382
  root.traverse((o) => {
33179
- if (!o.isMesh) return;
33383
+ if (!isMesh(o)) return;
33180
33384
  o.userData.iv = ent.id;
33181
33385
  if (o.castShadow) {
33182
33386
  if (!o.geometry.boundingSphere) o.geometry.computeBoundingSphere();
@@ -33187,7 +33391,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33187
33391
  roomLightMask(m);
33188
33392
  }
33189
33393
  });
33190
- const E = { id: ent.id, type, entry: ent, floor: ent.floor, group, root, parts: out.parts, spec, screen: body, pos: [item.x, ent.floorY, item.z], ry: item.ry, origin: ent.origin };
33394
+ const E = { id: ent.id, type, entry: ent, floor: ent.floor, group, root, parts: out.parts, spec, screen: body, pos: [ix, ent.floorY, iz], ry: iry, origin: ent.origin };
33191
33395
  IV.entries.set(ent.id, E);
33192
33396
  if (root.children.length) IV.roots.push(E);
33193
33397
  return spec;
@@ -33215,7 +33419,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33215
33419
  const wire = (spec.wires || []).find((x) => x.id === d.id + "_cord"), pts = (wire ? wire.points : [d.plug]).map((p) => wl(o, p));
33216
33420
  const sid = w.power.pluggedInto(E.id, d.id);
33217
33421
  if (sid) {
33218
- const cut = sid.indexOf(":"), so = w.get(sid.slice(0, cut)), sk = so && so.spec.sockets.find((s) => s.id === sid.slice(cut + 1));
33422
+ const cut = sid.indexOf(":"), so = w.get(sid.slice(0, cut)), sk = so && (so.spec.sockets || []).find((s) => s.id === sid.slice(cut + 1));
33219
33423
  if (so && sk) {
33220
33424
  const sp = wl(so, sk.pos), dir = [Math.sin(so.transform.ry), Math.cos(so.transform.ry)], last = pts[pts.length - 1];
33221
33425
  if (last[1] < 0.3 + E.pos[1]) {
@@ -33250,9 +33454,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33250
33454
  roomLightMask(sc.material);
33251
33455
  IV.screens.set(E.id, sc);
33252
33456
  }
33253
- E.screen.material = sc.material;
33254
- E.screen.castShadow = false;
33255
- E.screen.receiveShadow = false;
33457
+ const mesh3 = E.screen;
33458
+ mesh3.material = sc.material;
33459
+ mesh3.castShadow = false;
33460
+ mesh3.receiveShadow = false;
33256
33461
  }
33257
33462
  function ivEvent(h, e) {
33258
33463
  const IV = h.IV;
@@ -33288,16 +33493,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33288
33493
  IV.itemsDirty = true;
33289
33494
  break;
33290
33495
  }
33291
- if (K.IVK.onEvent) {
33496
+ const ik = K.IVK;
33497
+ if (ik.onEvent) {
33292
33498
  try {
33293
- K.IVK.onEvent(e, h.IV.pub);
33499
+ ik.onEvent(e, IV.pub);
33294
33500
  } catch (err) {
33295
33501
  console.warn("interactables.onEvent", err);
33296
33502
  }
33297
33503
  }
33298
- if (e.type === "seat" && K.IVK.onSeat && e.actor === "player") {
33504
+ if (e.type === "seat" && ik.onSeat && e.actor === "player") {
33299
33505
  try {
33300
- K.IVK.onSeat(e.seated ? ivSeat(IV) : null, e);
33506
+ ik.onSeat(e.seated ? ivSeat(IV) : null, e);
33301
33507
  } catch (err) {
33302
33508
  console.warn("interactables.onSeat", err);
33303
33509
  }
@@ -33306,7 +33512,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33306
33512
  function ivSeat(IV) {
33307
33513
  const w = IV.world, s = w.seatOf("player");
33308
33514
  if (!s) return null;
33309
- const o = w.get(s.object), seat2 = o.spec.seats.find((q) => q.id === s.seat), L = IV.k.GI.localToWorld, tr = o.transform, E = IV.entries.get(s.object);
33515
+ const o = w.get(s.object), seat2 = (o.spec.seats || []).find((q) => q.id === s.seat), L = IV.k.GI.localToWorld, tr = o.transform, E = IV.entries.get(s.object);
33310
33516
  const eye = L(tr, [seat2.pos[0], seat2.pos[1] + (seat2.eye === void 0 ? seat2.pose === "lie" ? 0.18 : 0.62 : seat2.eye), seat2.pos[2]]);
33311
33517
  return { object: s.object, seatInfo: s.seat, pose: seat2.pose, eye, yaw: tr.ry + seat2.ry, pitch: seat2.pose === "lie" ? 0.55 : -0.08, exitPoint: L(tr, seat2.exit), floor: E ? E.floor : 0, type: E ? E.type : null };
33312
33518
  }
@@ -33348,18 +33554,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33348
33554
  }
33349
33555
  }
33350
33556
  const em = w.emitters();
33351
- if (em.length && !IV.efx && K.IVK.effects) {
33557
+ const ivk = K.IVK;
33558
+ if (em.length && !IV.efx && ivk.effects) {
33352
33559
  const g = h.houseGroup;
33353
- IV.efx = ik.gfx.createEffects(g, { maxParticles: 1400, seed: 11, document: DOC, ...K.IVK.effectSink ? { effects: K.IVK.effectSink } : {} });
33560
+ IV.efx = ik.gfx.createEffects(g, { maxParticles: 1400, seed: 11, document: DOC, ...ivk.effectSink ? { effects: ivk.effectSink } : {} });
33354
33561
  }
33355
33562
  if (IV.efx) {
33356
33563
  const alive = IV.efx.stats().alive;
33357
33564
  if (em.length || alive) {
33358
- IV.efx.update(dt, em, K.IVK.camera ? typeof K.IVK.camera === "function" ? K.IVK.camera() : K.IVK.camera : void 0);
33565
+ IV.efx.update(dt, em, ivk.camera ? typeof ivk.camera === "function" ? ivk.camera() : ivk.camera : void 0);
33359
33566
  invalidate();
33360
33567
  }
33361
33568
  }
33362
- if (K.IVK.items && IV.itemsDirty && IV.t - IV.itemsT > 0.1 && !IV.anim.size) ivItems(IV, h);
33569
+ if (ivk.items && IV.itemsDirty && IV.t - IV.itemsT > 0.1 && !IV.anim.size) ivItems(IV, h);
33363
33570
  }
33364
33571
  const IV_SHAPE = {
33365
33572
  can: [["cyl", 1, 1, 1, 0, 1]],
@@ -33394,7 +33601,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33394
33601
  if (c.access && w.partT(E.id, c.access) < 0.02) continue;
33395
33602
  const st = w.contents(E.id, c.id);
33396
33603
  for (let i = 0; i < st.length; i++) {
33397
- if (st[i] && items[st[i].type]) list2.push([E, c.id, i, items[st[i].type]]);
33604
+ const stack = st[i];
33605
+ if (stack && items[stack.type]) list2.push([E, c.id, i, items[stack.type]]);
33398
33606
  }
33399
33607
  }
33400
33608
  }
@@ -33423,12 +33631,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33423
33631
  gm.setIndex(new THREE.BufferAttribute(A.i.slice(0, A.ni), 1));
33424
33632
  gm.computeBoundingSphere();
33425
33633
  if (!IV.items) {
33426
- IV.items = new THREE.Mesh(gm, shared2.mats.plain);
33427
- IV.items.name = "iv-items";
33428
- IV.items.castShadow = false;
33429
- IV.items.receiveShadow = true;
33430
- IV.items.frustumCulled = false;
33431
- h.houseGroup.add(IV.items);
33634
+ const mesh3 = new THREE.Mesh(gm, shared2.mats.plain);
33635
+ IV.items = mesh3;
33636
+ mesh3.name = "iv-items";
33637
+ mesh3.castShadow = false;
33638
+ mesh3.receiveShadow = true;
33639
+ mesh3.frustumCulled = false;
33640
+ h.houseGroup.add(mesh3);
33432
33641
  } else {
33433
33642
  IV.items.geometry.dispose();
33434
33643
  IV.items.geometry = gm;
@@ -33562,7 +33771,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33562
33771
  };
33563
33772
  return IV.pub;
33564
33773
  }
33565
- Object.assign(K, { IV_MATERIAL, IV_WIRE, IV_DOOR, ivGroup, ivAccumulate, ivBuild, ivRoomEffective, ivDraw, ivCords, ivAssemble, ivScreen, ivEvent, ivSeat, ivUpdate, IV_SHAPE, ivItems, ivTarget, ivRoomLight, ivParts, ivDispose, ivPublish });
33774
+ const defined = { IV_MATERIAL, IV_WIRE, IV_DOOR, ivGroup, ivAccumulate, ivBuild, ivRoomEffective, ivDraw, ivCords, ivAssemble, ivScreen, ivEvent, ivSeat, ivUpdate, IV_SHAPE, ivItems, ivTarget, ivRoomLight, ivParts, ivDispose, ivPublish };
33775
+ Object.assign(K, defined);
33566
33776
  }
33567
33777
  function installAnimationClotheslines(K, shared2) {
33568
33778
  const { invalidate, CLOTHES_UNIFORMS } = K;
@@ -33585,7 +33795,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33585
33795
  }
33586
33796
  invalidate();
33587
33797
  }
33588
- Object.assign(K, { WIND, animateClotheslines });
33798
+ const defined = { WIND, animateClotheslines };
33799
+ Object.assign(K, defined);
33589
33800
  }
33590
33801
  function installBuildInstance(K, shared2) {
33591
33802
  const { PROPS, THREE, DOC, cfg, HP, createInteractiveMaterials, createMaterials: createMaterials2, typeTable } = K;
@@ -33608,7 +33819,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33608
33819
  shared2.quality = h.quality;
33609
33820
  }
33610
33821
  const tagDamage = (type) => ({ type, hp: HP[type], hpMax: HP[type] });
33611
- Object.assign(K, { props, TYPES, newState, enter, tagDamage });
33822
+ const defined = { props, TYPES, newState, enter, tagDamage };
33823
+ Object.assign(K, defined);
33612
33824
  }
33613
33825
  function installInteractablesKit(K, shared2) {
33614
33826
  const { t, THREE, DOC, cfg, Reflector } = K;
@@ -33634,15 +33846,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33634
33846
  for (const k of ["wood", "foliage", "flowers", "fruit", "spines"]) roomLightMask(m[k]);
33635
33847
  return m;
33636
33848
  })());
33637
- Object.assign(K, { IVK, VEG, vegMaterials });
33849
+ const defined = { IVK, VEG, vegMaterials };
33850
+ Object.assign(K, defined);
33638
33851
  }
33852
+ var newGroup = (k, house, exterior) => ({ k, house, ls: [], exterior, pos: [0, 0, 0], color: 0, n: 0, range: 0, rects: [], y: [0, 0], exclusion: null, lumens: 0, dist: 0, decay: 0, floor: 0, roomId: null, dm: 0, d: 0 });
33639
33853
  function installLightsRoomLight(K, shared2) {
33640
33854
  const { THREE, rectsOf: rectsOf2, cfg } = K;
33641
33855
  const MAX_LIGHTS = 12, EMPTY = [1e9, 1e9, -1e9, -1e9];
33642
33856
  const LZU = { uRB0: { value: new Float32Array(MAX_LIGHTS * 4) }, uRB1: { value: new Float32Array(MAX_LIGHTS * 4) }, uRB2: { value: new Float32Array(MAX_LIGHTS * 4) }, uRBY: { value: new Float32Array(MAX_LIGHTS * 2) }, uREx: { value: new Float32Array(MAX_LIGHTS * 4) }, uIndK: { value: 0.06 } };
33643
33857
  for (let i = 0; i < MAX_LIGHTS; i++) for (const k of ["uRB0", "uRB1", "uRB2", "uREx"]) LZU[k].value.set(EMPTY, i * 4);
33644
- function roomLightMask(m) {
33645
- if (!m || m.userData && m.userData.roomLightMask || !(m.isMeshLambertMaterial || m.isMeshPhongMaterial || m.isMeshStandardMaterial || m.isMeshPhysicalMaterial)) return m;
33858
+ function roomLightMask(material) {
33859
+ const m = material;
33860
+ if (!m || m.userData && m.userData.roomLightMask || !(m.isMeshLambertMaterial || m.isMeshPhongMaterial || m.isMeshStandardMaterial || m.isMeshPhysicalMaterial)) return material;
33646
33861
  m.userData = m.userData || {};
33647
33862
  m.userData.roomLightMask = true;
33648
33863
  const prev = m.onBeforeCompile, pk = m.customProgramCacheKey;
@@ -33670,12 +33885,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33670
33885
  return (pk ? pk.call(this) : "") + "|rm1";
33671
33886
  };
33672
33887
  m.needsUpdate = true;
33673
- return m;
33888
+ return material;
33674
33889
  }
33675
- function lighting(o) {
33676
- o = o || {};
33890
+ function lighting(options) {
33891
+ const o = options || {};
33677
33892
  const scene = o.scene, N = Math.max(1, Math.min(MAX_LIGHTS, o.n || 6)), NS = Math.max(0, Math.min(N, o.shadows != null ? o.shadows : 2)), size = o.shadowSize || 512, MAX_EXTERNAL = o.external != null ? o.external : 2;
33678
- for (const k of Object.keys(shared2.mats)) roomLightMask(shared2.mats[k]);
33893
+ const mats = shared2.mats;
33894
+ for (const k of Object.keys(mats)) roomLightMask(mats[k]);
33679
33895
  const budget = o.budget, lease = budget ? budget.lease({ owner: "floorplan.rooms", point: N, shadows: NS }) : null;
33680
33896
  if (budget && !lease) throw new Error("lighting: the LightBudget has no " + N + " free point slots (" + NS + " with shadow) for the rooms");
33681
33897
  if (budget) for (const [key2, width] of [["uRB0", 4], ["uRB1", 4], ["uRB2", 4], ["uRBY", 2], ["uREx", 4]]) {
@@ -33726,9 +33942,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33726
33942
  }
33727
33943
  for (let i = 0; i < NS; i++) PL[i].shadow.needsUpdate = true;
33728
33944
  };
33729
- A.update = function(houses, focus, op) {
33730
- op = op || {};
33731
- houses = (Array.isArray(houses) ? houses : [houses]).filter(Boolean);
33945
+ A.update = function(houseOrList, focus, options2) {
33946
+ const op = options2 || {}, houses = (Array.isArray(houseOrList) ? houseOrList : [houseOrList]).filter((h) => !!h);
33732
33947
  _f.set(focus.x, focus.y, focus.z);
33733
33948
  const rooms = [], exterior = [];
33734
33949
  for (const house of houses) {
@@ -33740,7 +33955,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33740
33955
  if (!house.lightOn(l.roomId)) continue;
33741
33956
  const k = l.type === "outdoor" ? "ext:" + (l.id || exterior.length) : l.roomId != null ? l.roomId : l.room;
33742
33957
  let g = by.get(k);
33743
- if (!g) by.set(k, g = { k, house, ls: [], exterior: l.type === "outdoor" });
33958
+ if (!g) by.set(k, g = newGroup(k, house, l.type === "outdoor"));
33744
33959
  g.ls.push(l);
33745
33960
  }
33746
33961
  for (const g of by.values()) {
@@ -33775,9 +33990,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33775
33990
  }
33776
33991
  }
33777
33992
  g.exclusion = [x0 + 0.03, z0 + 0.03, x1 - 0.03, z1 - 0.03];
33778
- g.lumens = ls[0].lumens != null ? ls[0].lumens : 3.2;
33779
- g.dist = ls[0].dist != null ? ls[0].dist : 5.5;
33780
- g.decay = ls[0].decay != null ? ls[0].decay : 2;
33993
+ const l0 = ls[0];
33994
+ g.lumens = l0.lumens != null ? l0.lumens : 3.2;
33995
+ g.dist = l0.dist != null ? l0.dist : 5.5;
33996
+ g.decay = l0.decay != null ? l0.decay : 2;
33781
33997
  } else {
33782
33998
  const c = house.r.rooms.find((q) => q.id === g.k);
33783
33999
  if (!c) continue;
@@ -33878,8 +34094,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33878
34094
  }
33879
34095
  const effectsByBudget = /* @__PURE__ */ new WeakMap();
33880
34096
  const OPENING_REACH = 2.5, OPENING_SIDE = 0.6;
33881
- function effectLights(o) {
33882
- o = o || {};
34097
+ function effectLights(options) {
34098
+ const o = options || {};
33883
34099
  const budget = o.budget;
33884
34100
  if (!budget) throw new Error("effectLights: a LightBudget is required");
33885
34101
  const known = effectsByBudget.get(budget);
@@ -33957,7 +34173,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33957
34173
  const A = {
33958
34174
  /** Once per frame, after the budget's `present`: points the mask of every lit slot that is not the house's at the rooms its light reaches. */
33959
34175
  update(houses) {
33960
- const indoors = cfg.effectLightsIndoors !== false, list2 = (Array.isArray(houses) ? houses : [houses]).filter(Boolean), cache2 = /* @__PURE__ */ new Map();
34176
+ const indoors = cfg.effectLightsIndoors !== false, list2 = (Array.isArray(houses) ? houses : [houses]).filter((h) => !!h), cache2 = /* @__PURE__ */ new Map();
33961
34177
  for (let at3 = 0; at3 < size; at3++) {
33962
34178
  if (ours.has(at3)) continue;
33963
34179
  const light = budget.group.children[at3];
@@ -33985,7 +34201,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
33985
34201
  if (!o.ours) effectsByBudget.set(budget, A);
33986
34202
  return A;
33987
34203
  }
33988
- Object.assign(K, { MAX_LIGHTS, EMPTY, LZU, roomLightMask, lighting, effectLights });
34204
+ const defined = { MAX_LIGHTS, EMPTY, LZU, roomLightMask, lighting, effectLights };
34205
+ Object.assign(K, defined);
33989
34206
  }
33990
34207
  var NONE = { panels: [], replaced: [], supports: [] };
33991
34208
  var MEMO = /* @__PURE__ */ new WeakMap();
@@ -35162,8 +35379,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
35162
35379
  }
35163
35380
  function installBuildBuild(K, shared2) {
35164
35381
  const { THREE, cfg, rectsOf: rectsOf2, invalidateShadow, colliderChanged, VERSION: VERSION2, CARS, EPS: EPS6, LIGHTS, MIRRORS, Y0, animateClotheslines, animateDoors, animateInteractive, applyLeaf, applyOutbuildings, applyPart, applyPiece, assembleInteractive, baseboardAndSidewalk, buildStairs, building, carModel, chooseMirror, closeScene, collideAt, createWater, cursor, doorText, doors, electricalStructure, elevator, floorsAndSlabs, gatesInteractive, houseItems, ivAssemble, ivBuild, ivDispose, ivParts, ivPublish, ivUpdate, lightOn, linkDoorLeaves, mailboxInteractive, newInteractiveState, newMirrorState, outbuildings, paths, perimeter, placeSwitches, roofs, roomAt, solar, targetOf, terrain, toggleDoor, toggleLight, walls, waterPipes, windows, props, TYPES, IVK, VEG, vegMaterials, markGroups, assembleStructure, createHouseDestruction, newState, enter, tagDamage } = K;
35165
- function build(r0, opts) {
35166
- opts = opts || {};
35382
+ function build(r0, options) {
35383
+ const opts = options || {};
35167
35384
  const r = applyOutbuildings(r0);
35168
35385
  const t0 = performance.now();
35169
35386
  const h = { ctx: { mv: props, types: TYPES }, inter: newInteractiveState(), state: opts.state || newState(), mirrors: newMirrorState(), quality: opts.quality === "game" || opts.quality === "high" ? opts.quality : cfg.quality === "game" ? "game" : "high", lodCurrent: 0, lodMin: 0 };
@@ -35184,7 +35401,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
35184
35401
  shared2.ctx.pieces = /* @__PURE__ */ new Map();
35185
35402
  shared2.ctx.pieceObjects = /* @__PURE__ */ new Map();
35186
35403
  shared2.ctx.structureIndex = {};
35187
- for (const e of r0.structure && r0.structure.parts || []) shared2.ctx.structureIndex[e.id] = e;
35404
+ for (const e of r0.structure?.parts || []) shared2.ctx.structureIndex[e.id] = e;
35188
35405
  {
35189
35406
  const view = shared2.ctx.panelView = panelViewOf(r0.structure, !!cfg.destruction);
35190
35407
  shared2.ctx.panelsOf = /* @__PURE__ */ new Map();
@@ -35196,7 +35413,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
35196
35413
  else shared2.ctx.panelsOf.set(e.slab, [e]);
35197
35414
  }
35198
35415
  }
35199
- shared2.ctx.panes = r0.roof && r0.roof.panes || [];
35416
+ shared2.ctx.panes = r0.roof?.panes || [];
35200
35417
  shared2.ctx.noPiece = false;
35201
35418
  cursor.separate = opts.pieces === "meshes";
35202
35419
  cursor.pc = null;
@@ -35207,7 +35424,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
35207
35424
  shared2.ctx.pu = Math.max(0, pr.unit != null ? pr.unit : 0);
35208
35425
  shared2.ctx.showBuilding = shared2.ctx.apartment && (pr.showIt == null ? true : !!pr.showIt);
35209
35426
  shared2.ctx.limits = { x0: -2, z0: -2, x1: r.w + 2, z1: r.d + 2 };
35210
- shared2.ctx.veg = VEG ? { G: VEG.G, S: VEG.S, mats: vegMaterials, groups: /* @__PURE__ */ new Map(), ok: /* @__PURE__ */ new Map(), opts: shared2.quality === "game" ? { quality: "game" } : { lod: 0, triangleBudget: 6e4 } } : null;
35427
+ shared2.ctx.veg = VEG ? { G: VEG.G, S: VEG.S, mats: vegMaterials, groups: /* @__PURE__ */ new Map(), ok: /* @__PURE__ */ new Map(), opts: shared2.quality === "game" ? { quality: "game" } : { quality: "high", lod: 0, triangleBudget: 6e4 } } : null;
35211
35428
  shared2.ctx.vegInfo = null;
35212
35429
  terrain();
35213
35430
  if (r.lot) {
@@ -35257,7 +35474,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
35257
35474
  const g = gs[gd.name];
35258
35475
  if (!g) continue;
35259
35476
  delete gs[gd.name];
35260
- g.position.set(...gd.pos);
35477
+ g.position.fromArray(gd.pos);
35261
35478
  parent.add(g);
35262
35479
  fo.gs.push(g);
35263
35480
  }
@@ -35272,7 +35489,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
35272
35489
  root.add(house);
35273
35490
  shared2.mirrors.house = house;
35274
35491
  if (shared2.ctx.apartment) {
35275
- const u = r.building.units[Math.min(shared2.ctx.pu, r.building.units.length - 1)];
35492
+ const units = r.building.units, u = units[Math.min(shared2.ctx.pu, units.length - 1)];
35276
35493
  house.position.set(u.u, shared2.ctx.showBuilding ? 0 : -r.floors[0].y0, u.v);
35277
35494
  house.rotation.y = u.ry;
35278
35495
  shared2.ctx.unitRy = u.ry;
@@ -35388,7 +35605,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
35388
35605
  const wallAt = (f, axis2, L) => r.walls.find((w) => w.floor === f && w.axis === axis2 && Math.abs((axis2 === "u" ? w.v0 : w.u0) - L) < EPS6);
35389
35606
  for (const j of r.windows) {
35390
35607
  const alongU = j.axis === "u", y0 = Y0(j.floor), a = j.at - j.width / 2, b = j.at + j.width / 2, w = wallAt(j.floor, j.axis, j.pos), th = w ? w.thickness || 0.15 : 0.15, L = j.pos, id = "window:" + j.id;
35391
- parts[id] = { id, type: "window", group: null, virtual: true, floor: j.floor, aabb: alongU ? [a, y0 + j.y0, L - th / 2, b, y0 + j.y1, L + th / 2] : [L - th / 2, y0 + j.y0, a, L + th / 2, y0 + j.y1, b], damageable: tagDamage("glass"), opens: () => {
35608
+ const jy0 = j.y0, jy1 = j.y1;
35609
+ parts[id] = { id, type: "window", group: null, virtual: true, floor: j.floor, aabb: alongU ? [a, y0 + jy0, L - th / 2, b, y0 + jy1, L + th / 2] : [L - th / 2, y0 + jy0, a, L + th / 2, y0 + jy1, b], damageable: tagDamage("glass"), opens: () => {
35392
35610
  }, t: 0 };
35393
35611
  }
35394
35612
  for (const E of mirrorsCopy) {
@@ -35431,7 +35649,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
35431
35649
  const countDraw = () => {
35432
35650
  let n = 0, t = 0;
35433
35651
  root.traverseVisible((o) => {
35434
- if (o.isMesh) {
35652
+ if (isMesh(o)) {
35435
35653
  n++;
35436
35654
  t += (o.geometry.index ? o.geometry.index.count : o.geometry.attributes.position.count) / 3;
35437
35655
  }
@@ -35445,8 +35663,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
35445
35663
  const budget = opts.drawCallBudget != null ? opts.drawCallBudget : cfg.drawCallBudget;
35446
35664
  const stats2 = { quality: h.quality, drawCalls: s0.n, drawCallsLOD1: s1.n, triangles: s0.t, trianglesLod1: s1.t, budget: budget || null, overBudget: !!budget && s0.n > budget, tBuild: performance.now() - t0 };
35447
35665
  shared2.ctx.tBuild = stats2.tBuild;
35448
- const applyLod = (n) => {
35449
- n = Math.max(0, Math.min(2, n | 0));
35666
+ const applyLod = (level) => {
35667
+ const n = Math.max(0, Math.min(2, level | 0));
35450
35668
  if (n === h.lodCurrent) return;
35451
35669
  h.lodCurrent = n;
35452
35670
  for (const o of lodObjects) o.visible = n < 1;
@@ -35523,7 +35741,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
35523
35741
  lights: (() => {
35524
35742
  const by = {};
35525
35743
  for (const l of shared2.ctx.lights) {
35526
- const k = l.roomId != null ? l.roomId : l.room;
35744
+ const k = String(l.roomId != null ? l.roomId : l.room);
35527
35745
  (by[k] || (by[k] = [])).push(l);
35528
35746
  }
35529
35747
  return { list: shared2.ctx.lights, byRoom: by };
@@ -35563,9 +35781,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
35563
35781
  applyLod(Math.max(n, h.lodMin));
35564
35782
  }
35565
35783
  },
35566
- show(o) {
35784
+ show(options2) {
35567
35785
  enter(h);
35568
- o = o || {};
35786
+ const o = options2 || {};
35569
35787
  const rr = shared2.ctx.r, nA = rr.floors.length, a = o.floor == null ? -1 : o.floor, sel = a >= nA ? -1 : a, cut = !!o.cut;
35570
35788
  for (const [k, g] of Object.entries(gs)) {
35571
35789
  let v = true;
@@ -35585,7 +35803,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
35585
35803
  enter(h);
35586
35804
  const a = targetOf(o, opt);
35587
35805
  if (!a) return false;
35588
- return actOn(a.target && a.target.pub ? a.target.pub : { id: a.target && a.target.id || a.text, type: a.target && a.target.kit ? a.target.type : "door", label: a.text, ref: a.target, _action: a.action }, a);
35806
+ return actOn(a.target && a.target.pub ? a.target.pub : { id: a.target && a.target.id || a.text, type: a.target && a.target.kit ? a.target.type : "door", label: a.text, ref: a.target, _action: a.action, floor: 0, pos: [], radius: 0 }, a);
35589
35807
  },
35590
35808
  message() {
35591
35809
  return shared2.inter.msg && performance.now() < shared2.inter.msg.until ? shared2.inter.msg.text : null;
@@ -35642,13 +35860,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
35642
35860
  }
35643
35861
  return null;
35644
35862
  },
35645
- partAt(p, tol) {
35646
- tol = tol || 0.05;
35863
+ partAt(p, tolerance) {
35864
+ const tol = tolerance || 0.05;
35647
35865
  let m = null;
35648
35866
  for (const k in parts) {
35649
- const a = parts[k].aabb;
35867
+ const part = parts[k], a = part.aabb;
35650
35868
  if (a && p.x >= a[0] - tol && p.x <= a[3] + tol && p.y >= a[1] - tol && p.y <= a[4] + tol && p.z >= a[2] - tol && p.z <= a[5] + tol) {
35651
- m = parts[k];
35869
+ m = part;
35652
35870
  break;
35653
35871
  }
35654
35872
  }
@@ -35659,8 +35877,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
35659
35877
  destruction.deactivate();
35660
35878
  if (h.IV) ivDispose(h);
35661
35879
  root.traverse((o) => {
35662
- if (o.isMesh && o.geometry && !o.geometry.userData.shared) o.geometry.dispose();
35663
- if (o.type === "Reflector" && o.dispose) o.dispose();
35880
+ if (isMesh(o) && o.geometry && !o.geometry.userData.shared) o.geometry.dispose();
35881
+ if (o.type === "Reflector" && "dispose" in o && typeof o.dispose === "function") o.dispose();
35664
35882
  });
35665
35883
  root.removeFromParent();
35666
35884
  },
@@ -35668,7 +35886,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
35668
35886
  };
35669
35887
  return res;
35670
35888
  }
35671
- Object.assign(K, { build });
35889
+ const defined = { build };
35890
+ Object.assign(K, defined);
35672
35891
  }
35673
35892
  function buildApi(K, shared2) {
35674
35893
  const { cfg, VERSION: VERSION2, ATLAS, TEX, applyPart, carGroup, carModel, props, TYPES, roomLightMask, lighting, effectLights, newState, build } = K;
@@ -35688,11 +35907,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
35688
35907
  lighting,
35689
35908
  effectLights,
35690
35909
  setNight(n) {
35691
- shared2.mats.glass.emissive.set(n ? 9067040 : 0);
35692
- shared2.mats.glass.opacity = n ? 0.4 : 0.24;
35910
+ const glass = shared2.mats.glass;
35911
+ glass.emissive.set(n ? 9067040 : 0);
35912
+ glass.opacity = n ? 0.4 : 0.24;
35693
35913
  },
35694
35914
  /** The chipped-plaster painting of every house of this renderer as a `DeferredQueue` for a frame budget (id `floorplan.breach-paint`); asking for it changes nothing. */
35695
35915
  deferredQueue: () => K.breachPaintQueue,
35916
+ /* the destruction side is typed with the breach */
35696
35917
  cars: { model: carModel, group: carGroup, info: (k, seed) => {
35697
35918
  const m = carModel(k, seed);
35698
35919
  return m && { parts: m.parts.length, tris: m.tris, L: m.L, W: m.W, H: m.H };
@@ -35794,10 +36015,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
35794
36015
  }
35795
36016
 
35796
36017
  // ../game-floorplan-residential/dist/index.js
35797
- var __defProp3 = Object.defineProperty;
36018
+ var __defProp4 = Object.defineProperty;
35798
36019
  var __export2 = (target, all) => {
35799
36020
  for (var name in all)
35800
- __defProp3(target, name, { get: all[name], enumerable: true });
36021
+ __defProp4(target, name, { get: all[name], enumerable: true });
35801
36022
  };
35802
36023
  var residentialItems = [
35803
36024
  { type: "sofa_3seat", category: "sofa", w: 2.1, d: 0.9, h: 0.85, color: { role: "fabric_main" } },
@@ -37396,6 +37617,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
37396
37617
  signature = "";
37397
37618
  });
37398
37619
  return {
37620
+ get aimProgress() {
37621
+ return aimProgress;
37622
+ },
37399
37623
  handleChange(change) {
37400
37624
  if (change.kind === "action") return act(change.id);
37401
37625
  if (change.kind === "control" && change.id === SUPPORTED_CONTROL_ID && typeof change.value === "boolean") {
@@ -37542,7 +37766,63 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
37542
37766
  };
37543
37767
  var accessoryTextOf = (locale) => ACCESSORY_TEXT[locale] ?? ACCESSORY_TEXT.en;
37544
37768
 
37545
- // ../game-audio/dist/chunk-C2K7XN2K.js
37769
+ // ../game-audio/dist/chunk-JV5XXCQE.js
37770
+ var SFX_TIERS = { light: 0, medium: 0.34, heavy: 0.67 };
37771
+ function splitTier(id) {
37772
+ const match = /^(.*)_(light|medium|heavy)$/.exec(id);
37773
+ return match ? { base: match[1], tier: match[2] } : { base: id };
37774
+ }
37775
+ var refsOf = (entries2, baseUrl) => (entries2 ?? []).map((entry2) => ({ url: `${baseUrl}${entry2.file}` }));
37776
+ function sampleBankFromManifest(manifest, options) {
37777
+ const baseUrl = options.baseUrl ?? "";
37778
+ const samples = [];
37779
+ const tiersOf = /* @__PURE__ */ new Map();
37780
+ for (const sound3 of manifest.sounds) {
37781
+ const { base, tier } = splitTier(sound3.id);
37782
+ if (tier) tiersOf.set(base, [...tiersOf.get(base) ?? [], sound3]);
37783
+ }
37784
+ const bases = /* @__PURE__ */ new Map();
37785
+ for (const sound3 of manifest.sounds) {
37786
+ if (!splitTier(sound3.id).tier) bases.set(sound3.id, sound3);
37787
+ }
37788
+ for (const [base, tiers] of tiersOf) {
37789
+ if (!bases.has(base)) bases.set(base, { id: base, category: tiers[0]?.category ?? "", layers: { close: tiers[0]?.layers.close ?? [] } });
37790
+ }
37791
+ for (const sound3 of bases.values()) {
37792
+ const numbers = options.sounds?.[sound3.id] ?? options.defaults?.(sound3);
37793
+ const close = refsOf(sound3.layers.close, baseUrl);
37794
+ if (!numbers || close.length === 0) continue;
37795
+ const tiers = (tiersOf.get(sound3.id) ?? []).map((tier) => {
37796
+ const name = splitTier(tier.id).tier;
37797
+ const tierFar = refsOf(tier.layers.far, baseUrl);
37798
+ return { name, from: SFX_TIERS[name] ?? 0, close: refsOf(tier.layers.close, baseUrl), ...tierFar.length > 0 ? { far: tierFar } : {} };
37799
+ }).sort((a, b) => a.from - b.from);
37800
+ const far = refsOf(sound3.layers.far, baseUrl);
37801
+ const indoor = refsOf(sound3.layers.tail_in, baseUrl);
37802
+ const outdoor = refsOf(sound3.layers.tail_out, baseUrl);
37803
+ const files = [sound3, ...tiersOf.get(sound3.id) ?? []].flatMap((entry2) => Object.values(entry2.layers).flatMap((entries2) => entries2 ?? []));
37804
+ samples.push({
37805
+ id: sound3.id,
37806
+ bus: numbers.bus,
37807
+ close,
37808
+ ...far.length > 0 ? { far } : {},
37809
+ ...tiers.length > 0 ? { tiers } : {},
37810
+ ...numbers.crossover ? { crossover: numbers.crossover } : {},
37811
+ ...indoor.length > 0 || outdoor.length > 0 ? { tail: { ...indoor.length > 0 ? { indoor } : {}, ...outdoor.length > 0 ? { outdoor } : {}, ...numbers.tailGain === void 0 ? {} : { gain: numbers.tailGain } } } : {},
37812
+ ...numbers.pitch === void 0 ? {} : { pitch: numbers.pitch },
37813
+ ...numbers.gain === void 0 ? {} : { gain: numbers.gain },
37814
+ ...numbers.falloff ? { falloff: numbers.falloff } : {},
37815
+ ...numbers.cutoffK === void 0 ? {} : { cutoffK: numbers.cutoffK },
37816
+ ...numbers.group ? { group: numbers.group } : {},
37817
+ ...numbers.priority === void 0 ? {} : { priority: numbers.priority },
37818
+ ...numbers.fallback ? { fallback: numbers.fallback } : {},
37819
+ sources: files.map((file) => `${file.file}: ${file.source} ${file.author} ${file.license}`)
37820
+ });
37821
+ }
37822
+ return { id: options.id, samples };
37823
+ }
37824
+
37825
+ // ../game-audio/dist/chunk-UUWKSG4J.js
37546
37826
  var DISTANCE_CURVES = {
37547
37827
  /** The game's `sfx`: `vol / (1 + d² × 0.004)`, cutoff `/ (1 + d × 0.01)`, silent below 0.01 (jogo L62091–62092, L62101). */
37548
37828
  game_sfx: { model: "inverse_square", k: 4e-3, cutoffK: 0.01, minGain: 0.01 },
@@ -37717,6 +37997,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
37717
37997
  sources: [
37718
37998
  "sdk: the crackles of every fire share four voices"
37719
37999
  ]
38000
+ },
38001
+ debris_knock: {
38002
+ maxConcurrent: 3,
38003
+ cooldown: 0.04,
38004
+ sources: [
38005
+ "sdk: forty parts coming loose in one blast are a few knocks, not forty (room log: thunk x34 in under a second when a molotov broke)"
38006
+ ]
38007
+ },
38008
+ sizzle: {
38009
+ maxConcurrent: 1,
38010
+ cooldown: 0.5,
38011
+ sources: [
38012
+ "sdk: every melting part of a burning bin is one sizzle at a time (room log: hiss x34 in 1.6 s on a plastic bin)"
38013
+ ]
37720
38014
  }
37721
38015
  };
37722
38016
  var VOICE_GROUPS = voice_groups_default;
@@ -37804,17 +38098,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
37804
38098
  }
37805
38099
  return merged2;
37806
38100
  }
37807
- var trimmed = (refs, alias) => refs.map((ref) => ({
38101
+ var trimmed = (refs, alias) => refs.filter((ref) => alias.only === void 0 || ref.url.includes(alias.only)).map((ref) => ({
37808
38102
  ...ref,
37809
38103
  ...alias.offset === void 0 ? {} : { offset: alias.offset },
37810
38104
  ...alias.duration === void 0 ? {} : { duration: alias.duration }
37811
38105
  }));
37812
38106
  function aliasSample(alias, file) {
38107
+ const close = trimmed(file.close, alias);
38108
+ if (close.length === 0) return void 0;
37813
38109
  const { tiers: _tiers, fallback: _fallback, choke: _choke, ...rest2 } = file;
37814
38110
  return {
37815
38111
  ...rest2,
37816
38112
  id: alias.id,
37817
- close: trimmed(file.close, alias),
38113
+ close,
37818
38114
  ...file.far ? { far: trimmed(file.far, alias) } : {},
37819
38115
  ...alias.loop === void 0 ? {} : { loop: alias.loop },
37820
38116
  ...alias.baseFrequency === void 0 ? {} : { baseFrequency: alias.baseFrequency },
@@ -37841,7 +38137,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
37841
38137
  const file = samples.get(alias.file);
37842
38138
  if (!file) return void 0;
37843
38139
  const sample = aliasSample(alias, file);
37844
- derived.set(id, sample);
38140
+ if (sample) derived.set(id, sample);
37845
38141
  return sample;
37846
38142
  };
37847
38143
  const registry = {
@@ -39585,6 +39881,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
39585
39881
  const set2 = registry.set(id);
39586
39882
  return set2 ? chooser.pick(set2, random) : { id, rate: 1 };
39587
39883
  };
39884
+ const wanted = /* @__PURE__ */ new Set();
39588
39885
  const loadSounds = (sounds) => {
39589
39886
  const audio = ready();
39590
39887
  if (!audio) return Promise.resolve({ loaded: [], failed: sounds.flatMap(sampleUrls).map((url2) => ({ url: url2, error: "no audio context" })) });
@@ -39709,13 +40006,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
39709
40006
  };
39710
40007
  return {
39711
40008
  registry,
39712
- register: (bank) => registry.register(bank),
40009
+ register: (bank) => {
40010
+ registry.register(bank);
40011
+ if (wanted.size === 0) return;
40012
+ const now = [...wanted].map((id) => registry.sample(id)).filter((sample) => sample !== void 0);
40013
+ for (const sample of now) wanted.delete(sample.id);
40014
+ if (now.length > 0) void loadSounds(now).catch(() => void 0);
40015
+ },
39713
40016
  plan: (id, playOptions = {}) => planWith(id, playOptions, createRng3(playOptions.seed ?? seed)),
39714
40017
  planSample(id, playOptions = {}) {
39715
40018
  const sample = registry.sample(id);
39716
40019
  return sample ? planSample(sample, sampleInput(playOptions, createRng3(playOptions.seed ?? seed), false)) : null;
39717
40020
  },
39718
40021
  loadSamples(ids) {
40022
+ for (const id of ids ?? []) if (!registry.sample(id)) wanted.add(id);
39719
40023
  const chosen = (ids ?? registry.sampleIds()).map((id) => registry.sample(id)).filter((sample) => sample !== void 0);
39720
40024
  return loadSounds(chosen);
39721
40025
  },
@@ -40170,60 +40474,6 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
40170
40474
  burst: 20,
40171
40475
  burstSpacing: 0.06
40172
40476
  };
40173
- var SFX_TIERS = { light: 0, medium: 0.34, heavy: 0.67 };
40174
- function splitTier(id) {
40175
- const match = /^(.*)_(light|medium|heavy)$/.exec(id);
40176
- return match ? { base: match[1], tier: match[2] } : { base: id };
40177
- }
40178
- var refsOf = (entries2, baseUrl) => (entries2 ?? []).map((entry2) => ({ url: `${baseUrl}${entry2.file}` }));
40179
- function sampleBankFromManifest(manifest, options) {
40180
- const baseUrl = options.baseUrl ?? "";
40181
- const samples = [];
40182
- const tiersOf = /* @__PURE__ */ new Map();
40183
- for (const sound3 of manifest.sounds) {
40184
- const { base, tier } = splitTier(sound3.id);
40185
- if (tier) tiersOf.set(base, [...tiersOf.get(base) ?? [], sound3]);
40186
- }
40187
- const bases = /* @__PURE__ */ new Map();
40188
- for (const sound3 of manifest.sounds) {
40189
- if (!splitTier(sound3.id).tier) bases.set(sound3.id, sound3);
40190
- }
40191
- for (const [base, tiers] of tiersOf) {
40192
- if (!bases.has(base)) bases.set(base, { id: base, category: tiers[0]?.category ?? "", layers: { close: tiers[0]?.layers.close ?? [] } });
40193
- }
40194
- for (const sound3 of bases.values()) {
40195
- const numbers = options.sounds?.[sound3.id] ?? options.defaults?.(sound3);
40196
- const close = refsOf(sound3.layers.close, baseUrl);
40197
- if (!numbers || close.length === 0) continue;
40198
- const tiers = (tiersOf.get(sound3.id) ?? []).map((tier) => {
40199
- const name = splitTier(tier.id).tier;
40200
- const tierFar = refsOf(tier.layers.far, baseUrl);
40201
- return { name, from: SFX_TIERS[name] ?? 0, close: refsOf(tier.layers.close, baseUrl), ...tierFar.length > 0 ? { far: tierFar } : {} };
40202
- }).sort((a, b) => a.from - b.from);
40203
- const far = refsOf(sound3.layers.far, baseUrl);
40204
- const indoor = refsOf(sound3.layers.tail_in, baseUrl);
40205
- const outdoor = refsOf(sound3.layers.tail_out, baseUrl);
40206
- const files = [sound3, ...tiersOf.get(sound3.id) ?? []].flatMap((entry2) => Object.values(entry2.layers).flatMap((entries2) => entries2 ?? []));
40207
- samples.push({
40208
- id: sound3.id,
40209
- bus: numbers.bus,
40210
- close,
40211
- ...far.length > 0 ? { far } : {},
40212
- ...tiers.length > 0 ? { tiers } : {},
40213
- ...numbers.crossover ? { crossover: numbers.crossover } : {},
40214
- ...indoor.length > 0 || outdoor.length > 0 ? { tail: { ...indoor.length > 0 ? { indoor } : {}, ...outdoor.length > 0 ? { outdoor } : {}, ...numbers.tailGain === void 0 ? {} : { gain: numbers.tailGain } } } : {},
40215
- ...numbers.pitch === void 0 ? {} : { pitch: numbers.pitch },
40216
- ...numbers.gain === void 0 ? {} : { gain: numbers.gain },
40217
- ...numbers.falloff ? { falloff: numbers.falloff } : {},
40218
- ...numbers.cutoffK === void 0 ? {} : { cutoffK: numbers.cutoffK },
40219
- ...numbers.group ? { group: numbers.group } : {},
40220
- ...numbers.priority === void 0 ? {} : { priority: numbers.priority },
40221
- ...numbers.fallback ? { fallback: numbers.fallback } : {},
40222
- sources: files.map((file) => `${file.file}: ${file.source} ${file.author} ${file.license}`)
40223
- });
40224
- }
40225
- return { id: options.id, samples };
40226
- }
40227
40477
  var CATALOG = new Map([...SFX_CATALOG, ...SFX_IMPACTS].map((entry2) => [entry2.id, entry2]));
40228
40478
  var PT = {
40229
40479
  group: "Som",
@@ -42308,6 +42558,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
42308
42558
  const surfaceName = surface === "hard" ? "concreto" : surface === "soft" ? "terra" : surface === "wood" ? "madeira" : "metal";
42309
42559
  return { surface, kind, sample: `casing_drop_${surfaceName}_${kind}`, voices };
42310
42560
  }
42561
+ function magazineDropId(material) {
42562
+ const surface = casingSurfaceOf(material);
42563
+ return `mag_drop_${surface === "hard" ? "concreto" : surface === "soft" ? "terra" : surface === "wood" ? "madeira" : "metal"}`;
42564
+ }
42311
42565
 
42312
42566
  // src/audio/flyby.ts
42313
42567
  function computeFlyby(input) {
@@ -43109,7 +43363,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
43109
43363
  var isGunshot = (id) => GUNSHOT_SAMPLE_IDS.includes(id);
43110
43364
  function weaponSampleDefaults(sound3, overrides = {}) {
43111
43365
  if (sound3.category !== "armas") return void 0;
43112
- const base = sound3.id.startsWith("suppressed_") ? SUPPRESSED_SAMPLE : isGunshot(sound3.id) ? GUNSHOT_SAMPLE : sound3.id.startsWith("casing_drop_") ? CASING_SAMPLE : RELOAD_SAMPLE;
43366
+ 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;
43113
43367
  return { ...base, ...overrides[sound3.id] };
43114
43368
  }
43115
43369
  function weaponSampleBank(options) {
@@ -43160,6 +43414,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
43160
43414
  void loadSamples();
43161
43415
  return false;
43162
43416
  };
43417
+ const fittedReady = (id) => sampleIds.has(id) && engine.registry.sound(id) === void 0 && engine.registry.set(id) !== void 0;
43418
+ const hostReady = (id) => sampleReady(id) || engine.registry.sound(id) === void 0 && engine.registry.set(id) !== void 0;
43163
43419
  const burst2 = (config) => {
43164
43420
  const id = config.filter === "highpass" ? BURST_IDS.highpass : BURST_IDS.lowpass;
43165
43421
  const params = { frequency: config.frequency, q: config.q ?? 0.8, gain: Math.max(config.gain, 2e-4), seconds: config.seconds };
@@ -43214,6 +43470,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
43214
43470
  options.onCasing?.(sound3, "sample");
43215
43471
  return;
43216
43472
  }
43473
+ if (recorded && fittedReady(recorded)) {
43474
+ if ((input.bounce ?? 0) === 0) channel.play(recorded, { volume: Math.min(1, Math.max(0.2, (input.speed ?? 1.5) / 2.5)) });
43475
+ options.onCasing?.(sound3, "fitted");
43476
+ return;
43477
+ }
43217
43478
  for (const voice2 of sound3.voices) playCasingVoice(voice2);
43218
43479
  options.onCasing?.(sound3, "synth");
43219
43480
  };
@@ -43238,7 +43499,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
43238
43499
  const pitch = 1 + (channel.random() * 2 - 1) * pitchSpread;
43239
43500
  const shot = computeGunshot({ ...base, take, pitch }, options.gunshot);
43240
43501
  const recorded = shot.samples.close;
43241
- if (shot.audible && sampleReady(recorded)) {
43502
+ const sample = shot.audible && sampleReady(recorded);
43503
+ const fitted = shot.audible && !sample && fittedReady(recorded);
43504
+ if (sample || fitted) {
43242
43505
  const occlusion = Math.min(1, Math.max(0, extras.occlusion ?? 0));
43243
43506
  const handle = channel.play(recorded, {
43244
43507
  volume: (extras.volume ?? 1) * (1 - 0.5 * occlusion),
@@ -43251,7 +43514,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
43251
43514
  for (const voice2 of shot.voices) if (voice2.group === "tail") playGunshotVoice(voice2, extras);
43252
43515
  }
43253
43516
  const layers = handle?.kind === "sample" ? handle.plan.layers.map((layer3) => ({ role: layer3.role, take: layer3.take, rate: layer3.rate })) : [];
43254
- options.onGunshot?.(shot, { ...base, take, pitch }, { kind: "sample", id: recorded, layers });
43517
+ options.onGunshot?.(shot, { ...base, take, pitch }, fitted ? { kind: "fitted", id: recorded } : { kind: "sample", id: recorded, layers });
43255
43518
  return;
43256
43519
  }
43257
43520
  for (const voice2 of shot.voices) playGunshotVoice(voice2, extras);
@@ -43272,10 +43535,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
43272
43535
  mechanical,
43273
43536
  cue(id, profile, lead = 0) {
43274
43537
  const carriedBy = CUES_IN_SAMPLE[id];
43275
- if (carriedBy && sampleReady(carriedBy)) return "carried";
43276
- if (sampleReady(id)) {
43538
+ if (carriedBy && (sampleReady(carriedBy) || fittedReady(carriedBy))) return "carried";
43539
+ const recorded = sampleReady(id);
43540
+ if (recorded || fittedReady(id)) {
43277
43541
  channel.play(id, { intensity: WEIGHT_INTENSITY[(profile ?? DEFAULT_SOUND_PROFILE).weight] });
43278
- return "sample";
43542
+ return recorded ? "sample" : "fitted";
43279
43543
  }
43280
43544
  for (const entry2 of reloadCueSteps(id, profile, cueTable)) step(lead > 0 ? { ...entry2, at: entry2.at + lead } : entry2);
43281
43545
  return "synth";
@@ -43302,7 +43566,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
43302
43566
  casing: casing2,
43303
43567
  flyby(input) {
43304
43568
  const sound3 = computeFlyby({ ...input, pitch: input.pitch ?? 1 + (channel.random() * 2 - 1) * 0.05 });
43305
- for (const voice2 of sound3?.voices ?? []) playCasingVoice(voice2, input.position);
43569
+ if (!sound3) return;
43570
+ if (hostReady(sound3.sample)) {
43571
+ channel.play(sound3.sample, { volume: Math.min(1, 1 / (1 + input.miss / 1.5)), ...input.position ? { position: [input.position[0], input.position[1], input.position[2]] } : {} });
43572
+ return;
43573
+ }
43574
+ for (const voice2 of sound3.voices) playCasingVoice(voice2, input.position);
43306
43575
  },
43307
43576
  clink() {
43308
43577
  if (options.shotModel !== "game") {
@@ -43313,8 +43582,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
43313
43582
  const at3 = 0.25 + channel.random() * 0.2;
43314
43583
  sceneTone2({ layer: "scene_tone", at: at3, wave: "sine", f, f2: 3800, d: 0.06, vol: 0.06 });
43315
43584
  },
43316
- thud() {
43317
- burst2({ seconds: 0.09, gain: 0.35, filter: "lowpass", frequency: 380 });
43585
+ thud(input = {}) {
43586
+ const id = magazineDropId(input.surface);
43587
+ if (hostReady(id)) {
43588
+ if ((input.bounce ?? 0) === 0) channel.play(id, { volume: Math.min(1, Math.max(0.2, (input.speed ?? 1.5) / 2.5)) });
43589
+ return;
43590
+ }
43591
+ 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 });
43318
43592
  },
43319
43593
  setVolume(next) {
43320
43594
  const level = Math.max(0, Math.min(1, next));
@@ -43386,6 +43660,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
43386
43660
  shoulderGripTo: 0.34,
43387
43661
  /** The farthest apart two hands hold a long gun (a support hand past it slides back along the gun, toward the grip). */
43388
43662
  supportSpan: 0.5,
43663
+ /** A gun carried at the hip (`carry: 'hip'`): its rear grip low at the right hip, a little ahead of it. */
43664
+ hipGrip: [0.25, -0.5, -0.24],
43389
43665
  /** How much of the aim's pitch a tool held low in one hand follows. */
43390
43666
  toolPitch: 0.5
43391
43667
  };
@@ -43397,6 +43673,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
43397
43673
  holder.scale.setScalar(1);
43398
43674
  hand.position.set(...frame2.position);
43399
43675
  hand.quaternion.set(...frame2.quaternion);
43676
+ if (placement.hip) return placeAtHip(placement);
43400
43677
  const shouldered = !placement.handgun && placement.left !== null && placement.lengthMetres >= BODY_HOLD.shoulderedFrom;
43401
43678
  if (shouldered) {
43402
43679
  holder.position.set(0, BODY_HOLD.boreAbove, placement.rear);
@@ -43420,6 +43697,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
43420
43697
  hand.position.add(want.sub(now));
43421
43698
  hand.updateMatrixWorld(true);
43422
43699
  };
43700
+ var placeAtHip = (placement) => {
43701
+ const { THREE, hand, holder } = placement;
43702
+ scratch.a ?? (scratch.a = new THREE.Vector3());
43703
+ scratch.b ?? (scratch.b = new THREE.Vector3());
43704
+ scratch.euler ?? (scratch.euler = new THREE.Euler());
43705
+ const turn2 = scratch.euler.setFromQuaternion(hand.quaternion, "YXZ");
43706
+ hand.quaternion.setFromEuler(turn2.set(turn2.x * BODY_HOLD.toolPitch, turn2.y, 0, "YXZ"));
43707
+ holder.position.set(0, 0, 0);
43708
+ hand.updateMatrixWorld(true);
43709
+ if (!placement.right) return;
43710
+ const want = scratch.a.set(...BODY_HOLD.hipGrip).applyQuaternion(hand.quaternion).add(hand.position);
43711
+ const now = placement.right.part.localToWorld(scratch.b.copy(placement.right.offset));
43712
+ hand.position.add(want.sub(now));
43713
+ hand.updateMatrixWorld(true);
43714
+ };
43423
43715
  var limitSupportSpan = (targets) => {
43424
43716
  const right = targets.R?.position;
43425
43717
  const left = targets.L?.position;
@@ -43443,6 +43735,57 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
43443
43735
  };
43444
43736
  };
43445
43737
 
43738
+ // src/fx/view-hold.ts
43739
+ var VIEW_HOLD = {
43740
+ long: { grip: [0.2, -0.28, -0.38], fov: 84, sights: { distance: 0.34, fromRear: 0.3 } },
43741
+ handgun: { grip: [0.13, -0.15, -0.33], fov: 76, sights: { distance: 0.42, fromRear: 0.02 } },
43742
+ launcher: { grip: [0.2, -0.14, -0.3], fov: 84, sights: { distance: 0.18, fromRear: 0.25 } },
43743
+ tool: { grip: [0.21, -0.31, -0.36], fov: 84, sights: { distance: 0.3, fromRear: 0.1 }, tilt: 0.3 },
43744
+ // the gun at the hip, its rear grip low and to the right, the barrels ahead of the body; it has no sights to bring to the eye
43745
+ hip: { grip: [0.44, -0.32, -0.42], fov: 84, sights: { distance: 0.6, fromRear: 0.1 } }
43746
+ };
43747
+ var NO_GRIP_REAR = [0.2, -0.24, -0.12];
43748
+ var SIGHT_UNDER_EYE = 0.02;
43749
+ var scratch2 = { grip: null, hip: null, aimed: null, tilt: null };
43750
+ var ease = (k) => k * k * (3 - 2 * k);
43751
+ function placeInView(placement) {
43752
+ const { THREE, hand, holder, camera: camera2, right, box: box5, kind } = placement;
43753
+ const hold = VIEW_HOLD[kind];
43754
+ holder.scale.setScalar(1);
43755
+ hand.position.copy(camera2.position);
43756
+ hand.quaternion.copy(camera2.quaternion);
43757
+ if (hold.tilt) {
43758
+ scratch2.tilt ?? (scratch2.tilt = new THREE.Quaternion());
43759
+ hand.quaternion.multiply(scratch2.tilt.setFromAxisAngle(new THREE.Vector3(1, 0, 0), hold.tilt));
43760
+ }
43761
+ hand.scale.setScalar(1);
43762
+ holder.position.set(0, 0, 0);
43763
+ hand.updateMatrixWorld(true);
43764
+ scratch2.hip ?? (scratch2.hip = new THREE.Vector3());
43765
+ const hip = scratch2.hip;
43766
+ if (right) {
43767
+ scratch2.grip ?? (scratch2.grip = new THREE.Vector3());
43768
+ const grip = hand.worldToLocal(right.part.localToWorld(scratch2.grip.copy(right.offset)));
43769
+ hip.set(hold.grip[0] - grip.x, hold.grip[1] - grip.y, hold.grip[2] - grip.z);
43770
+ } else hip.set(NO_GRIP_REAR[0], NO_GRIP_REAR[1], NO_GRIP_REAR[2] + box5.min.x);
43771
+ const k = ease(Math.max(0, Math.min(1, placement.aim)));
43772
+ if (k > 0) {
43773
+ const along = box5.min.x + hold.sights.fromRear;
43774
+ scratch2.aimed ?? (scratch2.aimed = new THREE.Vector3());
43775
+ hip.lerp(scratch2.aimed.set(0, -SIGHT_UNDER_EYE - box5.max.y, along - hold.sights.distance), k);
43776
+ }
43777
+ holder.position.copy(hip).add(placement.offset);
43778
+ hand.updateMatrixWorld(true);
43779
+ }
43780
+ function toWorldLens(camera2, point, worldFov, lensFov) {
43781
+ const k = Math.tan(worldFov * Math.PI / 360) / Math.tan(lensFov * Math.PI / 360);
43782
+ camera2.updateMatrixWorld();
43783
+ camera2.worldToLocal(point);
43784
+ point.x *= k;
43785
+ point.y *= k;
43786
+ return camera2.localToWorld(point);
43787
+ }
43788
+
43446
43789
  // src/fx/hand-hold.ts
43447
43790
  var HAND_HOLD = {
43448
43791
  /** Half the width of a pistol grip, the palm sits this far (plus the palm) off its middle. */
@@ -43521,6 +43864,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
43521
43864
  const toRoot = (x, y, z) => V(THREE, inner.position.x + x * inner.scale.x, y, z);
43522
43865
  const handgun = parts.family === "pistol" || parts.family === "revolver";
43523
43866
  root.updateWorldMatrix(true, true);
43867
+ if (parts.holdRight || parts.holdLeft) return namedHold(THREE, model, holderScale);
43524
43868
  let gripAt;
43525
43869
  let up;
43526
43870
  if (parts.grip) {
@@ -43567,6 +43911,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
43567
43911
  gripLeft: HAND_HOLD.forend
43568
43912
  };
43569
43913
  }
43914
+ function namedHold(THREE, model, holderScale) {
43915
+ const { parts } = model;
43916
+ const on = (mark, fingers) => mark ? { part: mark, offset: V(THREE, 0, HAND_HOLD.palm, 0), quaternion: handFrame(THREE, fingers, V(THREE, 0, 1, 0)) } : null;
43917
+ return {
43918
+ right: on(parts.holdRight, V(THREE, 1, 0, 0)),
43919
+ left: on(parts.holdLeft, V(THREE, 0, 0, 1)),
43920
+ leftMagazine: null,
43921
+ scale: holderScale,
43922
+ grip: HAND_HOLD.closed,
43923
+ gripLeft: HAND_HOLD.closed
43924
+ };
43925
+ }
43570
43926
  function holdOfProp(THREE, group, category, scale) {
43571
43927
  const handle = group.getObjectByName("handle") ?? group.getObjectByName("body") ?? group;
43572
43928
  const head = group.getObjectByName("head");
@@ -44274,7 +44630,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
44274
44630
  rules: { dropCapacity: 400, curbCatch: false, guardBehindWall: false, clipRoadEnd: false, dripStyle: "workshop" }
44275
44631
  });
44276
44632
 
44277
- // ../game-items-three/dist/chunk-WGFTVYO3.js
44633
+ // ../game-items-three/dist/chunk-76GT7V27.js
44278
44634
  var destruction_default = {
44279
44635
  families: {
44280
44636
  drink_can: {
@@ -51034,6 +51390,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
51034
51390
  const q2 = new THREE.Quaternion();
51035
51391
  const pointForward = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2);
51036
51392
  const frontOf = new THREE.Vector3();
51393
+ const restBox = new THREE.Box3();
51394
+ const noMotion = new THREE.Vector3();
51395
+ let inLens = false;
51396
+ const setLens = (on) => {
51397
+ if (on !== inLens) options.viewmodelFov?.(on ? VIEW_HOLD.tool.fov : null);
51398
+ inLens = on;
51399
+ const layer3 = on ? FIRST_PERSON_LAYER : 0;
51400
+ hand.traverse((node) => node.layers.set(layer3));
51401
+ };
51037
51402
  const equip = (weapon) => {
51038
51403
  if (model) hand.remove(model);
51039
51404
  model = null;
@@ -51041,6 +51406,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
51041
51406
  def = arsenal.weapons.get(weapon) ?? null;
51042
51407
  if (!def || BODY_ACTIONS.has(def.id)) return;
51043
51408
  model = buildWeaponModel(THREE, def, options.items);
51409
+ restBox.setFromObject(model);
51410
+ inLens = false;
51044
51411
  const length2 = new THREE.Box3().setFromObject(model).getSize(v).x;
51045
51412
  rear = new THREE.Box3().setFromObject(model).min.x;
51046
51413
  lengthMetres = length2;
@@ -51141,6 +51508,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
51141
51508
  return {
51142
51509
  unequip() {
51143
51510
  if (model) hand.remove(model);
51511
+ if (inLens) setLens(false);
51144
51512
  model = null;
51145
51513
  inHand = null;
51146
51514
  hold = null;
@@ -51149,6 +51517,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
51149
51517
  if (!model || !def || !SPOUTS.has(def.action.kind)) return null;
51150
51518
  hand.updateMatrixWorld(true);
51151
51519
  const at3 = model.localToWorld(v.copy(frontOf));
51520
+ if (inLens) toWorldLens(camera2, at3, camera2.fov ?? 72, VIEW_HOLD.tool.fov);
51152
51521
  const along = v2.set(1, 0, 0).applyQuaternion(model.getWorldQuaternion(q2)).normalize();
51153
51522
  return { position: [at3.x, at3.y, at3.z], direction: [along.x, along.y, along.z], drawsFlash: false };
51154
51523
  },
@@ -51171,7 +51540,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
51171
51540
  update(dt) {
51172
51541
  kick *= Math.exp(-dt * 14);
51173
51542
  dip += ((reloading ? 1 : 0) - dip) * Math.min(1, dt * 8);
51174
- if (inHand && model) {
51543
+ if (inHand && model && options.firstPerson?.()) {
51544
+ setLens(true);
51545
+ placeInView({ THREE, hand, holder: model, camera: camera2, right: hold?.right ?? null, box: restBox, kind: "tool", aim: 0, offset: noMotion });
51546
+ hand.position.add(v.set(0, -0.12 * dip, 0.05 * kick).applyQuaternion(camera2.quaternion));
51547
+ hand.updateMatrixWorld(true);
51548
+ } else if (inHand && model) {
51549
+ if (inLens) setLens(false);
51175
51550
  const handgun = def?.category === "pistol" || def?.category === "revolver";
51176
51551
  placeOnBody({ THREE, hand, holder: model, frame: options.bodyHold?.() ?? eyeFrame(), rear, lengthMetres, handgun, right: hold?.right ?? null, left: hold?.left ?? null });
51177
51552
  hand.position.add(v.set(0, -0.12 * dip, 0.05 * kick).applyQuaternion(camera2.quaternion));
@@ -53712,6 +54087,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
53712
54087
  cylinderZ(group, 0.016, 0.07, M.poly, 0.06, -0.01, side * 0.2, 14);
53713
54088
  }
53714
54089
  parts.trigger = box5(group, 0.012, 0.02, 0.016, M.dark, 0.1, 0.085, 0.14, 0.3);
54090
+ parts.holdRight = kit.mark(group, 0.06, 6e-3, 0.2);
54091
+ parts.holdLeft = kit.mark(group, 0.22, 0.164, 0);
54092
+ parts.carry = "hip";
53715
54093
  parts.safety = box5(group, 0.014, 6e-3, 0.01, M.dark, 0.2, 0.073, -0.076, 0.4);
53716
54094
  }
53717
54095
  function buildFeed(kit, parts, group) {
@@ -54143,7 +54521,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
54143
54521
  var ROOT = "root";
54144
54522
  var AXIS_INDEX = { x: 0, y: 1, z: 2 };
54145
54523
  var EASE_STEPS = 10;
54146
- var ease = (progress) => progress < 0.5 ? 2 * progress * progress : 1 - (-2 * progress + 2) ** 2 / 2;
54524
+ var ease2 = (progress) => progress < 0.5 ? 2 * progress * progress : 1 - (-2 * progress + 2) ** 2 / 2;
54147
54525
  var move = (part, axis2, start, duration, from, to) => ({ part, channel: "position", axis: axis2, start, duration, from, to });
54148
54526
  var turn = (part, axis2, start, duration, from, to) => ({ part, channel: "rotation", axis: axis2, start, duration, from, to });
54149
54527
  var cue = (t, type, data) => ({ t, type, ...data ? { data } : {} });
@@ -54157,7 +54535,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
54157
54535
  for (const tween of tweens) {
54158
54536
  if (tween.start > t || tween.duration === 0 && (tween.start === t ? !includeInstants : false)) continue;
54159
54537
  if (tween.duration === 0 || t >= tween.start + tween.duration) value = tween.to;
54160
- else value = tween.from + (tween.to - tween.from) * ease((t - tween.start) / tween.duration);
54538
+ else value = tween.from + (tween.to - tween.from) * ease2((t - tween.start) / tween.duration);
54161
54539
  }
54162
54540
  return value;
54163
54541
  };
@@ -55206,9 +55584,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
55206
55584
  }
55207
55585
 
55208
55586
  // ../game-vfx/dist/index.js
55209
- var __defProp4 = Object.defineProperty;
55210
- var __defNormalProp2 = (obj, key2, value) => key2 in obj ? __defProp4(obj, key2, { enumerable: true, configurable: true, writable: true, value }) : obj[key2] = value;
55211
- var __publicField2 = (obj, key2, value) => __defNormalProp2(obj, typeof key2 !== "symbol" ? key2 + "" : key2, value);
55587
+ var __defProp5 = Object.defineProperty;
55588
+ var __defNormalProp3 = (obj, key2, value) => key2 in obj ? __defProp5(obj, key2, { enumerable: true, configurable: true, writable: true, value }) : obj[key2] = value;
55589
+ var __publicField3 = (obj, key2, value) => __defNormalProp3(obj, typeof key2 !== "symbol" ? key2 + "" : key2, value);
55212
55590
  var AREA_CAP_GAME = { radius: 40, window: 4, count: 6, excessScale: 0.3 };
55213
55591
  function createAreaCap(cap) {
55214
55592
  const recent = [];
@@ -56256,11 +56634,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
56256
56634
  var DEFAULT_WIND = { x: 0.55, y: 0, z: 0.2 };
56257
56635
  var OrderedPool = class {
56258
56636
  constructor(capacity, create4, release) {
56259
- __publicField2(this, "capacity", capacity);
56260
- __publicField2(this, "create", create4);
56261
- __publicField2(this, "release", release);
56262
- __publicField2(this, "items", []);
56263
- __publicField2(this, "spare", []);
56637
+ __publicField3(this, "capacity", capacity);
56638
+ __publicField3(this, "create", create4);
56639
+ __publicField3(this, "release", release);
56640
+ __publicField3(this, "items", []);
56641
+ __publicField3(this, "spare", []);
56264
56642
  }
56265
56643
  get count() {
56266
56644
  return this.items.length;
@@ -56555,13 +56933,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
56555
56933
  }
56556
56934
  var Enclosures = class {
56557
56935
  constructor(seed = 20973) {
56558
- __publicField2(this, "spaces", /* @__PURE__ */ new Map());
56559
- __publicField2(this, "list", []);
56560
- __publicField2(this, "random");
56561
- __publicField2(this, "out", { x: 0, y: 0, z: 0, nx: 0, ny: 0, nz: 0 });
56562
- __publicField2(this, "l0", new Float64Array(3));
56563
- __publicField2(this, "l1", new Float64Array(3));
56564
- __publicField2(this, "q", new Float64Array(3));
56936
+ __publicField3(this, "spaces", /* @__PURE__ */ new Map());
56937
+ __publicField3(this, "list", []);
56938
+ __publicField3(this, "random");
56939
+ __publicField3(this, "out", { x: 0, y: 0, z: 0, nx: 0, ny: 0, nz: 0 });
56940
+ __publicField3(this, "l0", new Float64Array(3));
56941
+ __publicField3(this, "l1", new Float64Array(3));
56942
+ __publicField3(this, "q", new Float64Array(3));
56565
56943
  this.random = lehmer(seed);
56566
56944
  }
56567
56945
  get empty() {
@@ -57084,7 +57462,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
57084
57462
  var round4 = call("round");
57085
57463
  var clamp3 = call("clamp");
57086
57464
  var lerp2 = call("lerp");
57087
- var ease2 = call("ease");
57465
+ var ease3 = call("ease");
57088
57466
  var lt = call("lt");
57089
57467
  var gt = call("gt");
57090
57468
  var le = call("le");
@@ -58183,15 +58561,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
58183
58561
  var inPuddle = (puddles, x, z) => puddles.some((p) => ((x - p[0]) / p[2]) ** 2 + ((z - p[1]) / p[3]) ** 2 < 1);
58184
58562
  var RainField = class {
58185
58563
  constructor(engine) {
58186
- __publicField2(this, "engine", engine);
58187
- __publicField2(this, "positions", new Float32Array(RAIN_CAPACITY * 6));
58188
- __publicField2(this, "count", 0);
58189
- __publicField2(this, "wind", 1);
58190
- __publicField2(this, "on", false);
58191
- __publicField2(this, "centerX", 0);
58192
- __publicField2(this, "centerZ", 0);
58193
- __publicField2(this, "puddles", WORKSHOP_PUDDLES);
58194
- __publicField2(this, "puddleAt");
58564
+ __publicField3(this, "engine", engine);
58565
+ __publicField3(this, "positions", new Float32Array(RAIN_CAPACITY * 6));
58566
+ __publicField3(this, "count", 0);
58567
+ __publicField3(this, "wind", 1);
58568
+ __publicField3(this, "on", false);
58569
+ __publicField3(this, "centerX", 0);
58570
+ __publicField3(this, "centerZ", 0);
58571
+ __publicField3(this, "puddles", WORKSHOP_PUDDLES);
58572
+ __publicField3(this, "puddleAt");
58195
58573
  }
58196
58574
  /** `initRain` (W321): `count` streaks (thinned by the quality), each drawn at a random place in the box. */
58197
58575
  init(count, wind) {
@@ -59875,19 +60253,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
59875
60253
  };
59876
60254
  var EffectInstance = class {
59877
60255
  constructor(deps) {
59878
- __publicField2(this, "deps", deps);
59879
- __publicField2(this, "variables", /* @__PURE__ */ new Map());
59880
- __publicField2(this, "def");
59881
- __publicField2(this, "param", 0);
59882
- __publicField2(this, "fresh", false);
59883
- __publicField2(this, "time", 0);
59884
- __publicField2(this, "elapsed", 0);
59885
- __publicField2(this, "setup", {});
59886
- __publicField2(this, "dt", 0);
59887
- __publicField2(this, "index", 0);
59888
- __publicField2(this, "schedule", createSchedule());
59889
- __publicField2(this, "host");
59890
- __publicField2(this, "context");
60256
+ __publicField3(this, "deps", deps);
60257
+ __publicField3(this, "variables", /* @__PURE__ */ new Map());
60258
+ __publicField3(this, "def");
60259
+ __publicField3(this, "param", 0);
60260
+ __publicField3(this, "fresh", false);
60261
+ __publicField3(this, "time", 0);
60262
+ __publicField3(this, "elapsed", 0);
60263
+ __publicField3(this, "setup", {});
60264
+ __publicField3(this, "dt", 0);
60265
+ __publicField3(this, "index", 0);
60266
+ __publicField3(this, "schedule", createSchedule());
60267
+ __publicField3(this, "host");
60268
+ __publicField3(this, "context");
59891
60269
  const instance = () => this;
59892
60270
  this.host = {
59893
60271
  engine: deps.engine,
@@ -60952,33 +61330,33 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
60952
61330
  }
60953
61331
  var SpriteKindPool = class {
60954
61332
  constructor(capacity, defs, owners) {
60955
- __publicField2(this, "capacity", capacity);
60956
- __publicField2(this, "defs", defs);
60957
- __publicField2(this, "owners", owners);
60958
- __publicField2(this, "live", 0);
60959
- __publicField2(this, "drawCount", 0);
60960
- __publicField2(this, "position");
60961
- __publicField2(this, "color");
60962
- __publicField2(this, "alpha");
60963
- __publicField2(this, "size");
60964
- __publicField2(this, "next", 0);
60965
- __publicField2(this, "high", 0);
60966
- __publicField2(this, "velocity");
60967
- __publicField2(this, "age");
60968
- __publicField2(this, "life");
60969
- __publicField2(this, "size0");
60970
- __publicField2(this, "alive");
60971
- __publicField2(this, "kind");
60972
- __publicField2(this, "seed");
60973
- __publicField2(this, "alphaMul");
60974
- __publicField2(this, "tag");
60975
- __publicField2(this, "owner");
60976
- __publicField2(this, "colorHex");
60977
- __publicField2(this, "rgbStart");
60978
- __publicField2(this, "rgbEnd");
60979
- __publicField2(this, "bounced");
60980
- __publicField2(this, "floor");
60981
- __publicField2(this, "riseMul");
61333
+ __publicField3(this, "capacity", capacity);
61334
+ __publicField3(this, "defs", defs);
61335
+ __publicField3(this, "owners", owners);
61336
+ __publicField3(this, "live", 0);
61337
+ __publicField3(this, "drawCount", 0);
61338
+ __publicField3(this, "position");
61339
+ __publicField3(this, "color");
61340
+ __publicField3(this, "alpha");
61341
+ __publicField3(this, "size");
61342
+ __publicField3(this, "next", 0);
61343
+ __publicField3(this, "high", 0);
61344
+ __publicField3(this, "velocity");
61345
+ __publicField3(this, "age");
61346
+ __publicField3(this, "life");
61347
+ __publicField3(this, "size0");
61348
+ __publicField3(this, "alive");
61349
+ __publicField3(this, "kind");
61350
+ __publicField3(this, "seed");
61351
+ __publicField3(this, "alphaMul");
61352
+ __publicField3(this, "tag");
61353
+ __publicField3(this, "owner");
61354
+ __publicField3(this, "colorHex");
61355
+ __publicField3(this, "rgbStart");
61356
+ __publicField3(this, "rgbEnd");
61357
+ __publicField3(this, "bounced");
61358
+ __publicField3(this, "floor");
61359
+ __publicField3(this, "riseMul");
60982
61360
  const n = Math.max(1, capacity);
60983
61361
  this.position = new Float32Array(n * 3);
60984
61362
  this.color = new Float32Array(n * 3);
@@ -61471,15 +61849,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
61471
61849
  var SPRITE_KINDS = sprite_kinds_default;
61472
61850
  var SpriteKindSystem = class {
61473
61851
  constructor(options) {
61474
- __publicField2(this, "options", options);
61475
- __publicField2(this, "additive");
61476
- __publicField2(this, "normal");
61477
- __publicField2(this, "random");
61478
- __publicField2(this, "ids");
61479
- __publicField2(this, "defs");
61480
- __publicField2(this, "index", /* @__PURE__ */ new Map());
61481
- __publicField2(this, "owners", []);
61482
- __publicField2(this, "listeners", /* @__PURE__ */ new Map());
61852
+ __publicField3(this, "options", options);
61853
+ __publicField3(this, "additive");
61854
+ __publicField3(this, "normal");
61855
+ __publicField3(this, "random");
61856
+ __publicField3(this, "ids");
61857
+ __publicField3(this, "defs");
61858
+ __publicField3(this, "index", /* @__PURE__ */ new Map());
61859
+ __publicField3(this, "owners", []);
61860
+ __publicField3(this, "listeners", /* @__PURE__ */ new Map());
61483
61861
  const kinds = options.kinds ?? SPRITE_KINDS;
61484
61862
  this.ids = Object.keys(kinds);
61485
61863
  this.defs = this.ids.map((id) => kinds[id]);
@@ -61633,11 +62011,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
61633
62011
  }
61634
62012
  var DebrisPool = class {
61635
62013
  constructor(context) {
61636
- __publicField2(this, "context", context);
61637
- __publicField2(this, "pieces", Array.from({ length: CAPACITY }, createPiece));
61638
- __publicField2(this, "count", 0);
61639
- __publicField2(this, "next", 0);
61640
- __publicField2(this, "direction", { x: 0, y: 0, z: 0 });
62014
+ __publicField3(this, "context", context);
62015
+ __publicField3(this, "pieces", Array.from({ length: CAPACITY }, createPiece));
62016
+ __publicField3(this, "count", 0);
62017
+ __publicField3(this, "next", 0);
62018
+ __publicField3(this, "direction", { x: 0, y: 0, z: 0 });
61641
62019
  }
61642
62020
  spawn(options) {
61643
62021
  const random = this.context.random;
@@ -61724,10 +62102,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
61724
62102
  }
61725
62103
  var DecalPool = class {
61726
62104
  constructor(context) {
61727
- __publicField2(this, "context", context);
61728
- __publicField2(this, "decals", Array.from({ length: CAPACITY2 }, createDecal));
61729
- __publicField2(this, "count", 0);
61730
- __publicField2(this, "next", 0);
62105
+ __publicField3(this, "context", context);
62106
+ __publicField3(this, "decals", Array.from({ length: CAPACITY2 }, createDecal));
62107
+ __publicField3(this, "count", 0);
62108
+ __publicField3(this, "next", 0);
61731
62109
  }
61732
62110
  add(x, y, z, size, color2, options = {}) {
61733
62111
  const random = this.context.random;
@@ -61802,9 +62180,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
61802
62180
  var aboutX = (angle) => [Math.sin(angle / 2), 0, 0, Math.cos(angle / 2)];
61803
62181
  var MeshPool = class {
61804
62182
  constructor(capacity = CAPACITY3) {
61805
- __publicField2(this, "capacity", capacity);
61806
- __publicField2(this, "particles", []);
61807
- __publicField2(this, "serial", 0);
62183
+ __publicField3(this, "capacity", capacity);
62184
+ __publicField3(this, "particles", []);
62185
+ __publicField3(this, "serial", 0);
61808
62186
  }
61809
62187
  get count() {
61810
62188
  return this.particles.length;
@@ -61888,31 +62266,31 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
61888
62266
  var SpritePool = class {
61889
62267
  /** `carried`: the normal-blend pool (smoke, dust, steam), whose light sprites go round the closed spaces; the additive one (flames, sparks) does not. */
61890
62268
  constructor(capacity, context, carried = false) {
61891
- __publicField2(this, "capacity", capacity);
61892
- __publicField2(this, "context", context);
61893
- __publicField2(this, "carried", carried);
61894
- __publicField2(this, "count", 0);
61895
- __publicField2(this, "position");
61896
- __publicField2(this, "velocity");
61897
- __publicField2(this, "colorStart");
61898
- __publicField2(this, "colorEnd");
61899
- __publicField2(this, "life");
61900
- __publicField2(this, "maxLife");
61901
- __publicField2(this, "startSize");
61902
- __publicField2(this, "growth");
61903
- __publicField2(this, "startAlpha");
61904
- __publicField2(this, "gravity");
61905
- __publicField2(this, "drag");
61906
- __publicField2(this, "fadeIn");
61907
- __publicField2(this, "groundMode");
61908
- __publicField2(this, "decalSize");
61909
- __publicField2(this, "color");
61910
- __publicField2(this, "size");
61911
- __publicField2(this, "alpha");
61912
- __publicField2(this, "vectorArrays");
61913
- __publicField2(this, "scalarArrays");
61914
- __publicField2(this, "direction", { x: 0, y: 0, z: 0 });
61915
- __publicField2(this, "unit", { x: 0, y: 0, z: 0 });
62269
+ __publicField3(this, "capacity", capacity);
62270
+ __publicField3(this, "context", context);
62271
+ __publicField3(this, "carried", carried);
62272
+ __publicField3(this, "count", 0);
62273
+ __publicField3(this, "position");
62274
+ __publicField3(this, "velocity");
62275
+ __publicField3(this, "colorStart");
62276
+ __publicField3(this, "colorEnd");
62277
+ __publicField3(this, "life");
62278
+ __publicField3(this, "maxLife");
62279
+ __publicField3(this, "startSize");
62280
+ __publicField3(this, "growth");
62281
+ __publicField3(this, "startAlpha");
62282
+ __publicField3(this, "gravity");
62283
+ __publicField3(this, "drag");
62284
+ __publicField3(this, "fadeIn");
62285
+ __publicField3(this, "groundMode");
62286
+ __publicField3(this, "decalSize");
62287
+ __publicField3(this, "color");
62288
+ __publicField3(this, "size");
62289
+ __publicField3(this, "alpha");
62290
+ __publicField3(this, "vectorArrays");
62291
+ __publicField3(this, "scalarArrays");
62292
+ __publicField3(this, "direction", { x: 0, y: 0, z: 0 });
62293
+ __publicField3(this, "unit", { x: 0, y: 0, z: 0 });
61916
62294
  const vectorArray = () => new Float32Array(capacity * FLOATS_PER_VECTOR);
61917
62295
  const scalarArray = () => new Float32Array(capacity);
61918
62296
  this.position = vectorArray();
@@ -62060,25 +62438,25 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
62060
62438
  var TAIL_BRIGHTNESS = 0.15;
62061
62439
  var StreakPool = class {
62062
62440
  constructor(capacity, context) {
62063
- __publicField2(this, "capacity", capacity);
62064
- __publicField2(this, "context", context);
62065
- __publicField2(this, "count", 0);
62066
- __publicField2(this, "point");
62067
- __publicField2(this, "velocity");
62068
- __publicField2(this, "colorStart");
62069
- __publicField2(this, "colorEnd");
62070
- __publicField2(this, "life");
62071
- __publicField2(this, "maxLife");
62072
- __publicField2(this, "length");
62073
- __publicField2(this, "gravity");
62074
- __publicField2(this, "drag");
62075
- __publicField2(this, "groundMode");
62076
- __publicField2(this, "startAlpha");
62077
- __publicField2(this, "segment");
62078
- __publicField2(this, "segmentColor");
62079
- __publicField2(this, "vectorArrays");
62080
- __publicField2(this, "scalarArrays");
62081
- __publicField2(this, "direction", { x: 0, y: 0, z: 0 });
62441
+ __publicField3(this, "capacity", capacity);
62442
+ __publicField3(this, "context", context);
62443
+ __publicField3(this, "count", 0);
62444
+ __publicField3(this, "point");
62445
+ __publicField3(this, "velocity");
62446
+ __publicField3(this, "colorStart");
62447
+ __publicField3(this, "colorEnd");
62448
+ __publicField3(this, "life");
62449
+ __publicField3(this, "maxLife");
62450
+ __publicField3(this, "length");
62451
+ __publicField3(this, "gravity");
62452
+ __publicField3(this, "drag");
62453
+ __publicField3(this, "groundMode");
62454
+ __publicField3(this, "startAlpha");
62455
+ __publicField3(this, "segment");
62456
+ __publicField3(this, "segmentColor");
62457
+ __publicField3(this, "vectorArrays");
62458
+ __publicField3(this, "scalarArrays");
62459
+ __publicField3(this, "direction", { x: 0, y: 0, z: 0 });
62082
62460
  const vectorArray = () => new Float32Array(capacity * FLOATS_PER_VECTOR2);
62083
62461
  const scalarArray = () => new Float32Array(capacity);
62084
62462
  this.point = vectorArray();
@@ -62194,9 +62572,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
62194
62572
  var DEFAULT_LIGHT_DISTANCE = 14;
62195
62573
  var WaveRingPool = class {
62196
62574
  constructor() {
62197
- __publicField2(this, "rings", Array.from({ length: RING_CAPACITY }, () => ({ on: false, point: UP15, from: 0, to: 0, t: 0, duration: 1, color: 0, normal: UP15, hold: 0 })));
62198
- __publicField2(this, "count", 0);
62199
- __publicField2(this, "next", 0);
62575
+ __publicField3(this, "rings", Array.from({ length: RING_CAPACITY }, () => ({ on: false, point: UP15, from: 0, to: 0, t: 0, duration: 1, color: 0, normal: UP15, hold: 0 })));
62576
+ __publicField3(this, "count", 0);
62577
+ __publicField3(this, "next", 0);
62200
62578
  }
62201
62579
  add(point, from, to, duration, color2, normal, hold) {
62202
62580
  const ring22 = this.rings[this.next++ % RING_CAPACITY];
@@ -62226,13 +62604,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
62226
62604
  };
62227
62605
  var FlashLightPool = class {
62228
62606
  constructor(context) {
62229
- __publicField2(this, "context", context);
62230
- __publicField2(this, "lights", Array.from({ length: LIGHT_CAPACITY }, () => ({ x: 0, y: 0, z: 0, color: 16760944, distance: DEFAULT_LIGHT_DISTANCE, peak: 0, duration: 1, t: 0, intensity: 0, steady: false })));
62231
- __publicField2(this, "fire", [
62607
+ __publicField3(this, "context", context);
62608
+ __publicField3(this, "lights", Array.from({ length: LIGHT_CAPACITY }, () => ({ x: 0, y: 0, z: 0, color: 16760944, distance: DEFAULT_LIGHT_DISTANCE, peak: 0, duration: 1, t: 0, intensity: 0, steady: false })));
62609
+ __publicField3(this, "fire", [
62232
62610
  { x: 0, y: 0, z: 0, intensity: 0 },
62233
62611
  { x: 0, y: 0, z: 0, intensity: 0 }
62234
62612
  ]);
62235
- __publicField2(this, "next", 0);
62613
+ __publicField3(this, "next", 0);
62236
62614
  }
62237
62615
  get lit() {
62238
62616
  return this.lights.filter((light) => light.intensity > 0).length;
@@ -62283,21 +62661,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
62283
62661
  }
62284
62662
  var WorkshopEngine = class {
62285
62663
  constructor(options) {
62286
- __publicField2(this, "context");
62287
- __publicField2(this, "add");
62288
- __publicField2(this, "normal");
62289
- __publicField2(this, "streaks");
62290
- __publicField2(this, "debris");
62291
- __publicField2(this, "decals");
62292
- __publicField2(this, "rings", new WaveRingPool());
62293
- __publicField2(this, "lights");
62294
- __publicField2(this, "rain", new RainField(this));
62295
- __publicField2(this, "meshes", new MeshPool());
62296
- __publicField2(this, "screen", createScreenState());
62297
- __publicField2(this, "lens", []);
62298
- __publicField2(this, "post", {});
62299
- __publicField2(this, "placement");
62300
- __publicField2(this, "accumulators", /* @__PURE__ */ new Map());
62664
+ __publicField3(this, "context");
62665
+ __publicField3(this, "add");
62666
+ __publicField3(this, "normal");
62667
+ __publicField3(this, "streaks");
62668
+ __publicField3(this, "debris");
62669
+ __publicField3(this, "decals");
62670
+ __publicField3(this, "rings", new WaveRingPool());
62671
+ __publicField3(this, "lights");
62672
+ __publicField3(this, "rain", new RainField(this));
62673
+ __publicField3(this, "meshes", new MeshPool());
62674
+ __publicField3(this, "screen", createScreenState());
62675
+ __publicField3(this, "lens", []);
62676
+ __publicField3(this, "post", {});
62677
+ __publicField3(this, "placement");
62678
+ __publicField3(this, "accumulators", /* @__PURE__ */ new Map());
62301
62679
  const profile = options.profile ?? PROFILES.high;
62302
62680
  this.context = { random: options.random, groundAt: options.groundAt ?? workshopGround, quality: { level: 0, mult: 1 }, trace: options.trace, ...options.confiner ? { confiner: options.confiner } : {} };
62303
62681
  this.add = new SpritePool(profile.sprites.add, this.context);
@@ -64216,38 +64594,6 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
64216
64594
  };
64217
64595
  }
64218
64596
 
64219
- // src/fx/view-hold.ts
64220
- var VIEW_HOLD = {
64221
- /** The right hand's grip, from the eye. */
64222
- grip: [0.2, -0.2, -0.3],
64223
- /** A handgun's grip: higher and nearer the middle, the arms out in front. */
64224
- handgunGrip: [0.13, -0.15, -0.33],
64225
- /** A rocket launcher's grip: its tube rides on the shoulder, so the hands are higher. */
64226
- launcherGrip: [0.2, -0.14, -0.3],
64227
- /** A gun with no grip anchor: the rear of its bore, from the eye. */
64228
- rear: [0.2, -0.24, -0.12]
64229
- };
64230
- var scratch2 = { grip: null };
64231
- function placeInView(placement) {
64232
- const { THREE, hand, holder, camera: camera2, right } = placement;
64233
- holder.scale.setScalar(1);
64234
- hand.position.copy(camera2.position);
64235
- hand.quaternion.copy(camera2.quaternion);
64236
- hand.scale.setScalar(1);
64237
- holder.position.set(0, 0, 0);
64238
- hand.updateMatrixWorld(true);
64239
- if (!right) {
64240
- holder.position.set(VIEW_HOLD.rear[0], VIEW_HOLD.rear[1], VIEW_HOLD.rear[2] + placement.rear);
64241
- hand.updateMatrixWorld(true);
64242
- return;
64243
- }
64244
- scratch2.grip ?? (scratch2.grip = new THREE.Vector3());
64245
- const grip = hand.worldToLocal(right.part.localToWorld(scratch2.grip.copy(right.offset)));
64246
- const [x, y, z] = placement.kind === "handgun" ? VIEW_HOLD.handgunGrip : placement.kind === "launcher" ? VIEW_HOLD.launcherGrip : VIEW_HOLD.grip;
64247
- holder.position.set(x - grip.x, y - grip.y, z - grip.z);
64248
- hand.updateMatrixWorld(true);
64249
- }
64250
-
64251
64597
  // src/fx/heavy.ts
64252
64598
  var PI14 = Math.PI;
64253
64599
  var ROCKET_LIGHT_NAME = "rocket-light";
@@ -64632,11 +64978,12 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
64632
64978
  switch (event.type) {
64633
64979
  case "muzzle_flash":
64634
64980
  if (data.at === "ugl") {
64635
- if (parts.uglMuzzle && world.layers.muzzleFlash) effects.muzzleFlash(positionOf3(parts.uglMuzzle), root.getWorldQuaternion(new THREE.Quaternion()), UGL_FLASH);
64981
+ if (parts.uglMuzzle && world.layers.muzzleFlash) world.afterPose(() => parts.uglMuzzle && effects.muzzleFlash(positionOf3(parts.uglMuzzle), root.getWorldQuaternion(new THREE.Quaternion()), UGL_FLASH));
64636
64982
  } else if (parts.muzzle && world.layers.muzzleFlash && (session.def.action.kind === "firearm" || session.def.action.kind === "launcher")) {
64637
64983
  const profile = muzzleSmokeOf({ caliber: session.caliber, weapon: session.def, suppressed: session.suppressed });
64638
64984
  const size = session.def.action.kind === "launcher" ? 2.2 : FLASH_BY_CASE[session.caseType];
64639
- effects.muzzleFlash(positionOf3(parts.muzzle), root.getWorldQuaternion(new THREE.Quaternion()), size, profile);
64985
+ const muzzle2 = parts.muzzle;
64986
+ world.afterPose(() => effects.muzzleFlash(positionOf3(muzzle2), root.getWorldQuaternion(new THREE.Quaternion()), size, profile));
64640
64987
  }
64641
64988
  break;
64642
64989
  case "eject_casing":
@@ -65174,7 +65521,9 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
65174
65521
 
65175
65522
  // src/fx/viewmodel.ts
65176
65523
  var PI16 = Math.PI;
65177
- var HEAT_DISPLAY_MAX_FALLBACK = 120;
65524
+ var HEAT_DISPLAY_MAX_FALLBACK = 750;
65525
+ var SMOKE_WISPS_PER_SECOND = 10;
65526
+ var SMOKE_THICKNESS_GAIN = 1.7;
65178
65527
  var WALL_PULL = { margin: 0.03, max: 1.2, rate: 14, probe: 3 };
65179
65528
  var HAND_IN_VIEW = { floor: -0.88, max: 0.3, rate: 10 };
65180
65529
  var LAUNCH_VOLUME = 0.6;
@@ -65193,6 +65542,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
65193
65542
  const held = sinceShot < TRIGGER_FINGER.burstSeconds ? TRIGGER_FINGER.pulled - TRIGGER_FINGER.tremor * (0.5 + 0.5 * Math.sin(sinceShot * 220)) : 0;
65194
65543
  return Math.max(ready + (TRIGGER_FINGER.pulled - ready) * pull, held);
65195
65544
  };
65545
+ var VIEW_MOTION = { sway: 6e-3, swayMax: 0.02, swayRate: 9, bobX: 6e-3, bobY: 8e-3, run: 1.6, fullSpeed: 4, frequency: 3.2 };
65196
65546
  function createViewmodel(options) {
65197
65547
  const { THREE, scene, camera: camera2, arsenal, groundAt, audio } = options;
65198
65548
  const kit = modelKit(THREE);
@@ -65200,16 +65550,33 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
65200
65550
  const layers = options.layers ?? createLayers();
65201
65551
  const distance3 = () => options.soundDistance?.() ?? 0;
65202
65552
  const particles = createParticles(THREE, scene, groundAt, options.particleLimit);
65553
+ const spawnParticle = particles.spawn.bind(particles);
65554
+ particles.spawn = (object2, velocity, particleOptions) => {
65555
+ if (lens2) toWorldLens(camera2, object2.position, worldFovOf(), lens2.fov);
65556
+ spawnParticle(object2, velocity, particleOptions);
65557
+ };
65203
65558
  particles.onBounce = (kind, hit) => {
65204
- if (kind === "magazine") audio?.thud();
65205
- if (kind !== "casing" || !audio) return;
65206
- const caseType = hit?.object.userData["caseType"];
65559
+ if (!audio || kind !== "casing" && kind !== "magazine") return;
65207
65560
  const surface = hit ? options.surfaceAt?.(hit.object.position.x, hit.object.position.z) : void 0;
65561
+ if (kind === "magazine") {
65562
+ audio.thud({ ...surface ? { surface } : {}, ...hit ? { speed: hit.speed, bounce: hit.bounce } : {} });
65563
+ return;
65564
+ }
65565
+ const caseType = hit?.object.userData["caseType"];
65208
65566
  audio.casing({ ...caseType ? { caseType } : {}, ...surface ? { surface } : {}, ...hit ? { speed: hit.speed, bounce: hit.bounce } : {} });
65209
65567
  };
65210
65568
  if (!options.effects) warnOnce("game-weapons-three.own-effects-world", "game-weapons-three made an effects world of its own because the host lent none (options.effects); pass the host effects so the effects share one budget");
65211
65569
  const ownVfx = options.effects ? void 0 : createVfxRenderer(THREE, { scene, camera: camera2, vfx: { profile: "medium" }, ...options.lights ? { lights: options.lights } : {} });
65212
- const effects = createEffects(THREE, options.effects ?? ownVfx, random);
65570
+ const worldSink = options.effects ?? ownVfx;
65571
+ const lensSink = worldSink ? {
65572
+ play: (request) => {
65573
+ if (!lens2 || !request.point) return worldSink.play(request);
65574
+ const at3 = toWorldLens(camera2, lensPoint.set(...request.point), worldFovOf(), lens2.fov);
65575
+ return worldSink.play({ ...request, point: [at3.x, at3.y, at3.z] });
65576
+ },
65577
+ stop: (handle) => worldSink.stop(handle)
65578
+ } : void 0;
65579
+ const effects = createEffects(THREE, lensSink, random);
65213
65580
  const hand = new THREE.Group();
65214
65581
  hand.name = VIEWMODEL_NODE_NAME;
65215
65582
  scene.add(hand);
@@ -65235,6 +65602,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
65235
65602
  const rootQuaternion = new THREE.Quaternion();
65236
65603
  const muzzleAt = new THREE.Vector3();
65237
65604
  const muzzleAlong = new THREE.Vector3();
65605
+ const posed = [];
65238
65606
  const world = {
65239
65607
  kit,
65240
65608
  scene,
@@ -65248,13 +65616,17 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
65248
65616
  const played = audio?.cue(cue3, profile, lead);
65249
65617
  options.onSound?.({ weapon, cue: cue3, profile, ...played ? { played } : {} });
65250
65618
  },
65251
- schedule: (delay, seconds, step, done) => void tasks.push({ delay, seconds, elapsed: 0, step: (progress) => step(ease(progress)), done })
65619
+ afterPose: (emit2) => void posed.push(emit2),
65620
+ schedule: (delay, seconds, step, done) => void tasks.push({ delay, seconds, elapsed: 0, step: (progress) => step(ease2(progress)), done })
65252
65621
  };
65253
65622
  const heatMax = arsenal.rules.heat.displayMax || HEAT_DISPLAY_MAX_FALLBACK;
65254
65623
  const visual = arsenal.rules.heat.visual;
65255
65624
  const hasSuppressor = (parts) => parts.some((part) => arsenal.attachments.get(part.id)?.kind === "suppressor");
65256
65625
  const release = () => {
65257
65626
  if (!session) return;
65627
+ if (lens2) options.viewmodelFov?.(null);
65628
+ lens2 = null;
65629
+ lensLayer = -1;
65258
65630
  session.attachments?.dispose();
65259
65631
  discardObject3D(session.model.root);
65260
65632
  player = null;
@@ -65294,6 +65666,9 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
65294
65666
  const modelBox = new THREE.Box3().setFromObject(model.root);
65295
65667
  const length2 = modelBox.getSize(new THREE.Vector3()).x;
65296
65668
  modelRear = modelBox.min.x;
65669
+ restBox.copy(modelBox);
65670
+ lens2 = null;
65671
+ lensLayer = -1;
65297
65672
  holder.add(model.root);
65298
65673
  const caliber = caliberOf(arsenal, def);
65299
65674
  const dims = caliber?.cartridge;
@@ -65356,6 +65731,42 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
65356
65731
  let reach = 0;
65357
65732
  let pull = 0;
65358
65733
  let lift = 0;
65734
+ const restBox = new THREE.Box3();
65735
+ let lens2 = null;
65736
+ let lensLayer = -1;
65737
+ const lensPoint = new THREE.Vector3();
65738
+ const worldFovOf = () => camera2.fov ?? 72;
65739
+ const setLens = (kind) => {
65740
+ const fov = kind ? VIEW_HOLD[kind].fov : null;
65741
+ if ((lens2?.fov ?? null) !== fov) options.viewmodelFov?.(fov);
65742
+ lens2 = kind && fov !== null ? { kind, fov } : null;
65743
+ const layer3 = lens2 ? FIRST_PERSON_LAYER : 0;
65744
+ if (layer3 === lensLayer && !lens2) return;
65745
+ lensLayer = layer3;
65746
+ hand.traverse((node) => node.layers.set(layer3));
65747
+ };
65748
+ const motion = { phase: 0, swayX: 0, swayY: 0, lastYaw: Number.NaN, lastPitch: Number.NaN };
65749
+ const motionEuler = new THREE.Euler(0, 0, 0, "YXZ");
65750
+ const motionOffset = new THREE.Vector3();
65751
+ const viewMotion = (dt, aim) => {
65752
+ const moving = options.motion?.() ?? { speed: 0, running: false };
65753
+ const calm = 1 - 0.8 * Math.max(0, Math.min(1, aim));
65754
+ motionEuler.setFromQuaternion(camera2.quaternion, "YXZ");
65755
+ const turnYaw = Number.isNaN(motion.lastYaw) || dt <= 0 ? 0 : Math.atan2(Math.sin(motionEuler.y - motion.lastYaw), Math.cos(motionEuler.y - motion.lastYaw)) / dt;
65756
+ const turnPitch = Number.isNaN(motion.lastPitch) || dt <= 0 ? 0 : (motionEuler.x - motion.lastPitch) / dt;
65757
+ motion.lastYaw = motionEuler.y;
65758
+ motion.lastPitch = motionEuler.x;
65759
+ const follow = Math.min(1, dt * VIEW_MOTION.swayRate);
65760
+ motion.swayX += (Math.max(-VIEW_MOTION.swayMax, Math.min(VIEW_MOTION.swayMax, turnYaw * VIEW_MOTION.sway)) - motion.swayX) * follow;
65761
+ motion.swayY += (Math.max(-VIEW_MOTION.swayMax, Math.min(VIEW_MOTION.swayMax, -turnPitch * VIEW_MOTION.sway)) - motion.swayY) * follow;
65762
+ const stride = Math.min(1, moving.speed / VIEW_MOTION.fullSpeed) * (moving.running ? VIEW_MOTION.run : 1);
65763
+ motion.phase += dt * moving.speed * VIEW_MOTION.frequency;
65764
+ return motionOffset.set(
65765
+ (motion.swayX + Math.sin(motion.phase) * VIEW_MOTION.bobX * stride) * calm,
65766
+ (motion.swayY - Math.abs(Math.cos(motion.phase)) * VIEW_MOTION.bobY * stride) * calm,
65767
+ 0
65768
+ );
65769
+ };
65359
65770
  const ahead = new THREE.Vector3();
65360
65771
  const up = new THREE.Vector3();
65361
65772
  const seen = new THREE.Vector3();
@@ -65388,13 +65799,17 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
65388
65799
  const family = session.model.parts.family;
65389
65800
  session.holderScale = 1;
65390
65801
  if (options.firstPerson?.()) {
65391
- placeInView({ THREE, hand, holder, camera: camera2, right: hold?.right ?? null, rear: modelRear, kind: family === "pistol" || family === "revolver" ? "handgun" : family === "rocket" ? "launcher" : "long" });
65802
+ const kind = session.model.parts.carry === "hip" ? "hip" : family === "pistol" || family === "revolver" ? "handgun" : family === "rocket" ? "launcher" : "long";
65803
+ const aim = kind === "hip" ? 0 : options.aim?.() ?? 0;
65804
+ placeInView({ THREE, hand, holder, camera: camera2, right: hold?.right ?? null, box: restBox, kind, aim, offset: viewMotion(dt, aim) });
65805
+ setLens(kind);
65392
65806
  lift = 0;
65393
- pullFromWall(dt);
65807
+ pull = 0;
65394
65808
  return;
65395
65809
  }
65810
+ setLens(null);
65396
65811
  hand.scale.set(1, 1, 1);
65397
- placeOnBody({ THREE, hand, holder, frame: options.bodyHold?.() ?? eyeFrame(), rear: modelRear, lengthMetres: session.lengthMetres, handgun: family === "pistol" || family === "revolver", right: hold?.right ?? null, left: hold?.left ?? null });
65812
+ placeOnBody({ THREE, hand, holder, frame: options.bodyHold?.() ?? eyeFrame(), rear: modelRear, lengthMetres: session.lengthMetres, handgun: family === "pistol" || family === "revolver", hip: session.model.parts.carry === "hip", right: hold?.right ?? null, left: hold?.left ?? null });
65398
65813
  hand.updateMatrixWorld(true);
65399
65814
  lift += (liftToKeepInView() - lift) * Math.min(1, dt * HAND_IN_VIEW.rate);
65400
65815
  if (lift > 1e-4) hand.position.addScaledVector(up.set(0, 1, 0).applyQuaternion(camera2.quaternion), lift);
@@ -65470,6 +65885,10 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
65470
65885
  if (session) {
65471
65886
  place(dt);
65472
65887
  player?.update(dt);
65888
+ if (posed.length) {
65889
+ hand.updateMatrixWorld(true);
65890
+ for (const emit2 of posed.splice(0)) emit2();
65891
+ }
65473
65892
  const wantsMagazine = reloading || options.tool?.().reloading === true;
65474
65893
  magazineHand += ((wantsMagazine ? 1 : 0) - magazineHand) * Math.min(1, dt * HAND_HOLD.magRate);
65475
65894
  const tool2 = options.tool?.();
@@ -65485,10 +65904,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
65485
65904
  }
65486
65905
  secondsSinceShot += dt;
65487
65906
  if (tool2 && tool2.heat !== void 0 && tool2.heat * heatMax > visual.smokeFrom && secondsSinceShot < visual.smokeSeconds && session.model.parts.muzzle) {
65488
- smokeDebt += dt * (tool2.heat * heatMax - visual.smokeFrom) * 0.1;
65907
+ const smokeLevel = Math.min(1, (tool2.heat * heatMax - visual.smokeFrom) / visual.smokeSpan);
65908
+ smokeDebt += dt * smokeLevel * SMOKE_WISPS_PER_SECOND;
65489
65909
  while (smokeDebt > 1) {
65490
65910
  smokeDebt -= 1;
65491
- const k = 0.5 + (tool2.heat * heatMax - visual.smokeFrom) / 60;
65911
+ const k = 0.5 + smokeLevel * SMOKE_THICKNESS_GAIN;
65492
65912
  effects.smoke(worldPositionOf(session, session.model.parts.muzzle, new THREE.Vector3()), new THREE.Vector3((random() - 0.5) * 0.015, 0.07 + random() * 0.08, (random() - 0.5) * 0.015), 4e-3 * k, 1.2 + random() * 0.6, Math.min(0.18, 0.06 + k * 0.04));
65493
65913
  }
65494
65914
  }
@@ -65515,6 +65935,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
65515
65935
  if (!session || !mark) return null;
65516
65936
  hand.updateMatrixWorld(true);
65517
65937
  const at3 = worldPositionOf(session, mark, muzzleAt);
65938
+ if (lens2) toWorldLens(camera2, at3, worldFovOf(), lens2.fov);
65518
65939
  const along = muzzleAlong.set(1, 0, 0).applyQuaternion(session.model.root.getWorldQuaternion(rootQuaternion)).normalize();
65519
65940
  const kind = session.def.action.kind;
65520
65941
  return { position: [at3.x, at3.y, at3.z], direction: [along.x, along.y, along.z], drawsFlash: kind === "firearm" || kind === "launcher" };
@@ -65524,7 +65945,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
65524
65945
  hand.updateMatrixWorld(true);
65525
65946
  const targets = targetsOf(THREE, hold, session.model.root.getWorldQuaternion(rootQuaternion), magazineHand, hold.works ? workWeights(hold.works, player?.running ?? []) : void 0);
65526
65947
  const trigger = session.model.parts.trigger;
65527
- if (trigger) targets.fingers = { index: indexCurl(trigger.rotation.z - triggerRest, clock - lastShot) };
65948
+ if (session.model.parts.carry === "hip") targets.fingers = { index: 1 };
65949
+ else if (trigger) targets.fingers = { index: indexCurl(trigger.rotation.z - triggerRest, clock - lastShot) };
65528
65950
  return limitSupportSpan(targets);
65529
65951
  },
65530
65952
  get inHand() {
@@ -65574,6 +65996,9 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
65574
65996
  ...options.contact ? { contact: options.contact } : {},
65575
65997
  ...options.bodyHold ? { bodyHold: options.bodyHold } : {},
65576
65998
  ...options.firstPerson ? { firstPerson: options.firstPerson } : {},
65999
+ ...options.viewmodelFov ? { viewmodelFov: options.viewmodelFov } : {},
66000
+ ...options.aim ? { aim: options.aim } : {},
66001
+ ...options.motion ? { motion: options.motion } : {},
65577
66002
  ...options.effects ? { effects: options.effects } : {},
65578
66003
  ...options.flyRocket === void 0 ? {} : { flyRocket: options.flyRocket },
65579
66004
  ...options.particleLimit ? { particleLimit: options.particleLimit } : {},
@@ -66664,6 +67089,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
66664
67089
  reloadClip: "Reload of {weapon}: {kind}, clip {clip} ({seconds} s)",
66665
67090
  soundCue: "Sound: {cue} ({weapon})",
66666
67091
  cueRecorded: " \xB7 recorded",
67092
+ cueFitted: " \xB7 fitted copy of the recording",
66667
67093
  cueCarried: " \xB7 inside the next recording",
66668
67094
  gunshotSound: "Shot sound: {profile}, take {take}/4, pitch {pitch}, {space}, {distance} m{far}",
66669
67095
  gunshotRecorded: " \xB7 recorded take {takes}",
@@ -66688,7 +67114,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
66688
67114
  fuseLength: "Dynamite fuse length",
66689
67115
  fuseLengthHint: "Metres of safety fuse (131 s per metre): a long one is set down lit, for a delayed trap",
66690
67116
  layers: { muzzle_flash: "Muzzle flash", casings: "Ejected casings", magazines: "Dropped magazines" },
66691
- metrics: { casings_live: "Casings in the scene", magazines_live: "Magazines in the scene", heat: "Barrel heat" }
67117
+ metrics: { casings_live: "Casings in the scene", magazines_live: "Magazines in the scene", heat: "Barrel temperature above ambient", rounds_to_warning: "Rounds to the heat warning (cyclic rate, from cold)" }
66692
67118
  },
66693
67119
  "pt-BR": {
66694
67120
  group: "Armas",
@@ -66699,6 +67125,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
66699
67125
  reloadClip: "Recarga de {weapon}: {kind}, clipe {clip} ({seconds} s)",
66700
67126
  soundCue: "Som: {cue} ({weapon})",
66701
67127
  cueRecorded: " \xB7 grava\xE7\xE3o",
67128
+ cueFitted: " \xB7 c\xF3pia medida da grava\xE7\xE3o",
66702
67129
  cueCarried: " \xB7 dentro da grava\xE7\xE3o seguinte",
66703
67130
  gunshotSound: "Som do tiro: {profile}, tomada {take}/4, tom {pitch}, {space}, {distance} m{far}",
66704
67131
  gunshotRecorded: " \xB7 grava\xE7\xE3o, tomada {takes}",
@@ -66723,7 +67150,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
66723
67150
  fuseLength: "Pavio da dinamite",
66724
67151
  fuseLengthHint: "Metros de pavio de seguran\xE7a (131 s por metro): um longo \xE9 posto no ch\xE3o aceso, para armadilha com atraso",
66725
67152
  layers: { muzzle_flash: "Clar\xE3o do cano", casings: "C\xE1psulas ejetadas", magazines: "Pentes que caem" },
66726
- metrics: { casings_live: "C\xE1psulas na cena", magazines_live: "Pentes na cena", heat: "Calor do cano" }
67153
+ metrics: { casings_live: "C\xE1psulas na cena", magazines_live: "Pentes na cena", heat: "Temperatura do cano acima do ambiente", rounds_to_warning: "Tiros at\xE9 o aviso de calor (cad\xEAncia, a frio)" }
66727
67154
  }
66728
67155
  };
66729
67156
  var textOf = (locale) => TEXT[locale] ?? TEXT.en;
@@ -66847,7 +67274,12 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
66847
67274
  let host = null;
66848
67275
  let soundDistance = 0;
66849
67276
  let soundIndoors = false;
66850
- const heatPercent = () => Math.min(100, (host?.tool().heat ?? 0) * 100);
67277
+ const barrelCelsius = () => (host?.tool().heat ?? 0) * arsenal.rules.heat.displayMax;
67278
+ const roundsToWarning2 = () => {
67279
+ const weaponId = host?.tool().weapon;
67280
+ const rounds = weaponId ? roundsToWarningOf(arsenal, weaponId) : Infinity;
67281
+ return Number.isFinite(rounds) ? rounds : "-";
67282
+ };
66851
67283
  return {
66852
67284
  id: "weapons_area",
66853
67285
  name: text.name,
@@ -66900,7 +67332,8 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
66900
67332
  metrics: () => [
66901
67333
  { id: "casings_live", name: text.metrics.casings_live, read: () => fx?.casings ?? 0 },
66902
67334
  { id: "magazines_live", name: text.metrics.magazines_live, read: () => fx?.magazines ?? 0 },
66903
- { id: "heat", name: text.metrics.heat, unit: "%", max: 100, digits: 0, read: heatPercent },
67335
+ { id: "heat", name: text.metrics.heat, unit: "\xB0C", max: arsenal.rules.heat.displayMax, digits: 0, read: barrelCelsius },
67336
+ { id: "rounds_to_warning", name: text.metrics.rounds_to_warning, read: roundsToWarning2 },
66904
67337
  ...accessoryMetrics(accessoryText, () => host?.tool() ?? EMPTY_TOOL)
66905
67338
  ],
66906
67339
  attach(lent) {
@@ -66913,20 +67346,20 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
66913
67346
  engine: lentEngine,
66914
67347
  ...options.samples ? { samples: options.samples } : {},
66915
67348
  onGunshot: (shot, input, played) => {
66916
- const recorded = played.kind === "sample" && played.layers.length > 0 ? fill(text.gunshotRecorded, { takes: played.layers.map((layer3) => `${layer3.role} ${layer3.take + 1}`).join(", ") }) : "";
67349
+ const recorded = played.kind === "sample" && played.layers.length > 0 ? fill(text.gunshotRecorded, { takes: played.layers.map((layer3) => `${layer3.role} ${layer3.take + 1}`).join(", ") }) : played.kind === "fitted" ? text.cueFitted : "";
66917
67350
  lent.log(
66918
67351
  fill(text.gunshotSound, { profile: shot.profile, take: String(shot.take + 1), pitch: `${shot.pitch >= 1 ? "+" : ""}${((shot.pitch - 1) * 100).toFixed(1)} %`, space: text.spaces[input.space ?? "outdoor"], distance: String(Math.round(input.distance ?? 0)), far: shot.closeMix < 1 ? ` (${Math.round((1 - shot.closeMix) * 100)} % far)` : "" }) + recorded,
66919
67352
  { profile: shot.profile, take: shot.take, pitch: shot.pitch, space: input.space ?? "outdoor", distance: input.distance ?? 0, closeMix: shot.closeMix, delay: shot.delay, samples: shot.samples, played },
66920
67353
  "sound"
66921
67354
  );
66922
67355
  },
66923
- onCasing: (sound3, played) => lent.log(fill(text.casingSound, { case: sound3.kind, surface: text.surfaces[sound3.surface] }) + (played === "sample" ? text.cueRecorded : ""), { case: sound3.kind, surface: sound3.surface, sample: sound3.sample, played }, "sound")
67356
+ onCasing: (sound3, played) => lent.log(fill(text.casingSound, { case: sound3.kind, surface: text.surfaces[sound3.surface] }) + (played === "sample" ? text.cueRecorded : played === "fitted" ? text.cueFitted : ""), { case: sound3.kind, surface: sound3.surface, sample: sound3.sample, played }, "sound")
66924
67357
  });
66925
67358
  }
66926
67359
  let simulatedMs = 0;
66927
67360
  const offClock = lent.onFrame((dt) => simulatedMs += dt * 1e3);
66928
67361
  const created = createWeaponFx({
66929
- onSound: ({ weapon, cue: cue3, profile, played }) => lent.log(fill(text.soundCue, { weapon: arsenal.name(weapon), cue: text.soundCues[cue3] ?? cue3 }) + (played === "sample" ? text.cueRecorded : played === "carried" ? text.cueCarried : ""), { weapon, cue: cue3, weight: profile.weight, material: profile.material, ...played ? { played } : {} }, "sound"),
67362
+ onSound: ({ weapon, cue: cue3, profile, played }) => lent.log(fill(text.soundCue, { weapon: arsenal.name(weapon), cue: text.soundCues[cue3] ?? cue3 }) + (played === "sample" ? text.cueRecorded : played === "fitted" ? text.cueFitted : played === "carried" ? text.cueCarried : ""), { weapon, cue: cue3, weight: profile.weight, material: profile.material, ...played ? { played } : {} }, "sound"),
66930
67363
  THREE: lent.THREE,
66931
67364
  scene: lent.scene,
66932
67365
  camera: lent.camera,
@@ -66943,6 +67376,10 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
66943
67376
  contact: createLaserRaycast(lent.THREE, lent.scene, lent.camera, { now: () => simulatedMs }),
66944
67377
  ...lent.holdFrame ? { bodyHold: () => lent.holdFrame?.() ?? null } : {},
66945
67378
  firstPerson: () => lent.player().cameraMode === "first",
67379
+ // the lens of the gun in first person, how far it is brought to the eye (the right button) and how the body moves (the bob and the sway follow it)
67380
+ ...lent.setViewmodelFov ? { viewmodelFov: (degrees) => lent.setViewmodelFov?.(degrees) } : {},
67381
+ aim: () => accessories.aimProgress,
67382
+ motion: () => ({ speed: lent.player().speed, running: lent.player().running }),
66946
67383
  ...lent.effects ? { effects: lent.effects } : {},
66947
67384
  ...lent.particleLimit ? { particleLimit: lent.particleLimit } : {},
66948
67385
  ...isLightBudget(lent.lights) ? { lights: lent.lights } : {},
@@ -66976,6 +67413,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
66976
67413
  const offEvents = lent.on((event) => {
66977
67414
  worldEffects.handle(event, lent.effects);
66978
67415
  if (event.type === "explosion") {
67416
+ if (lentEngine) return;
66979
67417
  const away = Math.hypot(event.point[0] - camera2.position.x, event.point[1] - camera2.position.y, event.point[2] - camera2.position.z);
66980
67418
  ownAudio()?.play("explosion", Math.min(1, EXPLOSION_VOLUME_BASE + event.radius * EXPLOSION_VOLUME_PER_METRE), away);
66981
67419
  return;