@adatechnology/game-floorplan-three 0.9.3 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,3 +1,7 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+
1
5
  // src/test-area/module.ts
2
6
  import { DEFERRED_PRIORITY, DEFERRED_QUEUE_ID as DEFERRED_QUEUE_ID2 } from "@adatechnology/game-contracts";
3
7
  import { isLightBudget } from "@adatechnology/game-render-three";
@@ -108,6 +112,20 @@ function installKernelGeometry(K, shared) {
108
112
  const WITH_MAP = { roughcast: 1, block: 1 };
109
113
  class Accumulator {
110
114
  constructor() {
115
+ __publicField(this, "cv");
116
+ __publicField(this, "ci");
117
+ __publicField(this, "p");
118
+ __publicField(this, "n");
119
+ __publicField(this, "c");
120
+ __publicField(this, "u");
121
+ __publicField(this, "i");
122
+ __publicField(this, "nv");
123
+ __publicField(this, "ni");
124
+ __publicField(this, "lim");
125
+ __publicField(this, "cur");
126
+ __publicField(this, "piece0");
127
+ __publicField(this, "mat", "");
128
+ __publicField(this, "group", "");
111
129
  this.cv = 2048;
112
130
  this.ci = 3072;
113
131
  this.p = new Float32Array(this.cv * 3);
@@ -170,7 +188,8 @@ function installKernelGeometry(K, shared) {
170
188
  g.position.copy(u.pose0.p);
171
189
  g.quaternion.copy(u.pose0.q);
172
190
  g.scale.copy(u.pose0.s);
173
- const e = new THREE.Vector3(...a.axis || [0, 1, 0]);
191
+ const [ax, ay, az] = a.axis || [0, 1, 0];
192
+ const e = new THREE.Vector3(ax, ay, az);
174
193
  if (a.type === "swing" || a.type === "toggle") g.rotateOnAxis(e, (a.angle || 0) * t);
175
194
  else if (a.type === "slide") g.translateOnAxis(e, (a.dist || 0) * t);
176
195
  else if (a.type === "scale") {
@@ -265,7 +284,7 @@ function installKernelGeometry(K, shared) {
265
284
  }
266
285
  if (uvr) {
267
286
  let gu = G.u[k * 2], gv = G.u[k * 2 + 1];
268
- for (let r = uvr.rot | 0; r > 0; r--) {
287
+ for (let r = (uvr.rot ?? 0) | 0; r > 0; r--) {
269
288
  const t = gu;
270
289
  gu = gv;
271
290
  gv = 1 - t;
@@ -363,14 +382,13 @@ function installKernelGeometry(K, shared) {
363
382
  A.nv += n;
364
383
  }
365
384
  let bxImpl = bxBase;
366
- function bx(...a) {
367
- return bxImpl(...a);
368
- }
369
- K.getBx = () => bxImpl;
370
- K.setBx = (f) => {
385
+ const bx = (...a) => bxImpl(...a);
386
+ const getBx = () => bxImpl;
387
+ const setBx = (f) => {
371
388
  bxImpl = f;
372
389
  };
373
- 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 });
390
+ 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 };
391
+ Object.assign(K, defined);
374
392
  }
375
393
 
376
394
  // src/kernel/noise.ts
@@ -388,17 +406,20 @@ function installKernelNoise(K, _shared) {
388
406
  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;
389
407
  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)];
390
408
  }
391
- Object.assign(K, { _h2, vnoise, macroGround });
409
+ const defined = { _h2, vnoise, macroGround };
410
+ Object.assign(K, defined);
392
411
  }
393
412
 
394
413
  // src/materials/textures.ts
395
414
  function installMaterialsTextures(K, _shared) {
396
415
  const { DOC, THREE, cfg } = K;
397
416
  function texture(n, f, rep = true, rx = 1, ry = 1) {
417
+ if (!DOC) throw new Error("game-floorplan-three: the procedural textures need a document (options.document)");
398
418
  const c = DOC.createElement("canvas");
399
419
  c.width = n;
400
420
  c.height = n;
401
421
  const g = c.getContext("2d");
422
+ if (!g) throw new Error("game-floorplan-three: no 2d canvas context");
402
423
  f(g, n);
403
424
  const t = new THREE.CanvasTexture(c);
404
425
  t.colorSpace = THREE.SRGBColorSpace;
@@ -517,10 +538,16 @@ function installMaterialsTextures(K, _shared) {
517
538
  const TEX = {};
518
539
  for (const k of Object.keys(TEXGEN)) TEX[k] = cfg.textures && cfg.textures[k] || TEXGEN[k]();
519
540
  const ATLAS = {};
520
- Object.assign(K, { texture, rngTexture, TEXGEN, TEX, ATLAS });
541
+ const defined = { texture, rngTexture, TEXGEN, TEX, ATLAS };
542
+ Object.assign(K, defined);
521
543
  }
522
544
 
523
545
  // src/materials/materials.ts
546
+ function context2d(c) {
547
+ const g = c.getContext("2d");
548
+ if (!g) throw new Error("game-floorplan-three: no 2d canvas context");
549
+ return g;
550
+ }
524
551
  function installMaterialsMaterials(K, _shared) {
525
552
  const { THREE, cfg, ATLAS, TEX, rngTexture } = K;
526
553
  function createMaterials(props) {
@@ -532,7 +559,7 @@ function installMaterialsMaterials(K, _shared) {
532
559
  return t;
533
560
  };
534
561
  if (!(cfg.atlas && cfg.atlas.floorKind)) {
535
- const pc = props.atlas("floor").canvas, g = pc.getContext("2d");
562
+ const pc = props.atlas("floor").canvas, g = context2d(pc);
536
563
  for (const c of [0, 1]) {
537
564
  g.save();
538
565
  g.globalCompositeOperation = "screen";
@@ -547,7 +574,7 @@ function installMaterialsMaterials(K, _shared) {
547
574
  g.restore();
548
575
  }
549
576
  if (!(cfg.atlas && cfg.atlas.floorKind)) {
550
- const pc = props.atlas("floor").canvas, g = pc.getContext("2d");
577
+ const pc = props.atlas("floor").canvas, g = context2d(pc);
551
578
  g.save();
552
579
  g.fillStyle = "rgba(128,92,62,0.52)";
553
580
  g.fillRect(256, 256, 256, 256);
@@ -644,7 +671,8 @@ function installMaterialsMaterials(K, _shared) {
644
671
  }
645
672
  const ORDER = { glass: 3, water: 2, screen: 3, building: 4 };
646
673
  const NO_SHADOW = /* @__PURE__ */ new Set(["dirt", "glass", "water", "screen", "building", "picture", "floor", "emissive"]);
647
- Object.assign(K, { createMaterials, antiTile, dirtMaterial, CLOTHES_UNIFORMS, clothesMaterial, ORDER, NO_SHADOW });
674
+ const defined = { createMaterials, antiTile, dirtMaterial, CLOTHES_UNIFORMS, clothesMaterial, ORDER, NO_SHADOW };
675
+ Object.assign(K, defined);
648
676
  }
649
677
 
650
678
  // src/kernel/close-scene.ts
@@ -655,15 +683,18 @@ function installKernelCloseScene(K, shared) {
655
683
  const assembleVegetation = (...a) => K.assembleVegetation(...a);
656
684
  function markMesh(m, A) {
657
685
  const L = A.lim, fx = [];
686
+ const pieces = shared.ctx.pieces;
658
687
  for (let k = 0; k < L.length; k++) {
659
- if (!L[k].pc) continue;
660
- const v1 = k + 1 < L.length ? L[k + 1].v : A.nv, i1 = k + 1 < L.length ? L[k + 1].i : A.ni;
661
- if (v1 > L[k].v) fx.push({ id: L[k].pc.id, v0: L[k].v, v1, i0: L[k].i, i1 });
688
+ const lim = L[k], pc = lim.pc;
689
+ if (!pc) continue;
690
+ const next = L[k + 1];
691
+ const v1 = next ? next.v : A.nv, i1 = next ? next.i : A.ni;
692
+ if (v1 > lim.v) fx.push({ id: pc.id, v0: lim.v, v1, i0: lim.i, i1 });
662
693
  }
663
694
  if (!fx.length) return;
664
695
  const u = m.userData, ids = [...new Set(fx.map((f) => f.id))], weight = {};
665
696
  for (const f of fx) {
666
- const mt = shared.ctx.pieces.get(f.id).mat;
697
+ const mt = pieces.get(f.id).mat;
667
698
  weight[mt] = (weight[mt] || 0) + f.v1 - f.v0;
668
699
  }
669
700
  u.ranges = fx;
@@ -671,7 +702,7 @@ function installKernelCloseScene(K, shared) {
671
702
  u.destructionMaterial = Object.keys(weight).sort((a, b) => weight[b] - weight[a])[0];
672
703
  if (ids.length === 1) {
673
704
  u.destructionPart = ids[0];
674
- const pc = shared.ctx.pieces.get(ids[0]);
705
+ const pc = pieces.get(ids[0]);
675
706
  if (pc.role) u.structuralRole = pc.role;
676
707
  }
677
708
  }
@@ -722,7 +753,8 @@ function installKernelCloseScene(K, shared) {
722
753
  assembleVegetation(groups);
723
754
  return groups;
724
755
  }
725
- Object.assign(K, { markMesh, closeScene });
756
+ const defined = { markMesh, closeScene };
757
+ Object.assign(K, defined);
726
758
  }
727
759
 
728
760
  // src/house/helpers.ts
@@ -760,8 +792,14 @@ function installHouseHelpers(K, shared) {
760
792
  for (const h of holes) L = L.flatMap((r) => subRect(r, h));
761
793
  return L;
762
794
  }
763
- const wallColor = (c) => c && c.color && colorOf(c.color.wall) != null ? colorOf(c.color.wall) : 14999768;
764
- const floorColor = (c) => c && c.color && colorOf(c.color.floor) != null ? colorOf(c.color.floor) : 11577496;
795
+ const wallColor = (c) => {
796
+ const k = c && c.color ? colorOf(c.color.wall) : null;
797
+ return k != null ? k : 14999768;
798
+ };
799
+ const floorColor = (c) => {
800
+ const k = c && c.color ? colorOf(c.color.floor) : null;
801
+ return k != null ? k : 11577496;
802
+ };
765
803
  function stairFootprint(m) {
766
804
  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]);
767
805
  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]))];
@@ -772,12 +810,14 @@ function installHouseHelpers(K, shared) {
772
810
  const pitch = A[f + 1].y0 - A[f].y0;
773
811
  return h > pitch && h - pitch <= 0.45 ? pitch : h;
774
812
  }
775
- Object.assign(K, { OPEN_ROOM_TYPES: OPEN_ROOM_TYPES2, NO_CEILING, OPEN_AREA, EPS, Y0, colorOf, rectsOf: rectsOf2, roomAt, subRect, subRects, wallColor, floorColor, stairFootprint, effectiveHeight });
813
+ const defined = { OPEN_ROOM_TYPES: OPEN_ROOM_TYPES2, NO_CEILING, OPEN_AREA, EPS, Y0, colorOf, rectsOf: rectsOf2, roomAt, subRect, subRects, wallColor, floorColor, stairFootprint, effectiveHeight };
814
+ Object.assign(K, defined);
776
815
  }
777
816
 
778
817
  // src/house/walls.ts
779
818
  function installHouseWalls(K, shared) {
780
819
  const { EPS, Y0, boxC, bx, cursor, effectiveHeight, pieceRecord, structurePiece, wallColor } = K;
820
+ const sh = (...a) => K.sh(...a);
781
821
  function wallBox(alongU, L, a, b, ya, yb, th, cL, cH, mL, mH) {
782
822
  if (yb - ya < 1e-4 || b - a < 1e-4) return;
783
823
  if (alongU) {
@@ -821,8 +861,9 @@ function installHouseWalls(K, shared) {
821
861
  function walls() {
822
862
  const R = shared.ctx.r, cut = shared.ctx.cut, nA = R.floors.length, vMin = Math.min(...R.walls.map((w) => w.axis === "u" ? w.v0 : Math.min(w.v0, w.v1)));
823
863
  const corners = /* @__PURE__ */ new Map();
864
+ const looks = /* @__PURE__ */ new Map();
824
865
  for (const w of R.walls) {
825
- const f = w.floor;
866
+ const f = w.floor, colliders = shared.ctx.colliders;
826
867
  cursor.group = "f" + f;
827
868
  cursor.pc = pieceOf(w);
828
869
  const y0 = Y0(f), pitch = f + 1 < nA ? Y0(f + 1) - y0 : Infinity, th = w.thickness || 0.15, alongU = w.axis === "u";
@@ -830,7 +871,11 @@ function installHouseWalls(K, shared) {
830
871
  const hh = cut ? Math.min(h, 1.2) : h, L = alongU ? w.v0 : w.u0, s0 = Math.min(alongU ? w.u0 : w.v0, alongU ? w.u1 : w.v1), s1 = Math.max(alongU ? w.u0 : w.v0, alongU ? w.u1 : w.v1);
831
872
  const front = alongU && Math.abs(L - vMin) < 0.05;
832
873
  const sideL = sideOf(w.sides[0], front), sideH = sideOf(w.sides[1], front);
833
- shared.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 });
874
+ if (w.id) {
875
+ const face = sideL.exterior ? sideL : sideH;
876
+ looks.set(w.id, { mat: face.mat, color: face.color, top: y0 + hh });
877
+ }
878
+ 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 });
834
879
  if (w.type === "railing") {
835
880
  const c0 = shared.ctx.colors.metal != null ? shared.ctx.colors.metal : 9080466;
836
881
  const sx = alongU ? 1 : 0, sz = alongU ? 0 : 1, len = s1 - s0, n = Math.max(1, Math.round(len / 1.4));
@@ -876,8 +921,28 @@ function installHouseWalls(K, shared) {
876
921
  cursor.group = "f" + e.f;
877
922
  bx(e.color.mat, e.pu - e.th / 2, e.y0, e.pv - e.th / 2, e.pu + e.th / 2, e.y0 + e.hh, e.pv + e.th / 2, e.color.color);
878
923
  }
924
+ if (shared.ctx.showPillars) wallPillars(looks);
925
+ }
926
+ const PILLAR_IN_WALL = /^(wall_column_|column_\d|jamb_column_)/;
927
+ const wallOf = (pillar, parts) => {
928
+ const u = (pillar.aabb[0] + pillar.aabb[2]) / 2, v = (pillar.aabb[1] + pillar.aabb[3]) / 2;
929
+ return parts.find((q) => (q.role === "wall" || q.role === "partition") && q.assembly !== void 0 && q.floor === pillar.floor && u >= q.aabb[0] - 1e-3 && u <= q.aabb[2] + 1e-3 && v >= q.aabb[1] - 1e-3 && v <= q.aabb[3] + 1e-3);
930
+ };
931
+ function wallPillars(looks) {
932
+ const parts = Object.values(shared.ctx.structureIndex);
933
+ for (const e of parts) {
934
+ if (e.role !== "column" || !PILLAR_IN_WALL.test(e.id)) continue;
935
+ const host = wallOf(e, parts);
936
+ const look = host && looks.get(host.id);
937
+ if (!host || !look) continue;
938
+ cursor.group = "f" + e.floor;
939
+ cursor.pc = structurePiece(host.id);
940
+ bx(look.mat, e.aabb[0], e.y0, e.aabb[1], e.aabb[2], Math.min(e.y1, look.top), e.aabb[3], sh(look.color != null ? look.color : 15262420, 0.93));
941
+ }
942
+ cursor.pc = null;
879
943
  }
880
- Object.assign(K, { wallBox, sideOf, pieceOf, nearestWall, walls });
944
+ const defined = { wallBox, sideOf, pieceOf, nearestWall, walls, wallPillars };
945
+ Object.assign(K, defined);
881
946
  }
882
947
 
883
948
  // src/house/doors.ts
@@ -896,7 +961,7 @@ function installHouseDoors(K, shared) {
896
961
  }
897
962
  shared.doorState = /* @__PURE__ */ new Map();
898
963
  function doors() {
899
- shared.ctx.leaves = [];
964
+ const leaves = shared.ctx.leaves = [], doorState = shared.doorState, colliders = shared.ctx.colliders;
900
965
  const R = shared.ctx.r, cut = shared.ctx.cut, C = shared.ctx.colors, wood = C.wood != null ? C.wood : 8016948, frame = sh(wood, 0.55);
901
966
  for (const p of R.doors) {
902
967
  const f = p.floor;
@@ -927,21 +992,21 @@ function installHouseDoors(K, shared) {
927
992
  }
928
993
  const leaf = (u0, u1, y_0, y_1, tt, color, mat = "wood") => alongU ? bx(mat, u0, y0 + y_0, L - tt / 2, u1, y0 + y_1, L + tt / 2, color) : bx(mat, L - tt / 2, y0 + y_0, u0, L + tt / 2, y0 + y_1, u1, color);
929
994
  const extC = wood;
930
- const open0 = p.blocked ? false : shared.doorState.has(p.id) ? shared.doorState.get(p.id) : !!p.open;
931
- shared.doorState.set(p.id, open0);
995
+ const open0 = p.blocked ? false : doorState.has(p.id) ? doorState.get(p.id) === true : !!p.open;
996
+ doorState.set(p.id, open0);
932
997
  const dc = alongU ? [p.at, L] : [L, p.at];
933
- 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 };
998
+ 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 };
934
999
  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 };
935
- shared.ctx.colliders.push(colR);
1000
+ colliders.push(colR);
936
1001
  fo.col = colR;
937
1002
  const leafBox = (hu, d0, d1, y_0, y_1, tt, color, mat) => alongU ? bx(mat, d0, y_0, -tt / 2, d1, y_1, tt / 2, color) : bx(mat, -tt / 2, y_0, d0, tt / 2, y_1, d1, color);
938
- const newGroup = (k, hu, topY) => {
1003
+ const newGroup2 = (k, hu, topY) => {
939
1004
  cursor.group = "dyn:" + p.id + ":" + k;
940
1005
  fo.groups.push({ name: cursor.group, pos: alongU ? [hu, topY != null ? y0 + topY : y0, L] : [L, topY != null ? y0 + topY : y0, hu] });
941
1006
  };
942
1007
  if (p.model === "steel") {
943
- const light = [14276044, 13223615, 14999766], pal = ((R.seed | 0) + p.id.length * 7) % 4, color = pal === 3 ? wood : light[pal], mid = (a + b) / 2;
944
- newGroup(0, mid, visH);
1008
+ const light = [14276044, 13223615, 14999766], pal = ((Number(R.seed) | 0) + p.id.length * 7) % 4, color = pal === 3 ? wood : light[pal], mid = (a + b) / 2;
1009
+ newGroup2(0, mid, visH);
945
1010
  const la = a + jw - mid, lb = b - jw - mid, nSec = Math.max(4, Math.round(visH / 0.5)), hs = visH / nSec, grv = sh(color, 0.55);
946
1011
  leafBox(0, la, lb, -visH, 0, 0.05, color, "metal");
947
1012
  for (let k = 1; k < nSec; k++) leafBox(0, la, lb, -k * hs - 0.012, -k * hs + 0.012, 0.07, grv, "metal");
@@ -956,7 +1021,7 @@ function installHouseDoors(K, shared) {
956
1021
  for (let k = 0; k < nf; k++) {
957
1022
  const u0 = nf === 2 ? k ? (aa + bb) / 2 : aa : aa, u1 = nf === 2 ? k ? bb : (aa + bb) / 2 : bb, color = p.exterior ? extC : wood;
958
1023
  const hingeAt = nf === 2 ? k ? u1 : u0 : p.hinge === "end" ? u1 : u0, dir = hingeAt === u0 ? 1 : -1, len = u1 - u0;
959
- newGroup(k, hingeAt);
1024
+ newGroup2(k, hingeAt);
960
1025
  const d0 = dir > 0 ? 5e-3 : -len + 5e-3, d1 = dir > 0 ? len - 5e-3 : -5e-3;
961
1026
  leafBox(hingeAt, d0, d1, 0, visH, 0.04, color, PMAT);
962
1027
  {
@@ -992,7 +1057,7 @@ function installHouseDoors(K, shared) {
992
1057
  fo.rot = Math.atan2(n[0] * A[1] - n[1] * A[0], A[0] * n[0] + A[1] * n[1]);
993
1058
  }
994
1059
  }
995
- shared.ctx.leaves.push(fo);
1060
+ leaves.push(fo);
996
1061
  cursor.group = "f" + f;
997
1062
  if (p.blocked) {
998
1063
  part("window_boards", [0, 0, 0], () => {
@@ -1020,11 +1085,12 @@ function installHouseDoors(K, shared) {
1020
1085
  }
1021
1086
  }
1022
1087
  }, { id: "boards:" + p.id }, "f" + f);
1023
- shared.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 });
1088
+ 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 });
1024
1089
  }
1025
1090
  }
1026
1091
  }
1027
- Object.assign(K, { doorLineSides, doors });
1092
+ const defined = { doorLineSides, doors };
1093
+ Object.assign(K, defined);
1028
1094
  }
1029
1095
 
1030
1096
  // src/house/windows.ts
@@ -1084,7 +1150,8 @@ function installHouseWindows(K, shared) {
1084
1150
  }
1085
1151
  }
1086
1152
  }
1087
- Object.assign(K, { FRAME_COLORS, SILL_COLORS, windows });
1153
+ const defined = { FRAME_COLORS, SILL_COLORS, windows };
1154
+ Object.assign(K, defined);
1088
1155
  }
1089
1156
 
1090
1157
  // src/house/floors.ts
@@ -1094,7 +1161,7 @@ function installHouseFloors(K, shared) {
1094
1161
  if (shared.ctx._flights && shared.ctx._flights.r === shared.ctx.r) return shared.ctx._flights.l;
1095
1162
  const R = shared.ctx.r, mp = /* @__PURE__ */ new Map();
1096
1163
  for (const m of R.items) {
1097
- if (m.type !== "stairs" || !m.link) continue;
1164
+ if (m.type !== "stairs" || !m.link || typeof m.link !== "object") continue;
1098
1165
  const k = [m.link.from, m.link.to, m.x.toFixed(2), m.z.toFixed(2), (m.ry || 0).toFixed(2)].join("|");
1099
1166
  if (!mp.has(k)) mp.set(k, { m, from: m.link.from, to: m.link.to, rect: stairFootprint(m) });
1100
1167
  }
@@ -1113,7 +1180,7 @@ function installHouseFloors(K, shared) {
1113
1180
  }
1114
1181
  const panelRects = (p) => p.footprint && p.footprint.length ? p.footprint : [p.aabb];
1115
1182
  function tilesOf(parent, rc) {
1116
- const ps = parent && shared.ctx.panelsOf && shared.ctx.panelsOf.get(parent);
1183
+ const ps = parent ? shared.ctx.panelsOf && shared.ctx.panelsOf.get(parent) : void 0;
1117
1184
  if (!ps) return [[parent ? structurePiece(parent) : null, rc]];
1118
1185
  const out = [], taken = [];
1119
1186
  for (const p of ps) for (const q of panelRects(p)) {
@@ -1177,13 +1244,12 @@ function installHouseStairs(K, shared) {
1177
1244
  const { rectsOf: rectsOf2, Y0, boxC, bx, cursor, flights, stairFootprint, structurePiece } = K;
1178
1245
  const sh = (...a) => K.sh(...a);
1179
1246
  function buildStairs() {
1180
- const R = shared.ctx.r;
1181
- shared.ctx.stairs = [];
1247
+ const R = shared.ctx.r, stairs = shared.ctx.stairs = [];
1182
1248
  for (const vo of flights()) {
1183
1249
  const m = vo.m, f = vo.from, Dr = m.d - (vo.LP || 0);
1184
1250
  cursor.group = "f" + f;
1185
1251
  cursor.pc = structurePiece("stairs_" + vo.from + "_" + vo.to);
1186
- 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);
1252
+ 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);
1187
1253
  const wood = shared.ctx.colors.wood != null ? shared.ctx.colors.wood : 9071176, under = sh(wood, 0.7);
1188
1254
  const P = (lx, lz) => [m.x + lx * c + lz * s, m.z - lx * s + lz * c];
1189
1255
  const boxL = (mat, lx, y, lz, w, h, d, color, rx = 0) => {
@@ -1206,7 +1272,7 @@ function installHouseStairs(K, shared) {
1206
1272
  }
1207
1273
  }
1208
1274
  cursor.pc = null;
1209
- shared.ctx.stairs.push({ m, f, to: vo.to, y0, H, rect: stairFootprint(m), landingPoint: (vo.LP || 0) / m.d });
1275
+ stairs.push({ m, f, to: vo.to, y0, H, rect: stairFootprint(m), landingPoint: (vo.LP || 0) / m.d });
1210
1276
  }
1211
1277
  }
1212
1278
  function elevator() {
@@ -1223,7 +1289,8 @@ function installHouseStairs(K, shared) {
1223
1289
  }
1224
1290
  }
1225
1291
  }
1226
- Object.assign(K, { buildStairs, elevator });
1292
+ const defined = { buildStairs, elevator };
1293
+ Object.assign(K, defined);
1227
1294
  }
1228
1295
 
1229
1296
  // src/lights/fixtures.ts
@@ -1263,14 +1330,15 @@ function installLightsFixtures(K, shared) {
1263
1330
  c: (mat, x, y, z, r, h, color, seg) => api.cylinder(M, mat, x, y0 + y, z, r, h, color, 0, 0, seg),
1264
1331
  e: (mat, x, y, z, r, h, color) => api.cylinder(M, mat, x, y0 + y - h / 2, z, r, h, color, 0, 0, "sphere"),
1265
1332
  t(mat, p, q, r, color, seg) {
1333
+ const tc = color ?? NaN;
1266
1334
  const dx = q[0] - p[0], dy = q[1] - p[1], dz = q[2] - p[2], L = Math.hypot(dx, dy, dz);
1267
1335
  if (L < 1e-5) return;
1268
1336
  const nx = dx / L, ny = dy / L, nz = dz / L;
1269
1337
  if (Math.abs(nx) < 1e-4 && Math.abs(nz) < 1e-4) {
1270
- api.cylinder(M, mat, p[0], y0 + Math.min(p[1], q[1]), p[2], r, L, color, 0, 0, seg);
1338
+ api.cylinder(M, mat, p[0], y0 + Math.min(p[1], q[1]), p[2], r, L, tc, 0, 0, seg);
1271
1339
  return;
1272
1340
  }
1273
- api.cylinder(M, mat, (p[0] + q[0]) / 2, y0 + (p[1] + q[1]) / 2, (p[2] + q[2]) / 2, r, L, color, Math.atan2(nz, ny), -Math.asin(nx), seg);
1341
+ 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), seg);
1274
1342
  },
1275
1343
  polyFace: (mat, pts, color, hint) => polyFace(mat, pts.map((p) => W(p[0], p[1], p[2])), color, hint && [hint[0] * c + hint[2] * s, hint[1], -hint[0] * s + hint[2] * c]),
1276
1344
  part(type, lx, ly, lz, fn, meta) {
@@ -1449,7 +1517,8 @@ function installLightsFixtures(K, shared) {
1449
1517
  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 });
1450
1518
  }
1451
1519
  }
1452
- Object.assign(K, { hashString, rngString, SEED, STYLE, kit2, arcPoints, TEMP_WARM, TEMP_NEUTRAL, TEMP_COOL, colorTemperature, lightStyle, ceilingLamp, tableLamp, floorLamp, sconce, outdoorLamp, lightSwitch });
1520
+ const defined = { hashString, rngString, SEED, STYLE, kit2, arcPoints, TEMP_WARM, TEMP_NEUTRAL, TEMP_COOL, colorTemperature, lightStyle, ceilingLamp, tableLamp, floorLamp, sconce, outdoorLamp, lightSwitch };
1521
+ Object.assign(K, defined);
1453
1522
  }
1454
1523
 
1455
1524
  // src/lights/decor.ts
@@ -1516,7 +1585,8 @@ function installLightsDecor(K, shared) {
1516
1585
  void sd;
1517
1586
  }
1518
1587
  }
1519
- Object.assign(K, { decorLights });
1588
+ const defined = { decorLights };
1589
+ Object.assign(K, defined);
1520
1590
  }
1521
1591
 
1522
1592
  // src/lot/terrain.ts
@@ -1569,7 +1639,8 @@ function installLotTerrain(K, shared) {
1569
1639
  if (x < b) out.push([x, b]);
1570
1640
  return out.filter((q) => q[1] - q[0] > 0.3);
1571
1641
  }
1572
- Object.assign(K, { terrain, freeSpans });
1642
+ const defined = { terrain, freeSpans };
1643
+ Object.assign(K, defined);
1573
1644
  }
1574
1645
 
1575
1646
  // src/lot/perimeter.ts
@@ -1589,7 +1660,7 @@ function installLotPerimeter(K, shared) {
1589
1660
  for (const s of lt.perimeter) {
1590
1661
  const alongU = Math.abs(s.v1 - s.v0) < EPS, 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);
1591
1662
  cursor.pc = pieceRecord("lot_wall:" + s.id, s.type === "wall" ? "brick" : s.type === "fence" ? "wood_soft" : "steel", null, { tags: ["wall"] });
1592
- const th = s.thickness || 0.15, h = s.height, color = colorOf(s.color) != null ? colorOf(s.color) : C.wall || 12104874, len = b - a;
1663
+ const th = s.thickness || 0.15, h = s.height, color = colorOf(s.color) ?? (C.wall || 12104874), len = b - a;
1593
1664
  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);
1594
1665
  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 };
1595
1666
  shared.ctx.colliders.push(col);
@@ -1663,7 +1734,8 @@ function installLotPerimeter(K, shared) {
1663
1734
  }
1664
1735
  }
1665
1736
  }
1666
- Object.assign(K, { perimeter, paths });
1737
+ const defined = { perimeter, paths };
1738
+ Object.assign(K, defined);
1667
1739
  }
1668
1740
 
1669
1741
  // src/lot/gates.ts
@@ -1679,7 +1751,7 @@ function installLotGates(K, shared) {
1679
1751
  cursor.group = "lot";
1680
1752
  const structure = R.style, auto = structure !== "budget", wall = colorOf("wall") || 12104874, cu = (lt.rect[0] + lt.rect[2]) / 2, cz = (lt.rect[1] + lt.rect[3]) / 2;
1681
1753
  for (const g of lt.gates) {
1682
- 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";
1754
+ 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";
1683
1755
  const sd = cz - v >= 0 ? 1 : -1;
1684
1756
  const pil = (x0, x1, high) => {
1685
1757
  bx("plaster", x0, 0, v - 0.13, x1, high, v + 0.13, wall);
@@ -1751,7 +1823,8 @@ function installLotGates(K, shared) {
1751
1823
  if (!g.open || ped) shared.ctx.colliders.push({ type: "gate", f: -1, x0: a, z0: v - 0.1, x1: b, z1: v + 0.1 });
1752
1824
  }
1753
1825
  }
1754
- Object.assign(K, { slideDirection, gates });
1826
+ const defined = { slideDirection, gates };
1827
+ Object.assign(K, defined);
1755
1828
  }
1756
1829
 
1757
1830
  // src/roof/roofs.ts
@@ -1765,13 +1838,13 @@ function installRoofRoofs(K, shared) {
1765
1838
  function roofs() {
1766
1839
  const R = shared.ctx.r, F = R.facade, C = shared.ctx.colors, nA = R.floors.length, type = F.roof;
1767
1840
  cursor.group = "roof";
1768
- shared.ctx.roofRects = [];
1769
- shared.ctx.gutter = gutterConfig();
1770
- shared.ctx.gutter.ncond = 0;
1771
- shared.ctx.gutter.nbuz = 0;
1772
- shared.ctx.gutter.bz = /* @__PURE__ */ new Set();
1841
+ const roofRects = shared.ctx.roofRects = [];
1842
+ const G = shared.ctx.gutter = gutterConfig();
1843
+ G.ncond = 0;
1844
+ G.nbuz = 0;
1845
+ G.bz = /* @__PURE__ */ new Set();
1773
1846
  shared.ctx.gutterInfo = { gutters: [], downpipes: [], drains: [] };
1774
- const roofColor = C.roof != null ? C.roof : 11031610, gable = (R.seed | 0) % 2 === 0;
1847
+ const roofColor = C.roof != null ? C.roof : 11031610, gable = (Number(R.seed) | 0) % 2 === 0;
1775
1848
  for (let f = 0; f < nA; f++) {
1776
1849
  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);
1777
1850
  if (!rs.length) continue;
@@ -1793,7 +1866,7 @@ function installRoofRoofs(K, shared) {
1793
1866
  return Y0(f) + Math.max(...cs.map((c) => c.ceiling)) + 0.2;
1794
1867
  };
1795
1868
  if (type === "slab") {
1796
- for (let j = 0; j < nz; j++) for (let i = 0; i < nx; i++) if (O(j, i)) shared.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 });
1869
+ 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 });
1797
1870
  slabs(f, xs, zs, O, U, nx, nz, full, pe, C);
1798
1871
  cursor.pc = null;
1799
1872
  continue;
@@ -1816,16 +1889,16 @@ function installRoofRoofs(K, shared) {
1816
1889
  if (U(q.j0 - 1, i)) touchesU[1] = 1;
1817
1890
  if (U(q.j1 + 1, i)) touchesU[3] = 1;
1818
1891
  }
1819
- shared.ctx.roofRects.push({ f, r: [x0, z0, x1, z1], touchesU });
1892
+ roofRects.push({ f, r: [x0, z0, x1, z1], touchesU });
1820
1893
  const ybq = pe(x0, z0, x1, z1);
1821
1894
  roofRect(type, x0, z0, x1, z1, ybq, roofColor, gable && single, F, touchesU);
1822
1895
  cursor.pc = null;
1823
- if (shared.ctx.gutter.on) gutter(type, f, x0, z0, x1, z1, ybq, touchesU);
1896
+ if (G.on) gutter(type, f, x0, z0, x1, z1, ybq, touchesU);
1824
1897
  }
1825
1898
  }
1826
1899
  for (const e of shared.ctx.outbuildingList || []) {
1827
1900
  const [x0, z0, x1, z1] = e.aabb, yb = Y0(0) + (e.ceiling || 2.6) + 0.2;
1828
- shared.ctx.roofRects.push({ f: 0, r: [x0, z0, x1, z1], outbuilding: e.id });
1901
+ roofRects.push({ f: 0, r: [x0, z0, x1, z1], outbuilding: e.id });
1829
1902
  if (type === "slab") {
1830
1903
  const c = C.facade != null ? C.facade : 14209216;
1831
1904
  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));
@@ -1836,13 +1909,15 @@ function installRoofRoofs(K, shared) {
1836
1909
  roofRect(type, x0, z0, x1, z1, yb, roofColor, true, F, [0, 0, 0, 0]);
1837
1910
  cursor.pc = null;
1838
1911
  shared.ctx.noPiece = false;
1839
- if (shared.ctx.gutter.on) gutter(type, 0, x0, z0, x1, z1, yb, [0, 0, 0, 0]);
1912
+ if (G.on) gutter(type, 0, x0, z0, x1, z1, yb, [0, 0, 0, 0]);
1840
1913
  }
1841
1914
  }
1842
- Object.assign(K, { roofs });
1915
+ const defined = { roofs };
1916
+ Object.assign(K, defined);
1843
1917
  }
1844
1918
 
1845
1919
  // src/roof/gutters.ts
1920
+ var paletteMeta = (colors) => colors.meta;
1846
1921
  function installRoofGutters(K, shared) {
1847
1922
  const { boxC, bx, cursor, roomAt } = K;
1848
1923
  const sh = (...a) => K.sh(...a);
@@ -1859,7 +1934,7 @@ function installRoofGutters(K, shared) {
1859
1934
  const draw = rnd() < p, light = rnd() < 0.6;
1860
1935
  void draw;
1861
1936
  const on = true;
1862
- return { on, rnd, color: high ? 3816770 : light ? 15527921 : 10857392, bad: (shared.ctx.colors.meta && shared.ctx.colors.meta.state) === "abandoned" || R.state === "abandoned", fallback: false };
1937
+ return { on, rnd, color: high ? 3816770 : light ? 15527921 : 10857392, bad: paletteMeta(shared.ctx.colors)?.state === "abandoned" || R.state === "abandoned", fallback: false };
1863
1938
  }
1864
1939
  function gutter(type, f, X0, Z0, X1, Z1, yb, touchesU) {
1865
1940
  const G = shared.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;
@@ -1901,7 +1976,7 @@ function installRoofGutters(K, shared) {
1901
1976
  const px = cx + sx * 0.06, pz = cz + sz * 0.06;
1902
1977
  if (!freeAt(px, pz, sx, sz)) return false;
1903
1978
  const floats = G.bad && G.ncond === 1, yt = yb - 0.1, ybx = floats ? 0.7 : 0.04;
1904
- G.ncond++;
1979
+ G.ncond = (G.ncond ?? 0) + 1;
1905
1980
  if (run2 >= 2) boxC("plain", (sides[run2][4] + px) / 2, yt, pz, Math.abs(sides[run2][4] - px), 0.07, 0.07, c);
1906
1981
  else boxC("plain", px, yt, (sides[run2][4] + pz) / 2, 0.07, 0.07, Math.abs(sides[run2][4] - pz), c);
1907
1982
  boxC("plain", px, (ybx + yt) / 2, pz, 0.08, yt - ybx, 0.08, c);
@@ -1935,7 +2010,7 @@ function installRoofGutters(K, shared) {
1935
2010
  function drain(x, z, px, pz, c) {
1936
2011
  const g0 = cursor.group;
1937
2012
  cursor.group = "f0";
1938
- 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));
2013
+ 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));
1939
2014
  const t = 0.045;
1940
2015
  bx("plain", x - 0.12, 0, z - 0.12, x + 0.12, t - 6e-3, z + 0.12, 12170668);
1941
2016
  bx("metal", x - 0.11, t, z - 0.11, x + 0.11, t + 0.012, z + 0.11, 5922145);
@@ -1946,7 +2021,8 @@ function installRoofGutters(K, shared) {
1946
2021
  bx("metal", x - 0.085, t + 0.012, z - 6e-3, x + 0.085, t + 0.02, z + 6e-3, 9080466);
1947
2022
  cursor.group = g0;
1948
2023
  }
1949
- Object.assign(K, { gutterConfig, gutter, drain });
2024
+ const defined = { gutterConfig, gutter, drain };
2025
+ Object.assign(K, defined);
1950
2026
  }
1951
2027
 
1952
2028
  // src/roof/slabs.ts
@@ -1980,15 +2056,16 @@ function installRoofSlabs(K, shared) {
1980
2056
  side(free(j, i + 1), x1 + o - t, z0 - ez0, x1 + o, z1 + ez1);
1981
2057
  side(free(j - 1, i), x0 - ex0, z0 - o, x1 + ex1, z0 - o + t);
1982
2058
  side(free(j + 1, i), x0 - ex0, z1 + o - t, x1 + ex1, z1 + o);
1983
- if (shared.ctx.gutter && shared.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]]) {
2059
+ const G = shared.ctx.gutter;
2060
+ 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]]) {
1984
2061
  const kd = f + ":" + dx + ":" + dz;
1985
- if (!ok || shared.ctx.gutter.bz.has(kd)) continue;
1986
- shared.ctx.gutter.bz.add(kd);
1987
- shared.ctx.gutter.nbuz++;
1988
- 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 = shared.ctx.gutter.color;
2062
+ if (!ok || G.bz.has(kd)) continue;
2063
+ G.bz.add(kd);
2064
+ G.nbuz = (G.nbuz ?? 0) + 1;
2065
+ 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;
1989
2066
  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);
1990
2067
  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));
1991
- if (shared.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);
2068
+ 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);
1992
2069
  {
1993
2070
  const tx = ex + dx * 0.38, tz = ez + dz * 0.38;
1994
2071
  let lv = true;
@@ -2008,7 +2085,8 @@ function installRoofSlabs(K, shared) {
2008
2085
  }
2009
2086
  }
2010
2087
  }
2011
- Object.assign(K, { slabs });
2088
+ const defined = { slabs };
2089
+ Object.assign(K, defined);
2012
2090
  }
2013
2091
 
2014
2092
  // src/roof/tiles.ts
@@ -2141,7 +2219,8 @@ function installRoofTiles(K, shared) {
2141
2219
  }
2142
2220
  return m ? structurePiece(m.id) : null;
2143
2221
  }
2144
- Object.assign(K, { R_STYLE, tileRelief, ridge, pieceOfPane });
2222
+ const defined = { R_STYLE, tileRelief, ridge, pieceOfPane };
2223
+ Object.assign(K, defined);
2145
2224
  }
2146
2225
 
2147
2226
  // src/roof/rect.ts
@@ -2187,7 +2266,7 @@ function installRoofRect(K, shared) {
2187
2266
  }
2188
2267
  const rm = alongX ? dz / 2 : dx / 2;
2189
2268
  {
2190
- const rr = shared.ctx.roofRects[shared.ctx.roofRects.length - 1];
2269
+ const roofRects = shared.ctx.roofRects, rr = roofRects[roofRects.length - 1];
2191
2270
  if (rr && !rr.yb) Object.assign(rr, { yb, tp, gable: !!gable, alongX, exterior: [x0, z0, x1, z1], rm });
2192
2271
  }
2193
2272
  if (gable) {
@@ -2224,7 +2303,8 @@ function installRoofRect(K, shared) {
2224
2303
  }
2225
2304
  }
2226
2305
  }
2227
- Object.assign(K, { roofRect });
2306
+ const defined = { roofRect };
2307
+ Object.assign(K, defined);
2228
2308
  }
2229
2309
 
2230
2310
  // src/mirrors.ts
@@ -2235,9 +2315,11 @@ function installMirrors(K, shared) {
2235
2315
  function mirrorEnv() {
2236
2316
  if (shared.mirrorEnv) return shared.mirrorEnv;
2237
2317
  const mk = (f) => {
2318
+ if (!DOC) throw new Error("game-floorplan-three: the mirrors need a document (options.document)");
2238
2319
  const c = DOC.createElement("canvas");
2239
2320
  c.width = c.height = 64;
2240
2321
  const g = c.getContext("2d");
2322
+ if (!g) throw new Error("game-floorplan-three: no 2d canvas context");
2241
2323
  f(g);
2242
2324
  return c;
2243
2325
  };
@@ -2296,7 +2378,7 @@ function installMirrors(K, shared) {
2296
2378
  B.N.push(v.x, v.y, v.z);
2297
2379
  B.U.push(ua.getX(i), ua.getY(i));
2298
2380
  }
2299
- for (const k of geo.index.array) B.I.push(B.nv + k);
2381
+ for (const k of geo.index?.array ?? []) B.I.push(B.nv + k);
2300
2382
  B.nv += pa.count;
2301
2383
  geo.dispose();
2302
2384
  }
@@ -2374,10 +2456,12 @@ function installMirrors(K, shared) {
2374
2456
  m.fake.visible = !on;
2375
2457
  }
2376
2458
  }
2377
- Object.assign(K, { mirrorEnv, newMirrorState, assembleMirrors, floorAtY, chooseMirror });
2459
+ const defined = { mirrorEnv, newMirrorState, assembleMirrors, floorAtY, chooseMirror };
2460
+ Object.assign(K, defined);
2378
2461
  }
2379
2462
 
2380
2463
  // src/cars.ts
2464
+ import { isMesh } from "@adatechnology/game-shapes-three";
2381
2465
  function installCars(K, shared) {
2382
2466
  const { THREE, FLEET, _Y } = K;
2383
2467
  const CARS = [];
@@ -2387,13 +2471,16 @@ function installCars(K, shared) {
2387
2471
  high: ["electric_hatch", "hybrid_suv", "midsize_suv", "v8_coupe", "large_suv", "midsize_pickup", "crossover_pickup", "fastback_sedan"]
2388
2472
  }, K.cfg.carKinds);
2389
2473
  const CAR_CACHE = /* @__PURE__ */ new Map();
2390
- function materialSignature(m) {
2474
+ function materialSignature(material) {
2475
+ const m = material;
2391
2476
  const f = (v) => v == null ? "" : typeof v === "number" ? v.toFixed(3) : v.isColor ? v.getHexString() : v.uuid || String(v);
2392
2477
  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("|");
2393
2478
  }
2394
2479
  const BUCKETS = /* @__PURE__ */ new Map();
2395
- function bucketMaterial(m) {
2396
- if (m.type !== "MeshStandardMaterial" || m.map || m.alphaTest || m.vertexColors || !m.color) return null;
2480
+ function bucketMaterial(material) {
2481
+ if (material.type !== "MeshStandardMaterial") return null;
2482
+ const m = material;
2483
+ if (m.map || m.alphaTest || m.vertexColors || !m.color) return null;
2397
2484
  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 : "");
2398
2485
  let b = BUCKETS.get(sig);
2399
2486
  if (!b) {
@@ -2405,7 +2492,7 @@ function installCars(K, shared) {
2405
2492
  }
2406
2493
  function carModel(k, seed) {
2407
2494
  const kc = k + "|" + shared.quality + "|" + (seed || 0);
2408
- if (CAR_CACHE.has(kc)) return CAR_CACHE.get(kc);
2495
+ if (CAR_CACHE.has(kc)) return CAR_CACHE.get(kc) ?? null;
2409
2496
  if (!FLEET) return null;
2410
2497
  let res = null;
2411
2498
  try {
@@ -2413,8 +2500,10 @@ function installCars(K, shared) {
2413
2500
  c.root.updateMatrixWorld(true);
2414
2501
  const inv = new THREE.Matrix4();
2415
2502
  const byMaterial = /* @__PURE__ */ new Map(), tmp = new THREE.Matrix4(), v = new THREE.Vector3(), nm = new THREE.Matrix3(), bb = new THREE.Box3();
2416
- c.g.traverse((o) => {
2417
- if (!o.isMesh || o.isInstancedMesh || o.isSkinnedMesh || !o.geometry || !o.geometry.attributes.position) return;
2503
+ c.g.traverse((node) => {
2504
+ if (!isMesh(node)) return;
2505
+ const o = node;
2506
+ if (o.isInstancedMesh || o.isSkinnedMesh || !o.geometry || !o.geometry.attributes.position) return;
2418
2507
  for (let p = o; p; p = p.parent) if (p.visible === false) return;
2419
2508
  const mats = Array.isArray(o.material) ? o.material : [o.material];
2420
2509
  let geo = o.geometry;
@@ -2428,7 +2517,7 @@ function installCars(K, shared) {
2428
2517
  const pa = geo.attributes.position, na = geo.attributes.normal, ua = geo.attributes.uv, total = pa.count;
2429
2518
  const grs = Array.isArray(o.material) && o.geometry.groups.length ? o.geometry.groups : [{ start: 0, count: total, materialIndex: 0 }];
2430
2519
  for (const gr of grs) {
2431
- const m = mats[gr.materialIndex] || mats[0];
2520
+ const m = (gr.materialIndex != null ? mats[gr.materialIndex] : void 0) || mats[0];
2432
2521
  if (!m) continue;
2433
2522
  const a0 = Math.min(gr.start, total), n0 = Math.min(gr.count, total - a0) - Math.min(gr.count, total - a0) % 3;
2434
2523
  if (n0 < 3) continue;
@@ -2529,7 +2618,10 @@ function installCars(K, shared) {
2529
2618
  return g;
2530
2619
  }
2531
2620
  function assembleCars(groups) {
2532
- if (shared.quality === "game") return assembleMergedCars(groups);
2621
+ if (shared.quality === "game") {
2622
+ assembleMergedCars(groups);
2623
+ return;
2624
+ }
2533
2625
  for (const C of CARS) {
2534
2626
  const g = carGroup(C.k, C.w, C.d, C.seed);
2535
2627
  if (!g) continue;
@@ -2580,7 +2672,8 @@ function installCars(K, shared) {
2580
2672
  (groups[B.parent] || (groups[B.parent] = new THREE.Group())).add(m);
2581
2673
  }
2582
2674
  }
2583
- Object.assign(K, { CARS, CAR_BY_STYLE, CAR_CACHE, materialSignature, BUCKETS, bucketMaterial, carModel, carGroup, assembleCars, assembleMergedCars });
2675
+ const defined = { CARS, CAR_BY_STYLE, CAR_CACHE, materialSignature, BUCKETS, bucketMaterial, carModel, carGroup, assembleCars, assembleMergedCars };
2676
+ Object.assign(K, defined);
2584
2677
  }
2585
2678
 
2586
2679
  // src/house/building.ts
@@ -2636,14 +2729,15 @@ function installHouseBuilding(K, shared) {
2636
2729
  bx("plaster", Math.min(hall[0] - 3, color[0]), ytop, Math.min(un[1] ? unitBox(un[1])[1] : 0, el[1]), Math.max(color[2], un0[2]), ytop + 0.2, Math.max(un0[3], un[1] ? unitBox(un[1])[3] : 0), 11841704);
2637
2730
  shared.ctx.limits = { x0: Math.min(hall[0] - 3, color[0]), z0: Math.min(el[1], un[1] ? unitBox(un[1])[1] : 0), x1: Math.max(color[2], un0[2]), z1: Math.max(un0[3], un[1] ? unitBox(un[1])[3] : 0) };
2638
2731
  }
2639
- Object.assign(K, { building });
2732
+ const defined = { building };
2733
+ Object.assign(K, defined);
2640
2734
  }
2641
2735
 
2642
2736
  // src/utilities/water.ts
2643
2737
  function installUtilitiesWater(K, shared) {
2644
2738
  const { THREE, _Y, _q, cursor, cylBase, part, pieceRecord, put } = K;
2645
2739
  function createWater(r, state) {
2646
- const H = r.utilities.plumbing, cap = H ? +H.capacityL || 0 : 0, ls = { dry: [], full: [] }, points = {}, itemPoint = {};
2740
+ const H = r.utilities?.plumbing, cap = H ? +H.capacityL || 0 : 0, ls = { dry: [], full: [] }, points = {}, itemPoint = {};
2647
2741
  if (H) for (const p of H.points) {
2648
2742
  points[p.id] = p;
2649
2743
  itemPoint[p.item] = p.id;
@@ -2732,14 +2826,14 @@ function installUtilitiesWater(K, shared) {
2732
2826
  }
2733
2827
  const _v3 = new THREE.Vector3();
2734
2828
  function waterPipes() {
2735
- const H = shared.ctx.r.utilities.plumbing;
2829
+ const H = shared.ctx.r.utilities?.plumbing;
2736
2830
  if (!H || !H.visibleRuns) return;
2737
2831
  const nA = shared.ctx.r.floors.length;
2738
2832
  const groupOf = (c) => c && c.floor >= 0 ? "f" + Math.min(c.floor, nA - 1) : "lot", xyz = (p) => [p[0], p[2], p[1]];
2739
2833
  for (const tr of H.visibleRuns) {
2740
2834
  const pts = tr.points.map(xyz), d = tr.diameter || 0.025;
2741
2835
  if (tr.exposed === "wall") {
2742
- const pt = H.points.find((p) => p.run === tr.id), com = shared.ctx.roomById[tr.to], g2 = groupOf(com || pt && { floor: pt.floor });
2836
+ const pt = H.points.find((p) => p.run === tr.id), com = tr.to != null ? shared.ctx.roomById[tr.to] : void 0, g2 = groupOf(com || pt && { floor: pt.floor });
2743
2837
  part("wall_pipe", [0, 0, 0], () => {
2744
2838
  for (let i = 0; i + 1 < pts.length; i++) pipe(pts[i], pts[i + 1], d, PIPE_COLOR);
2745
2839
  for (const p of pts) cylBase("plain", p[0], p[1] - d, p[2], d * 0.7, d * 2, PIPE_COLOR);
@@ -2761,7 +2855,8 @@ function installUtilitiesWater(K, shared) {
2761
2855
  cursor.pc = null;
2762
2856
  }
2763
2857
  }
2764
- Object.assign(K, { createWater, PIPE_COLOR, pipe, _v3, waterPipes });
2858
+ const defined = { createWater, PIPE_COLOR, pipe, _v3, waterPipes };
2859
+ Object.assign(K, defined);
2765
2860
  }
2766
2861
 
2767
2862
  // src/utilities/electrical.ts
@@ -2769,10 +2864,10 @@ function installUtilitiesElectrical(K, shared) {
2769
2864
  const { _Y, _q, _v3, bx, cursor, cylBase, pieceRecord, put } = K;
2770
2865
  const sh = (...a) => K.sh(...a);
2771
2866
  function electricalStructure() {
2772
- const E = shared.ctx.r.utilities.electrical;
2867
+ const R = shared.ctx.r, E = R.utilities?.electrical;
2773
2868
  shared.ctx.electricalInfo = null;
2774
2869
  if (!E) return;
2775
- const R = shared.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 };
2870
+ 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 };
2776
2871
  const en2 = E.serviceEntrance, KV = shared.ctx.iv ? shared.ctx.iv.plane : null;
2777
2872
  const wireL = (a, b, r_ = 8e-3) => {
2778
2873
  const L = Math.hypot(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
@@ -2877,7 +2972,8 @@ function installUtilitiesElectrical(K, shared) {
2877
2972
  _q.setFromUnitVectors(_Y, _v3.set(dx / L, dy / L, dz / L));
2878
2973
  put("plain", "cyl", (a[0] + b[0]) / 2, (a[1] + b[1]) / 2, (a[2] + b[2]) / 2, _q, diameter, L, diameter, color);
2879
2974
  }
2880
- Object.assign(K, { electricalStructure, pipe2 });
2975
+ const defined = { electricalStructure, pipe2 };
2976
+ Object.assign(K, defined);
2881
2977
  }
2882
2978
 
2883
2979
  // src/house/baseboard.ts
@@ -2915,7 +3011,8 @@ function installHouseBaseboard(K, shared) {
2915
3011
  strip(W, y0, y0 + 0.045, 0, W, "sidewalk", cal);
2916
3012
  }
2917
3013
  }
2918
- Object.assign(K, { baseboardAndSidewalk });
3014
+ const defined = { baseboardAndSidewalk };
3015
+ Object.assign(K, defined);
2919
3016
  }
2920
3017
 
2921
3018
  // src/utilities/solar.ts
@@ -2930,6 +3027,7 @@ function installUtilitiesSolar(K, shared) {
2930
3027
  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);
2931
3028
  continue;
2932
3029
  }
3030
+ if (!rr.exterior || rr.tp == null || rr.rm == null) continue;
2933
3031
  const [x0, z0, x1, z1] = rr.exterior;
2934
3032
  if (u < x0 || u > x1 || v < z0 || v > z1) continue;
2935
3033
  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);
@@ -2938,7 +3036,7 @@ function installUtilitiesSolar(K, shared) {
2938
3036
  return y;
2939
3037
  }
2940
3038
  function solar() {
2941
- const R = shared.ctx.r, S = R.utilities.solar;
3039
+ const R = shared.ctx.r, S = R.utilities?.solar;
2942
3040
  shared.ctx.solarInfo = null;
2943
3041
  if (!S || !S.panels || !S.panels.length) return;
2944
3042
  cursor.group = "roof";
@@ -2981,13 +3079,14 @@ function installUtilitiesSolar(K, shared) {
2981
3079
  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);
2982
3080
  bx("emissive", iv.u - 0.03, y0 - 0.12, iv.v + fa0, iv.u + 0.03, y0 - 0.09, iv.v + fa1, 6479994);
2983
3081
  }
2984
- const top = Math.max(...(shared.ctx.roofRects || []).filter((t2) => t2.yb != null).map((t2) => t2.yb), Y0(fa) + 2.8);
3082
+ const top = Math.max(...(shared.ctx.roofRects || []).flatMap((t2) => t2.yb != null ? [t2.yb] : []), Y0(fa) + 2.8);
2985
3083
  cylBase("plain", iv.u, y0 + h / 2, iv.v, 0.016, Math.max(0.2, top - 0.2 - (y0 + h / 2)), 15262936);
2986
3084
  info.inverter = { id: iv.id, pos: [iv.u, y0, iv.v], side: iv.side, link: iv.link };
2987
3085
  }
2988
3086
  shared.ctx.solarInfo = info;
2989
3087
  }
2990
- Object.assign(K, { roofHeightAt, solar });
3088
+ const defined = { roofHeightAt, solar };
3089
+ Object.assign(K, defined);
2991
3090
  }
2992
3091
 
2993
3092
  // src/house/outbuildings.ts
@@ -3002,7 +3101,7 @@ function installHouseOutbuildings(K, shared) {
3002
3101
  counts.set(w.floor, i + 1);
3003
3102
  return w.id ? w : Object.assign({}, w, { id: `wall_${w.floor}_${i}` });
3004
3103
  }) });
3005
- const E = (r.outbuildings || []).filter((e) => e && e.walls && e.walls.length && e.interior && e.interior.length);
3104
+ const E = (r.outbuildings || []).filter((e) => !!(e && e.walls && e.walls.length && e.interior && e.interior.length));
3006
3105
  if (!E.length) return r;
3007
3106
  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");
3008
3107
  for (const e of E) {
@@ -3016,7 +3115,22 @@ function installHouseOutbuildings(K, shared) {
3016
3115
  const alongU = p.axis === "u", below = p.pos < (alongU ? cz : cx);
3017
3116
  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 });
3018
3117
  }
3019
- 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 });
3118
+ for (const j of e.windows || []) windows.push({
3119
+ id: j.id,
3120
+ floor: 0,
3121
+ u: j.u,
3122
+ v: j.v,
3123
+ axis: j.axis,
3124
+ pos: j.pos,
3125
+ at: j.at,
3126
+ width: j.width,
3127
+ y0: j.y0 ?? 1,
3128
+ y1: j.y1 ?? 2,
3129
+ /* the structure always gives a window its sill and head (1.0, 2.0) */
3130
+ room: e.id,
3131
+ side: j.side,
3132
+ outbuilding: e.id
3133
+ });
3020
3134
  (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" }));
3021
3135
  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 });
3022
3136
  }
@@ -3037,7 +3151,8 @@ function installHouseOutbuildings(K, shared) {
3037
3151
  }
3038
3152
  }
3039
3153
  }
3040
- Object.assign(K, { OUTBUILDING_USE, applyOutbuildings, outbuildings });
3154
+ const defined = { OUTBUILDING_USE, applyOutbuildings, outbuildings };
3155
+ Object.assign(K, defined);
3041
3156
  }
3042
3157
 
3043
3158
  // src/furniture/api.ts
@@ -3102,7 +3217,8 @@ function installFurnitureApi(K, _shared) {
3102
3217
  return { b: (mat, x, y, z, w, h, d, color, ry, rx, rz) => A.box(M, mat, x, y0 + y, z, w, h, d, color, ry || 0, rx || 0, rz || 0), c: (mat, x, y, z, r, h, color, rx, rz, seg) => A.cylinder(M, mat, x, y0 + y, z, r, h, color, rx || 0, rz || 0, seg), rnd: rngOf(M), wood: paletteColor(M, "wood", 8016948), met: paletteColor(M, "metal", 10133154) };
3103
3218
  }
3104
3219
  const PE = Math.PI / 2;
3105
- Object.assign(K, { MATERIAL_MAP, mm, LIGHTS, makeApi, sh, paletteColor, rngOf, kk, PE });
3220
+ const defined = { MATERIAL_MAP, mm, LIGHTS, makeApi, sh, paletteColor, rngOf, kk, PE };
3221
+ Object.assign(K, defined);
3106
3222
  }
3107
3223
 
3108
3224
  // src/furniture/builders.ts
@@ -3230,7 +3346,7 @@ function installFurnitureBuilders(K, _shared) {
3230
3346
  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);
3231
3347
  },
3232
3348
  wardrobe(M, A) {
3233
- 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));
3349
+ 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));
3234
3350
  lb("wood", 0, 0.06, 0, w, h - 0.06, d, wood);
3235
3351
  lb("wood", 0, h, 0, w + 0.04, 0.04, d + 0.04, sh(wood, 0.8));
3236
3352
  lb("wood", 0, 0, 0, w - 0.04, 0.06, d - 0.04, sh(wood, 0.4));
@@ -3622,7 +3738,8 @@ function installFurnitureBuilders(K, _shared) {
3622
3738
  lb("metal", 0, h - 0.04, d / 2, w, 0.03, 0.03, 3815994);
3623
3739
  }
3624
3740
  };
3625
- Object.assign(K, { FURNITURE });
3741
+ const defined = { FURNITURE };
3742
+ Object.assign(K, defined);
3626
3743
  }
3627
3744
 
3628
3745
  // src/furniture/type-table.ts
@@ -3632,7 +3749,8 @@ function installFurnitureTypeTable(K, _shared) {
3632
3749
  function typeTable(props) {
3633
3750
  const B = props.builders, T = {};
3634
3751
  const mv = (type, id) => {
3635
- if (B[id || type]) T[type] = { f: B[id || type], source: "props3d" };
3752
+ const f = B[id || type];
3753
+ if (f) T[type] = { f, source: "props3d" };
3636
3754
  };
3637
3755
  const mine = (type, f, source = "game") => {
3638
3756
  T[type] = { f, source };
@@ -3771,7 +3889,8 @@ function installFurnitureTypeTable(K, _shared) {
3771
3889
  extraTypes(T, props);
3772
3890
  return T;
3773
3891
  }
3774
- Object.assign(K, { typeTable });
3892
+ const defined = { typeTable };
3893
+ Object.assign(K, defined);
3775
3894
  }
3776
3895
 
3777
3896
  // src/furniture/taps.ts
@@ -3835,7 +3954,8 @@ function installFurnitureTaps(K, shared) {
3835
3954
  }, { id: id + "_a", target: id, hidden: true, fluid: "water" });
3836
3955
  return id;
3837
3956
  }
3838
- Object.assign(K, { counterTap, wallTap });
3957
+ const defined = { counterTap, wallTap };
3958
+ Object.assign(K, defined);
3839
3959
  }
3840
3960
 
3841
3961
  // src/furniture/fixtures.ts
@@ -3948,7 +4068,7 @@ function installFurniturePlants(K, _shared) {
3948
4068
  const a = rnd() * 6.283, u = Math.sqrt(rnd()), ph = (rnd() - 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;
3949
4069
  const r = R * (0.34 + rnd() * 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 + rnd() * 0.12;
3950
4070
  K2.e("plant", cx + dx, cy + dy + r * 0.5, cz + dz, r, alt, sh(green, f));
3951
- if (o.flower && rnd() < o.flower) {
4071
+ if (o.flower && o.flowers && rnd() < o.flower) {
3952
4072
  const fa = rnd() * 6.283;
3953
4073
  K2.e("plain", cx + dx + Math.cos(fa) * r * 0.78, cy + dy + r * 0.5 + rnd() * r * 0.5, cz + dz + Math.sin(fa) * r * 0.78, 0.028 + rnd() * 0.012, 0.05, o.flowers[rnd() * o.flowers.length | 0]);
3954
4074
  }
@@ -4061,7 +4181,8 @@ function installFurniturePlants(K, _shared) {
4061
4181
  else blobs(K2, x, bh - 0.05, z, 0.24 + rnd() * 0.08, 6, green, rnd, { flatten: true, flower: tp === "flower" ? 0.9 : 0.25, flowers: FLOWERS.slice(i % 3, i % 3 + 3) });
4062
4182
  }
4063
4183
  }
4064
- Object.assign(K, { GREENS, FLOWERS, blobs, potModel, arcLeaf, tuft, palm_tree, treeModel, shrubModel, potPlant, tablePot, planterModel });
4184
+ const defined = { GREENS, FLOWERS, blobs, potModel, arcLeaf, tuft, palm_tree, treeModel, shrubModel, potPlant, tablePot, planterModel };
4185
+ Object.assign(K, defined);
4065
4186
  }
4066
4187
 
4067
4188
  // src/furniture/yard.ts
@@ -4217,7 +4338,7 @@ function installFurnitureYard(K, shared) {
4217
4338
  };
4218
4339
  FURNITURE.mailbox = function(M, A) {
4219
4340
  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, rnd = rngString(SEED() + "|" + seedKey(M.seed) + "|correio");
4220
- if (M.pole !== false && !(M.y > 0)) {
4341
+ if (M.pole !== false && !(M.y != null && M.y > 0)) {
4221
4342
  K2.b("plain", 0, 0, -d / 2 - 0.1, 0.12, y, 0.12, 12104874);
4222
4343
  }
4223
4344
  K2.b("metal", 0, y, 0, w, h * 0.78, d, pc);
@@ -4237,7 +4358,8 @@ function installFurnitureYard(K, shared) {
4237
4358
  );
4238
4359
  K2.b("plain", 0, y + h * 0.62, d / 2 + 4e-3, 0.08, 0.05, 4e-3, 15921386);
4239
4360
  };
4240
- Object.assign(K, { CLOTHES_COLORS, strip, garment });
4361
+ const defined = { CLOTHES_COLORS, strip, garment };
4362
+ Object.assign(K, defined);
4241
4363
  }
4242
4364
 
4243
4365
  // src/furniture/extra-types.ts
@@ -4297,7 +4419,8 @@ function installFurnitureExtraTypes(K, _shared) {
4297
4419
  tuft(K2, 0, 0, 0, Math.max(0.2, (M.w || 0.4) / 2), 16, 5212738, rnd);
4298
4420
  });
4299
4421
  }
4300
- Object.assign(K, { extraTypes });
4422
+ const defined = { extraTypes };
4423
+ Object.assign(K, defined);
4301
4424
  }
4302
4425
 
4303
4426
  // src/furniture/place-items.ts
@@ -4319,8 +4442,8 @@ function installFurniturePlaceItems(K, shared) {
4319
4442
  if (m.type === "stairs") continue;
4320
4443
  const exterior = m.outdoor || m.floor < 0, f = exterior ? -1 : Math.min(m.floor, R.floors.length - 1);
4321
4444
  cursor.group = exterior ? "lot" : "f" + f;
4322
- const com = shared.ctx.roomById[m.room], base = exterior ? 0 : Y0(f);
4323
- 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: shared.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: shared.ctx.night, light: shared.ctx.night, lit: shared.ctx.night, open: !!m.doorOpen, overhead: m.overhead, assembly: m.assembly, hose: m.hose };
4445
+ const com = m.room != null ? shared.ctx.roomById[m.room] : void 0, base = exterior ? 0 : Y0(f);
4446
+ 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: shared.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: shared.ctx.night, light: shared.ctx.night, lit: shared.ctx.night, open: !!m.doorOpen, overhead: m.overhead, assembly: m.assembly, hose: m.hose };
4324
4447
  if (m.category === "ground_cover" && m.polygon) {
4325
4448
  const xs = m.polygon.map((p) => p[0]), zs = m.polygon.map((p) => p[1]);
4326
4449
  M.x = (Math.min(...xs) + Math.max(...xs)) / 2;
@@ -4397,10 +4520,12 @@ function installFurniturePlaceItems(K, shared) {
4397
4520
  boxC("plain", m.x, M.base + (m.y || 0) + h / 2, m.z, m.w, h, m.d, color, 0, m.ry || 0, 0);
4398
4521
  shared.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" });
4399
4522
  }
4400
- Object.assign(K, { houseItems, waterTankOfHouse, hashColor, labeledBox });
4523
+ const defined = { houseItems, waterTankOfHouse, hashColor, labeledBox };
4524
+ Object.assign(K, defined);
4401
4525
  }
4402
4526
 
4403
4527
  // src/vegetation/bridge.ts
4528
+ import { isMesh as isMesh2 } from "@adatechnology/game-shapes-three";
4404
4529
  function installVegetationBridge(K, shared) {
4405
4530
  const seedKey = (id) => K.seedKey(id);
4406
4531
  const { THREE, SEED, rngString } = K;
@@ -4432,7 +4557,7 @@ function installVegetationBridge(K, shared) {
4432
4557
  const ids = VEG_MAP[m.type], can = VEG_PLANTER[m.type];
4433
4558
  if (!ids && !can) return false;
4434
4559
  const rnd = rngString(SEED() + "|" + seedKey(m.id) + "|veg"), pick = (l) => l[Math.min(l.length - 1, rnd() * l.length | 0)], ok = (id) => {
4435
- if (V.ok.has(id)) return V.ok.get(id);
4560
+ if (V.ok.has(id)) return V.ok.get(id) === true;
4436
4561
  let r = true;
4437
4562
  try {
4438
4563
  V.S.toSpec(id);
@@ -4478,7 +4603,7 @@ function installVegetationBridge(K, shared) {
4478
4603
  obj.position.y = G.y;
4479
4604
  obj.name = "vegetation";
4480
4605
  obj.traverse((o) => {
4481
- if (o.isMesh) {
4606
+ if (isMesh2(o)) {
4482
4607
  o.castShadow = true;
4483
4608
  o.receiveShadow = true;
4484
4609
  o.name = "veg/" + o.name;
@@ -4493,10 +4618,12 @@ function installVegetationBridge(K, shared) {
4493
4618
  }
4494
4619
  shared.ctx.vegInfo = { plants: pl, triangles: tri, colliders: col, lodCounts: lod, materials: mats };
4495
4620
  }
4496
- Object.assign(K, { VEG_POT, VEG_CACTUS, VEG_MAP, VEG_PLANTER, vegItem, assembleVegetation });
4621
+ const defined = { VEG_POT, VEG_CACTUS, VEG_MAP, VEG_PLANTER, vegItem, assembleVegetation };
4622
+ Object.assign(K, defined);
4497
4623
  }
4498
4624
 
4499
4625
  // src/interaction/state.ts
4626
+ import { isMesh as isMesh3 } from "@adatechnology/game-shapes-three";
4500
4627
  function installInteractionState(K, shared) {
4501
4628
  const { THREE, cfg, colliderChanged, invalidateShadow, invalidate, UV_SCALE, applyPart, texture } = K;
4502
4629
  const ivRoomEffective = (...a) => K.ivRoomEffective(...a);
@@ -4561,12 +4688,14 @@ function installInteractionState(K, shared) {
4561
4688
  shared.inter.msg = { text, until: performance.now() + MESSAGE_MS };
4562
4689
  if (cfg.onMessage) cfg.onMessage(text);
4563
4690
  };
4564
- function definePiece(name, def) {
4691
+ const I = () => shared.inter;
4692
+ function definePiece(name, definition) {
4693
+ const def = definition;
4565
4694
  def.name = name;
4566
4695
  def.meshes = [];
4567
4696
  def.t = def.target = shared.partState.has(name) ? shared.partState.get(name) : def.t0 || 0;
4568
- shared.inter.defs.set(name, def);
4569
- shared.inter.pieces.push(def);
4697
+ I().defs.set(name, def);
4698
+ I().pieces.push(def);
4570
4699
  return def;
4571
4700
  }
4572
4701
  const localOf = (M, lx, lz) => {
@@ -4578,17 +4707,18 @@ function installInteractionState(K, shared) {
4578
4707
  return true;
4579
4708
  }
4580
4709
  function assembleInteractive(gs) {
4581
- for (const [name, def] of shared.inter.defs) {
4710
+ const inter = I();
4711
+ for (const [name, def] of inter.defs) {
4582
4712
  const g = gs[name];
4583
4713
  if (!g) continue;
4584
4714
  delete gs[name];
4585
4715
  const outer = new THREE.Group();
4586
- outer.position.set(...def.pivot);
4716
+ outer.position.fromArray(def.pivot);
4587
4717
  outer.rotation.y = def.ry || 0;
4588
4718
  outer.updateMatrix();
4589
- const inv = new THREE.Matrix4().compose(new THREE.Vector3(...def.pivot), new THREE.Quaternion().setFromAxisAngle(_EY, def.ry || 0), _UM3).invert();
4719
+ const inv = new THREE.Matrix4().compose(new THREE.Vector3().fromArray(def.pivot), new THREE.Quaternion().setFromAxisAngle(_EY, def.ry || 0), _UM3).invert();
4590
4720
  g.traverse((o) => {
4591
- if (o.isMesh) {
4721
+ if (isMesh3(o)) {
4592
4722
  o.geometry.applyMatrix4(inv);
4593
4723
  o.userData.piece = def;
4594
4724
  def.meshes.push(o);
@@ -4600,13 +4730,14 @@ function installInteractionState(K, shared) {
4600
4730
  const parent = def.leaf ? def.leaf.gs[def.k] : gs[def.parent] || (gs[def.parent] = new THREE.Group());
4601
4731
  if (parent) parent.add(outer);
4602
4732
  if (def.roomId) {
4603
- if (!shared.inter.lights.has(def.roomId)) shared.inter.lights.set(def.roomId, []);
4604
- shared.inter.lights.get(def.roomId).push(def);
4733
+ let lamps = inter.lights.get(def.roomId);
4734
+ if (!lamps) inter.lights.set(def.roomId, lamps = []);
4735
+ lamps.push(def);
4605
4736
  }
4606
4737
  applyPiece(def);
4607
4738
  }
4608
- for (const roomId of shared.inter.litRooms) applyLight(roomId);
4609
- shared.inter.defs.forEach((d) => {
4739
+ for (const roomId of inter.litRooms) applyLight(roomId);
4740
+ inter.defs.forEach((d) => {
4610
4741
  if (d.col) d.col.off = d.t > 0.5;
4611
4742
  });
4612
4743
  }
@@ -4614,6 +4745,7 @@ function installInteractionState(K, shared) {
4614
4745
  const n = p.inner;
4615
4746
  if (!n) return;
4616
4747
  switch (p.kind) {
4748
+ /* each kind always sets its dimensions (sgn, angle, travel, k, axis) */
4617
4749
  case "swing":
4618
4750
  n.rotation.y = p.sgn * p.t * p.angle;
4619
4751
  break;
@@ -4646,8 +4778,9 @@ function installInteractionState(K, shared) {
4646
4778
  }
4647
4779
  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 };
4648
4780
  function animateInteractive(dt) {
4649
- if (!shared.inter.anim.size) return;
4650
- for (const p of shared.inter.anim) {
4781
+ const inter = I();
4782
+ if (!inter.anim.size) return;
4783
+ for (const p of inter.anim) {
4651
4784
  const step = dt / (DURATION[p.kind] || 0.5), d = p.target - p.t;
4652
4785
  p.t = Math.abs(d) <= step ? p.target : p.t + Math.sign(d) * step;
4653
4786
  applyPiece(p);
@@ -4655,7 +4788,7 @@ function installInteractionState(K, shared) {
4655
4788
  p.col.off = p.target > 0.5;
4656
4789
  colliderChanged(p.col);
4657
4790
  }
4658
- if (p.t === p.target) shared.inter.anim.delete(p);
4791
+ if (p.t === p.target) inter.anim.delete(p);
4659
4792
  }
4660
4793
  invalidateShadow();
4661
4794
  }
@@ -4666,7 +4799,7 @@ function installInteractionState(K, shared) {
4666
4799
  p.col.off = p.target > 0.5;
4667
4800
  colliderChanged(p.col);
4668
4801
  }
4669
- shared.inter.anim.add(p);
4802
+ I().anim.add(p);
4670
4803
  }
4671
4804
  const lightBase = (roomId) => roomId == null ? true : shared.partState.has("light:" + roomId) ? !!shared.partState.get("light:" + roomId) : !!shared.ctx.night;
4672
4805
  const lightOn = (roomId) => {
@@ -4674,20 +4807,21 @@ function installInteractionState(K, shared) {
4674
4807
  return S ? S.ef : lightBase(roomId);
4675
4808
  };
4676
4809
  function applyLight(roomId) {
4677
- const on = lightOn(roomId);
4678
- for (const d of shared.inter.lights.get(roomId) || []) for (const m of d.meshes) if (m.name.endsWith("/emissive")) m.material = on ? shared.mats.emissive : shared.mats.off;
4679
- const sw = shared.inter.defs.get("ix:int:" + roomId);
4810
+ const on = lightOn(roomId), inter = I(), mats = shared.mats;
4811
+ 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;
4812
+ const sw = inter.defs.get("ix:int:" + roomId);
4680
4813
  if (sw) {
4681
4814
  sw.target = on ? 1 : 0;
4682
- if (sw.t !== sw.target) shared.inter.anim.add(sw);
4815
+ if (sw.t !== sw.target) inter.anim.add(sw);
4683
4816
  }
4684
4817
  invalidate();
4685
4818
  }
4686
4819
  function toggleLight(roomId) {
4687
4820
  const S = shared.ctx.iv && shared.ctx.iv.roomStates.get(roomId);
4688
4821
  if (S) {
4689
- ivRoomLight(shared.ctx.iv, roomId, !S.ef);
4690
- const ef = ivRoomEffective(shared.ctx.iv, S);
4822
+ const IV = shared.ctx.iv;
4823
+ ivRoomLight(IV, roomId, !S.ef);
4824
+ const ef = ivRoomEffective(IV, S);
4691
4825
  if (ef !== S.ef) {
4692
4826
  S.ef = ef;
4693
4827
  applyLight(roomId);
@@ -4699,11 +4833,13 @@ function installInteractionState(K, shared) {
4699
4833
  applyLight(roomId);
4700
4834
  if (cfg.onLight) cfg.onLight(roomId, lightOn(roomId));
4701
4835
  }
4702
- Object.assign(K, { newInteractiveState, MESSAGE_MS, createInteractiveMaterials, _EY, _UM3, hudMessage, definePiece, localOf, visibleChain, assembleInteractive, applyPiece, DURATION, animateInteractive, togglePiece, lightBase, lightOn, applyLight, toggleLight });
4836
+ const defined = { newInteractiveState, MESSAGE_MS, createInteractiveMaterials, _EY, _UM3, hudMessage, definePiece, localOf, visibleChain, assembleInteractive, applyPiece, DURATION, animateInteractive, togglePiece, lightBase, lightOn, applyLight, toggleLight };
4837
+ Object.assign(K, defined);
4703
4838
  }
4704
4839
 
4705
4840
  // src/interaction/collision.ts
4706
4841
  function installInteractionCollision(K, shared) {
4842
+ const inter = () => shared.inter;
4707
4843
  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)/;
4708
4844
  function registerCollision(m, M) {
4709
4845
  const h = m.h || 0, y = M.y || 0;
@@ -4713,7 +4849,7 @@ function installInteractionCollision(K, shared) {
4713
4849
  w = Math.min(w, 0.5);
4714
4850
  d = Math.min(d, 0.5);
4715
4851
  }
4716
- shared.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 });
4852
+ 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 });
4717
4853
  }
4718
4854
  function objectDistance(o, x, z) {
4719
4855
  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;
@@ -4721,7 +4857,7 @@ function installInteractionCollision(K, shared) {
4721
4857
  }
4722
4858
  function collideObject(x, z, fx, fz, floor) {
4723
4859
  const R = 0.2;
4724
- for (const o of shared.inter.objs) {
4860
+ for (const o of inter().objs) {
4725
4861
  if (o.f !== -1 ? o.f !== floor : floor !== 0) continue;
4726
4862
  const d1 = objectDistance(o, x, z);
4727
4863
  if (d1 < R && d1 < objectDistance(o, fx, fz) - 1e-6) return true;
@@ -4741,7 +4877,8 @@ function installInteractionCollision(K, shared) {
4741
4877
  const de = opt.from || [x + 1e4, z + 1e4];
4742
4878
  return collideObject(x, z, de[0], de[1], floor);
4743
4879
  }
4744
- Object.assign(K, { NO_COLLIDE, registerCollision, objectDistance, collideObject, collideAt });
4880
+ const defined = { NO_COLLIDE, registerCollision, objectDistance, collideObject, collideAt };
4881
+ Object.assign(K, defined);
4745
4882
  }
4746
4883
 
4747
4884
  // src/interaction/items.ts
@@ -4750,6 +4887,7 @@ function installInteractionItems(K, shared) {
4750
4887
  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)$/;
4751
4888
  const DRAWER_ITEM = /^(console_table|dresser|nightstand|vanity_table)$/;
4752
4889
  const LIGHT_TYPES = /* @__PURE__ */ new Set(["ceiling_light", "pendant", "chandelier", "track_spot", "hanging_plant"]);
4890
+ const I = () => shared.inter;
4753
4891
  function objectName(type, drawer) {
4754
4892
  return drawer ? "drawer" : /^wardrobe/.test(type) ? "wardrobe" : /fridge|refrig|freezer/.test(type) ? "fridge" : /pantry/.test(type) ? "pantry" : "cabinet";
4755
4893
  }
@@ -4778,8 +4916,8 @@ function installInteractionItems(K, shared) {
4778
4916
  cursor.group = parent;
4779
4917
  }
4780
4918
  for (let i = n0; i < LIGHTS.length; i++) LIGHTS[i].roomId = m.room;
4781
- if (!shared.inter.defs.has(name)) definePiece(name, { kind: "light", pivot: [0, 0, 0], ry: 0, parent, roomId: m.room });
4782
- shared.inter.litRooms.add(m.room);
4919
+ if (!I().defs.has(name)) definePiece(name, { kind: "light", pivot: [0, 0, 0], ry: 0, parent, roomId: m.room });
4920
+ I().litRooms.add(m.room);
4783
4921
  }
4784
4922
  function curtainItem(m, M, ent, api, parent) {
4785
4923
  M.open = false;
@@ -4807,12 +4945,13 @@ function installInteractionItems(K, shared) {
4807
4945
  for (const c of body) api[c[0]](M, ...c[1]);
4808
4946
  if (!parts.length) return;
4809
4947
  const [ax, az] = localOf(M, 0, 0.2);
4810
- shared.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: () => {
4811
- const al = parts[0].target > 0.5 ? 0 : 1;
4948
+ const first = parts[0];
4949
+ 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: () => {
4950
+ const al = first.target > 0.5 ? 0 : 1;
4812
4951
  for (const p of parts) {
4813
4952
  p.target = al;
4814
4953
  shared.partState.set(p.name, al);
4815
- shared.inter.anim.add(p);
4954
+ I().anim.add(p);
4816
4955
  }
4817
4956
  } });
4818
4957
  }
@@ -4833,7 +4972,7 @@ function installInteractionItems(K, shared) {
4833
4972
  calls.forEach((c, i) => {
4834
4973
  if (owner.has(i)) return;
4835
4974
  const a = c[1];
4836
- let x0, x1, y0, y1, ok = false, grip = 0, wide = false;
4975
+ let x0 = 0, x1 = 0, y0 = 0, y1 = 0, ok = false, grip = 0, wide = false;
4837
4976
  if (c[0] === "box") {
4838
4977
  const [mat, x, y, z, w, h, d, , ry, rx, rz] = a;
4839
4978
  if (ry || rx || rz || d > 0.05 || z + d / 2 < front - 5e-3 || w > M.w * 1.01) return;
@@ -4865,8 +5004,9 @@ function installInteractionItems(K, shared) {
4865
5004
  return;
4866
5005
  }
4867
5006
  candidate.sort((p, q) => overlap(x0, x1, q.x0, q.x1) - overlap(x0, x1, p.x0, p.x1));
4868
- owner.set(i, candidate[0]);
4869
- if (grip) candidate[0].grip = grip;
5007
+ const best = candidate[0];
5008
+ owner.set(i, best);
5009
+ if (grip) best.grip = grip;
4870
5010
  });
4871
5011
  const name = objectName(m.type, drawer), parts = [];
4872
5012
  panels.forEach((p, k) => {
@@ -4882,8 +5022,8 @@ function installInteractionItems(K, shared) {
4882
5022
  p.def = def;
4883
5023
  parts.push(def);
4884
5024
  const [ax, az] = localOf(M, cx, front + 0.08);
4885
- shared.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) });
4886
- def.item = shared.inter.items[shared.inter.items.length - 1];
5025
+ 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) });
5026
+ def.item = I().items[I().items.length - 1];
4887
5027
  });
4888
5028
  calls.forEach((c, i) => {
4889
5029
  const p = owner.get(i);
@@ -4897,14 +5037,17 @@ function installInteractionItems(K, shared) {
4897
5037
  }
4898
5038
  cursor.group = parent;
4899
5039
  }
4900
- Object.assign(K, { DOOR_ITEM, DRAWER_ITEM, LIGHT_TYPES, objectName, recordApi, buildItem, lightItem, curtainItem, furnitureItem });
5040
+ const defined = { DOOR_ITEM, DRAWER_ITEM, LIGHT_TYPES, objectName, recordApi, buildItem, lightItem, curtainItem, furnitureItem };
5041
+ Object.assign(K, defined);
4901
5042
  }
4902
5043
 
4903
5044
  // src/interaction/fittings.ts
4904
5045
  function installInteractionFittings(K, shared) {
4905
5046
  const { t, EPS, OPEN_AREA, Y0, applyPiece, bx, cursor, definePiece, gates, lightOn, roomAt, slideDirection, toggleLight, togglePiece } = K;
5047
+ const I = () => shared.inter;
5048
+ const house = () => shared.ctx.r;
4906
5049
  function gatesInteractive() {
4907
- const lt = shared.ctx.r.lot;
5050
+ const lt = house().lot;
4908
5051
  if (!lt) return;
4909
5052
  const cz0 = (lt.rect[1] + lt.rect[3]) / 2;
4910
5053
  const orig = K.getBx(), gs = lt.gates, opening = gs.map((g) => g.open), reg = gs.map((g) => {
@@ -4924,9 +5067,9 @@ function installInteractionFittings(K, shared) {
4924
5067
  return;
4925
5068
  }
4926
5069
  }
4927
- return orig(mat, x0, y0, z0, x1, y1, z1, color);
5070
+ orig(mat, x0, y0, z0, x1, y1, z1, color);
4928
5071
  });
4929
- const n0 = shared.ctx.colliders.length;
5072
+ const colliders = shared.ctx.colliders, n0 = colliders.length;
4930
5073
  try {
4931
5074
  gs.forEach((g) => {
4932
5075
  g.open = false;
@@ -4938,7 +5081,7 @@ function installInteractionFittings(K, shared) {
4938
5081
  g.open = opening[i];
4939
5082
  });
4940
5083
  }
4941
- const cols = shared.ctx.colliders.slice(n0), cz = (lt.rect[1] + lt.rect[3]) / 2, cu = (lt.rect[0] + lt.rect[2]) / 2;
5084
+ const cols = colliders.slice(n0), cz = (lt.rect[1] + lt.rect[3]) / 2, cu = (lt.rect[0] + lt.rect[2]) / 2;
4942
5085
  reg.forEach((r, i) => {
4943
5086
  const g = r.g;
4944
5087
  if (!isFinite(r.x0)) return;
@@ -4947,25 +5090,25 @@ function installInteractionFittings(K, shared) {
4947
5090
  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 }));
4948
5091
  if (p.col) p.col.off = p.target > 0.5;
4949
5092
  const text = () => t(p.target > 0.5 ? "prompt.close" : "prompt.open", { what: t(ped ? "what.pedestrianGate" : "what.garageGate") });
4950
- shared.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 });
5093
+ 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 });
4951
5094
  });
4952
5095
  }
4953
5096
  function mailboxInteractive() {
4954
- for (const m of shared.ctx.r.items) {
5097
+ for (const m of house().items) {
4955
5098
  if (m.type !== "mailbox") continue;
4956
5099
  const g = shared.ctx.parts && shared.ctx.parts["mailbox_" + m.id];
4957
5100
  if (!g) continue;
4958
5101
  const name = "ix:correio:" + m.id, def = definePiece(name, { kind: "part", pivot: [0, 0, 0], ry: 0, parent: "lot" });
4959
5102
  def.inner = g;
4960
5103
  const fx = Math.sin(m.ry || 0), fz = Math.cos(m.ry || 0), ay = (m.y || 1) + (m.h || 0.3) * 0.4;
4961
- shared.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 });
5104
+ 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 });
4962
5105
  applyPiece(def);
4963
5106
  }
4964
5107
  }
4965
5108
  function placeSwitches() {
4966
- const R = shared.ctx.r, used = /* @__PURE__ */ new Set();
5109
+ const R = house(), used = /* @__PURE__ */ new Set();
4967
5110
  for (const c of R.rooms) {
4968
- if (c.type === "void" || OPEN_AREA(c) || !shared.inter.litRooms.has(c.id) || used.has(c.id) || shared.ctx.iv && shared.ctx.iv.switchRooms.has(c.id)) continue;
5111
+ if (c.type === "void" || OPEN_AREA(c) || !I().litRooms.has(c.id) || used.has(c.id) || shared.ctx.iv && shared.ctx.iv.switchRooms.has(c.id)) continue;
4969
5112
  const doors = R.doors.filter((p) => p.floor === c.floor && (p.a === c.id || p.b === c.id));
4970
5113
  doors.sort((p, q) => ((q.exterior ? 1 : 0) - (p.exterior ? 1 : 0)) * (c.type === "living" ? 1 : -1));
4971
5114
  for (const p of doors) if (putSwitch(c, p)) {
@@ -4975,11 +5118,11 @@ function installInteractionFittings(K, shared) {
4975
5118
  }
4976
5119
  }
4977
5120
  function putSwitch(c, p) {
4978
- const R = shared.ctx.r, f = p.floor, alongU = p.axis === "u", L = p.pos, a = p.at - p.width / 2, b = p.at + p.width / 2;
5121
+ 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;
4979
5122
  const wref = R.walls.find((w) => w.floor === f && w.axis === p.axis && Math.abs((alongU ? w.v0 : w.u0) - L) < EPS), th = wref ? wref.thickness || 0.15 : 0.15;
4980
5123
  const inside = (sd2) => {
4981
5124
  const cc = roomAt(f, alongU ? p.at : L + sd2 * 0.4, alongU ? L + sd2 * 0.4 : p.at);
4982
- return cc && cc.id === c.id;
5125
+ return !!cc && cc.id === c.id;
4983
5126
  };
4984
5127
  const sd = inside(1) ? 1 : inside(-1) ? -1 : 0;
4985
5128
  if (!sd) return false;
@@ -5002,19 +5145,22 @@ function installInteractionFittings(K, shared) {
5002
5145
  const piece = 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 });
5003
5146
  piece.t = piece.target = lightOn(roomId) ? 1 : 0;
5004
5147
  const an = alongU ? [u, yc, face + sd * 0.12] : [face + sd * 0.12, yc, u];
5005
- shared.inter.items.push({ type: "light_switch", id: roomId, floor: f, anchor: an, range: 1.5, angle: 0.45, pieces: [piece], text: () => t(lightOn(roomId) ? "prompt.lightOff" : "prompt.lightOn"), action: () => toggleLight(roomId) });
5148
+ I().items.push({ type: "light_switch", id: roomId, floor: f, anchor: an, range: 1.5, angle: 0.45, pieces: [piece], text: () => t(lightOn(roomId) ? "prompt.lightOff" : "prompt.lightOn"), action: () => toggleLight(roomId) });
5006
5149
  return true;
5007
5150
  }
5008
5151
  return false;
5009
5152
  }
5010
- Object.assign(K, { gatesInteractive, mailboxInteractive, placeSwitches, putSwitch });
5153
+ const defined = { gatesInteractive, mailboxInteractive, placeSwitches, putSwitch };
5154
+ Object.assign(K, defined);
5011
5155
  }
5012
5156
 
5013
5157
  // src/interaction/doors.ts
5014
5158
  function installInteractionDoors(K, shared) {
5015
5159
  const { t, colliderChanged, invalidateShadow, applyPiece, hudMessage } = K;
5160
+ const leaves = () => shared.ctx.leaves;
5016
5161
  function linkDoorLeaves() {
5017
- for (const fo of shared.ctx.leaves) fo.handles = (fo.handleNames || []).map((n) => shared.inter.defs.get(n)).filter(Boolean);
5162
+ const I = shared.inter;
5163
+ for (const fo of leaves()) fo.handles = (fo.handleNames || []).map((n) => I.defs.get(n)).filter((d) => !!d);
5018
5164
  }
5019
5165
  function handleApply(fo) {
5020
5166
  for (const mc of fo.handles || []) {
@@ -5024,11 +5170,12 @@ function installInteractionDoors(K, shared) {
5024
5170
  }
5025
5171
  function toggleDoor(fo) {
5026
5172
  if (fo.phase === "rattle") return;
5173
+ const col = fo.col;
5027
5174
  if (fo.phase === "handle" || fo.phase === "swing") {
5028
5175
  fo.open = !fo.open;
5029
5176
  shared.doorState.set(fo.id, fo.open);
5030
- fo.col.off = fo.open;
5031
- colliderChanged(fo.col);
5177
+ col.off = fo.open;
5178
+ colliderChanged(col);
5032
5179
  fo.anim = true;
5033
5180
  fo.phase = "swing";
5034
5181
  return;
@@ -5042,8 +5189,8 @@ function installInteractionDoors(K, shared) {
5042
5189
  }
5043
5190
  fo.open = !fo.open;
5044
5191
  shared.doorState.set(fo.id, fo.open);
5045
- fo.col.off = fo.open;
5046
- colliderChanged(fo.col);
5192
+ col.off = fo.open;
5193
+ colliderChanged(col);
5047
5194
  fo.anim = true;
5048
5195
  shared.ctx.animateDoorsOn = true;
5049
5196
  if (fo.handles && fo.handles.length) {
@@ -5054,7 +5201,7 @@ function installInteractionDoors(K, shared) {
5054
5201
  function animateDoors(dt) {
5055
5202
  if (!shared.ctx.animateDoorsOn) return;
5056
5203
  let active = false;
5057
- for (const fo of shared.ctx.leaves) {
5204
+ for (const fo of leaves()) {
5058
5205
  if (!fo.phase) continue;
5059
5206
  active = true;
5060
5207
  if (fo.phase === "handle") {
@@ -5074,7 +5221,7 @@ function installInteractionDoors(K, shared) {
5074
5221
  handleApply(fo);
5075
5222
  if (fo.hT <= 0) fo.phase = null;
5076
5223
  } else if (fo.phase === "rattle") {
5077
- fo.jig -= dt;
5224
+ fo.jig = (fo.jig ?? 0) - dt;
5078
5225
  fo.hT = fo.jig > 0 ? 0.55 * Math.abs(Math.sin(fo.jig * 26)) : 0;
5079
5226
  handleApply(fo);
5080
5227
  if (fo.jig <= 0) {
@@ -5088,9 +5235,9 @@ function installInteractionDoors(K, shared) {
5088
5235
  invalidateShadow();
5089
5236
  }
5090
5237
  function wallBlocks(ex, ez, ax, az, floor) {
5091
- const n = shared.ctx.wallColliders != null ? shared.ctx.wallColliders : 0;
5238
+ const n = shared.ctx.wallColliders != null ? shared.ctx.wallColliders : 0, colliders = shared.ctx.colliders;
5092
5239
  for (let i = 0; i < n; i++) {
5093
- const c = shared.ctx.colliders[i];
5240
+ const c = colliders[i];
5094
5241
  if (c.f !== floor && !(c.f === -1 && floor === 0)) continue;
5095
5242
  let t0 = 0, t1 = 1;
5096
5243
  const dx = ax - ex, dz = az - ez;
@@ -5120,7 +5267,8 @@ function installInteractionDoors(K, shared) {
5120
5267
  g.updateMatrix();
5121
5268
  }
5122
5269
  }
5123
- Object.assign(K, { linkDoorLeaves, handleApply, toggleDoor, animateDoors, wallBlocks, doorText, applyLeaf });
5270
+ const defined = { linkDoorLeaves, handleApply, toggleDoor, animateDoors, wallBlocks, doorText, applyLeaf };
5271
+ Object.assign(K, defined);
5124
5272
  }
5125
5273
 
5126
5274
  // src/interaction/target.ts
@@ -5130,6 +5278,7 @@ function installInteractionTarget(K, shared) {
5130
5278
  function targetOf(o, opt) {
5131
5279
  if (!o) return null;
5132
5280
  opt = opt || {};
5281
+ const I = shared.inter;
5133
5282
  const ex = o.x, ey = o.y, ez = o.z, floor = o.floor, cp = Math.cos(o.pitch || 0), vx = Math.sin(o.yaw) * cp, vy = Math.sin(o.pitch || 0), vz = Math.cos(o.yaw) * cp;
5134
5283
  let best = null;
5135
5284
  const tries = (score, text, action, target) => {
@@ -5143,16 +5292,16 @@ function installInteractionTarget(K, shared) {
5143
5292
  if (angle > 1.35 && d > 0.9) continue;
5144
5293
  tries(angle * 1.6 + d * 0.5 + (angle < 0.25 ? 0 : 0.6), doorText(fo), () => toggleDoor(fo), fo);
5145
5294
  }
5146
- const vis = shared.inter.pieces.flatMap((p) => p.meshes).filter(visibleChain), hit = vis.length && opt.strike ? opt.strike(vis) : null;
5295
+ const vis = I.pieces.flatMap((p) => p.meshes).filter(visibleChain), hit = vis.length && opt.strike ? opt.strike(vis) : null;
5147
5296
  const kitA = shared.ctx.iv ? ivTarget(shared.ctx.iv, o, opt && opt.interactives) : null;
5148
5297
  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;
5149
5298
  const pieceHit = hit && !nearKit && hit.object.userData.piece;
5150
- for (const it of shared.inter.items) {
5299
+ for (const it of I.items) {
5151
5300
  if (it.floor !== floor && !(it.floor === -1 && floor === 0)) continue;
5152
5301
  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);
5153
5302
  if (dh > it.range + 0.4) continue;
5154
5303
  const angle = Math.acos(Math.max(-1, Math.min(1, (dx * vx + dy * vy + dz * vz) / (d || 1))));
5155
- const byRay = pieceHit && it.pieces.includes(pieceHit) && hit.distance <= it.range + 0.5;
5304
+ const byRay = !!hit && pieceHit && it.pieces.includes(pieceHit) && hit.distance <= it.range + 0.5;
5156
5305
  if (!byRay && !(dh <= it.range && angle <= it.angle)) continue;
5157
5306
  if (!it.noWall && wallBlocks(ex, ez, ax, az, it.floor < 0 ? 0 : it.floor)) continue;
5158
5307
  tries((byRay ? 0 : angle * 2) + d * 0.3 - (byRay ? 1.5 : 0), it.text(), it.action, it);
@@ -5160,10 +5309,12 @@ function installInteractionTarget(K, shared) {
5160
5309
  if (kitA) tries(kitA.score - (nearKit ? 0.5 : 0), kitA.text, kitA.action, kitA.target);
5161
5310
  return best;
5162
5311
  }
5163
- Object.assign(K, { targetOf });
5312
+ const defined = { targetOf };
5313
+ Object.assign(K, defined);
5164
5314
  }
5165
5315
 
5166
5316
  // src/interactables/bridge.ts
5317
+ import { isMesh as isMesh4 } from "@adatechnology/game-shapes-three";
5167
5318
  function installInteractablesBridge(K, shared) {
5168
5319
  const { t, THREE, invalidate, invalidateShadow, cfg, DOC, LIGHT_TYPES, _Y, _q, _v3, accFor, applyLight, cursor, hashString, hudMessage, lightBase, pieceRecord, put, rgbOf, sh, wallBlocks } = K;
5169
5320
  const enter = (...a) => K.enter(...a);
@@ -5217,7 +5368,8 @@ function installInteractablesBridge(K, shared) {
5217
5368
  function ivBuild(h, water) {
5218
5369
  const ik = K.IVK, r = shared.ctx.r, A = ik.A, world0 = null;
5219
5370
  void world0;
5220
- const plane = A.plan(r, { seed: r.seed });
5371
+ const source = r;
5372
+ const plane = A.plan(source, { seed: r.seed });
5221
5373
  const IV = { k: ik, plane, 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 };
5222
5374
  h.IV = IV;
5223
5375
  const t0 = performance.now();
@@ -5236,9 +5388,10 @@ function installInteractablesBridge(K, shared) {
5236
5388
  const wants = (roomId) => lightBase(roomId);
5237
5389
  const entById = new Map(plane.items.map((e) => [e.id, e]));
5238
5390
  const entByItem = new Map(plane.items.map((e) => [e.item, e]));
5239
- IV.mats = { plain: shared.mats.plain, metal: shared.mats.metal, wood: shared.mats.wood, glass: shared.mats.glass, fabric: shared.mats.fabric, plant: shared.mats.plant, water: shared.mats.water, emissive: shared.mats.emissive, atlas_picture: shared.mats.picture, atlas_floor: shared.mats.floor };
5391
+ const mats = shared.mats;
5392
+ IV.mats = { plain: mats.plain, metal: shared.mats.metal, wood: shared.mats.wood, glass: shared.mats.glass, fabric: shared.mats.fabric, plant: shared.mats.plant, water: shared.mats.water, emissive: shared.mats.emissive, atlas_picture: shared.mats.picture, atlas_floor: shared.mats.floor };
5240
5393
  const ev = (e) => ivEvent(h, e);
5241
- const world = IV.world = A.createWorld(r, { water, seed: r.seed, onEvent: ev });
5394
+ const world = IV.world = A.createWorld(source, { water, seed: r.seed, onEvent: ev });
5242
5395
  const add0 = world.add;
5243
5396
  world.add = (id, spec, tr) => {
5244
5397
  const e = entById.get(id);
@@ -5255,7 +5408,7 @@ function installInteractablesBridge(K, shared) {
5255
5408
  }
5256
5409
  return add0(id, spec, tr);
5257
5410
  };
5258
- const added = A.add(world, plane, { isBlocked: A.blockedOf(r), build: (type, item) => ivDraw(IV, entByItem.get(item), type, item) });
5411
+ const added = A.add(world, plane, { isBlocked: A.blockedOf(source), build: (type, item) => ivDraw(IV, entByItem.get(item), type, item) });
5259
5412
  world.add = add0;
5260
5413
  IV.warnings = added.warnings;
5261
5414
  IV.added = added;
@@ -5302,14 +5455,15 @@ function installInteractablesBridge(K, shared) {
5302
5455
  }
5303
5456
  function ivDraw(IV, ent, type, item) {
5304
5457
  const ik = IV.k, loc = Object.assign({}, item, { x: 0, z: 0, ry: 0 });
5458
+ const ix = item.x, iz = item.z, iry = item.ry;
5305
5459
  const mesh = ik.gfx.createMeshApi({ quality: "game", materials: IV.mats, shadows: true, mergeParts: true, swayAmplitude: 0.03 });
5306
5460
  const spec = ik.A.household.build(type, loc, mesh.api);
5307
5461
  const out = mesh.finish(spec);
5308
5462
  for (const l of out.lights) l.removeFromParent();
5309
5463
  const group = ivGroup(ent), g0 = cursor.group, root = new THREE.Group();
5310
5464
  root.name = "iv:" + ent.id;
5311
- root.position.set(item.x, ent.floorY, item.z);
5312
- root.rotation.y = item.ry;
5465
+ root.position.set(ix, ent.floorY, iz);
5466
+ root.rotation.y = iry;
5313
5467
  root.userData.iv = ent.id;
5314
5468
  const screen = spec.devices && spec.devices.some((d) => d.kind === "screen");
5315
5469
  let body = null;
@@ -5318,7 +5472,7 @@ function installInteractablesBridge(K, shared) {
5318
5472
  if (type === "gas_bottle") {
5319
5473
  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"] });
5320
5474
  for (const m of out.group.children) if (!m.name.startsWith("static:")) m.traverse((o) => {
5321
- if (o.isMesh) {
5475
+ if (isMesh4(o)) {
5322
5476
  o.userData.destructionPart = cursor.pc.id;
5323
5477
  o.userData.destructionMaterial = "steel";
5324
5478
  }
@@ -5326,13 +5480,13 @@ function installInteractablesBridge(K, shared) {
5326
5480
  }
5327
5481
  try {
5328
5482
  for (const m of out.group.children.slice()) {
5329
- if (m.isMesh && m.name.startsWith("static:")) {
5483
+ if (isMesh4(m) && m.name.startsWith("static:")) {
5330
5484
  if (screen && m.userData.material === "emissive") {
5331
5485
  body = m;
5332
5486
  root.add(m);
5333
5487
  continue;
5334
5488
  }
5335
- ivAccumulate(IV_MATERIAL[m.userData.material] || "plain", m.geometry, item.x, ent.floorY, item.z, item.ry, null);
5489
+ ivAccumulate(IV_MATERIAL[m.userData.material] || "plain", m.geometry, ix, ent.floorY, iz, iry, null);
5336
5490
  m.geometry.dispose();
5337
5491
  } else root.add(m);
5338
5492
  }
@@ -5342,7 +5496,7 @@ function installInteractablesBridge(K, shared) {
5342
5496
  }
5343
5497
  const base = new Set(Object.values(IV.mats));
5344
5498
  root.traverse((o) => {
5345
- if (!o.isMesh) return;
5499
+ if (!isMesh4(o)) return;
5346
5500
  o.userData.iv = ent.id;
5347
5501
  if (o.castShadow) {
5348
5502
  if (!o.geometry.boundingSphere) o.geometry.computeBoundingSphere();
@@ -5353,7 +5507,7 @@ function installInteractablesBridge(K, shared) {
5353
5507
  roomLightMask(m);
5354
5508
  }
5355
5509
  });
5356
- 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 };
5510
+ 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 };
5357
5511
  IV.entries.set(ent.id, E);
5358
5512
  if (root.children.length) IV.roots.push(E);
5359
5513
  return spec;
@@ -5381,7 +5535,7 @@ function installInteractablesBridge(K, shared) {
5381
5535
  const wire = (spec.wires || []).find((x) => x.id === d.id + "_cord"), pts = (wire ? wire.points : [d.plug]).map((p) => wl(o, p));
5382
5536
  const sid = w.power.pluggedInto(E.id, d.id);
5383
5537
  if (sid) {
5384
- const cut = sid.indexOf(":"), so = w.get(sid.slice(0, cut)), sk = so && so.spec.sockets.find((s) => s.id === sid.slice(cut + 1));
5538
+ const cut = sid.indexOf(":"), so = w.get(sid.slice(0, cut)), sk = so && (so.spec.sockets || []).find((s) => s.id === sid.slice(cut + 1));
5385
5539
  if (so && sk) {
5386
5540
  const sp = wl(so, sk.pos), dir = [Math.sin(so.transform.ry), Math.cos(so.transform.ry)], last = pts[pts.length - 1];
5387
5541
  if (last[1] < 0.3 + E.pos[1]) {
@@ -5416,9 +5570,10 @@ function installInteractablesBridge(K, shared) {
5416
5570
  roomLightMask(sc.material);
5417
5571
  IV.screens.set(E.id, sc);
5418
5572
  }
5419
- E.screen.material = sc.material;
5420
- E.screen.castShadow = false;
5421
- E.screen.receiveShadow = false;
5573
+ const mesh = E.screen;
5574
+ mesh.material = sc.material;
5575
+ mesh.castShadow = false;
5576
+ mesh.receiveShadow = false;
5422
5577
  }
5423
5578
  function ivEvent(h, e) {
5424
5579
  const IV = h.IV;
@@ -5454,16 +5609,17 @@ function installInteractablesBridge(K, shared) {
5454
5609
  IV.itemsDirty = true;
5455
5610
  break;
5456
5611
  }
5457
- if (K.IVK.onEvent) {
5612
+ const ik = K.IVK;
5613
+ if (ik.onEvent) {
5458
5614
  try {
5459
- K.IVK.onEvent(e, h.IV.pub);
5615
+ ik.onEvent(e, IV.pub);
5460
5616
  } catch (err) {
5461
5617
  console.warn("interactables.onEvent", err);
5462
5618
  }
5463
5619
  }
5464
- if (e.type === "seat" && K.IVK.onSeat && e.actor === "player") {
5620
+ if (e.type === "seat" && ik.onSeat && e.actor === "player") {
5465
5621
  try {
5466
- K.IVK.onSeat(e.seated ? ivSeat(IV) : null, e);
5622
+ ik.onSeat(e.seated ? ivSeat(IV) : null, e);
5467
5623
  } catch (err) {
5468
5624
  console.warn("interactables.onSeat", err);
5469
5625
  }
@@ -5472,7 +5628,7 @@ function installInteractablesBridge(K, shared) {
5472
5628
  function ivSeat(IV) {
5473
5629
  const w = IV.world, s = w.seatOf("player");
5474
5630
  if (!s) return null;
5475
- const o = w.get(s.object), seat = o.spec.seats.find((q) => q.id === s.seat), L = IV.k.GI.localToWorld, tr = o.transform, E = IV.entries.get(s.object);
5631
+ const o = w.get(s.object), seat = (o.spec.seats || []).find((q) => q.id === s.seat), L = IV.k.GI.localToWorld, tr = o.transform, E = IV.entries.get(s.object);
5476
5632
  const eye = L(tr, [seat.pos[0], seat.pos[1] + (seat.eye === void 0 ? seat.pose === "lie" ? 0.18 : 0.62 : seat.eye), seat.pos[2]]);
5477
5633
  return { object: s.object, seatInfo: s.seat, pose: seat.pose, eye, yaw: tr.ry + seat.ry, pitch: seat.pose === "lie" ? 0.55 : -0.08, exitPoint: L(tr, seat.exit), floor: E ? E.floor : 0, type: E ? E.type : null };
5478
5634
  }
@@ -5514,18 +5670,19 @@ function installInteractablesBridge(K, shared) {
5514
5670
  }
5515
5671
  }
5516
5672
  const em = w.emitters();
5517
- if (em.length && !IV.efx && K.IVK.effects) {
5673
+ const ivk = K.IVK;
5674
+ if (em.length && !IV.efx && ivk.effects) {
5518
5675
  const g = h.houseGroup;
5519
- IV.efx = ik.gfx.createEffects(g, { maxParticles: 1400, seed: 11, document: DOC, ...K.IVK.effectSink ? { effects: K.IVK.effectSink } : {} });
5676
+ IV.efx = ik.gfx.createEffects(g, { maxParticles: 1400, seed: 11, document: DOC, ...ivk.effectSink ? { effects: ivk.effectSink } : {} });
5520
5677
  }
5521
5678
  if (IV.efx) {
5522
5679
  const alive = IV.efx.stats().alive;
5523
5680
  if (em.length || alive) {
5524
- IV.efx.update(dt, em, K.IVK.camera ? typeof K.IVK.camera === "function" ? K.IVK.camera() : K.IVK.camera : void 0);
5681
+ IV.efx.update(dt, em, ivk.camera ? typeof ivk.camera === "function" ? ivk.camera() : ivk.camera : void 0);
5525
5682
  invalidate();
5526
5683
  }
5527
5684
  }
5528
- if (K.IVK.items && IV.itemsDirty && IV.t - IV.itemsT > 0.1 && !IV.anim.size) ivItems(IV, h);
5685
+ if (ivk.items && IV.itemsDirty && IV.t - IV.itemsT > 0.1 && !IV.anim.size) ivItems(IV, h);
5529
5686
  }
5530
5687
  const IV_SHAPE = {
5531
5688
  can: [["cyl", 1, 1, 1, 0, 1]],
@@ -5560,7 +5717,8 @@ function installInteractablesBridge(K, shared) {
5560
5717
  if (c.access && w.partT(E.id, c.access) < 0.02) continue;
5561
5718
  const st = w.contents(E.id, c.id);
5562
5719
  for (let i = 0; i < st.length; i++) {
5563
- if (st[i] && items[st[i].type]) list.push([E, c.id, i, items[st[i].type]]);
5720
+ const stack = st[i];
5721
+ if (stack && items[stack.type]) list.push([E, c.id, i, items[stack.type]]);
5564
5722
  }
5565
5723
  }
5566
5724
  }
@@ -5589,12 +5747,13 @@ function installInteractablesBridge(K, shared) {
5589
5747
  gm.setIndex(new THREE.BufferAttribute(A.i.slice(0, A.ni), 1));
5590
5748
  gm.computeBoundingSphere();
5591
5749
  if (!IV.items) {
5592
- IV.items = new THREE.Mesh(gm, shared.mats.plain);
5593
- IV.items.name = "iv-items";
5594
- IV.items.castShadow = false;
5595
- IV.items.receiveShadow = true;
5596
- IV.items.frustumCulled = false;
5597
- h.houseGroup.add(IV.items);
5750
+ const mesh = new THREE.Mesh(gm, shared.mats.plain);
5751
+ IV.items = mesh;
5752
+ mesh.name = "iv-items";
5753
+ mesh.castShadow = false;
5754
+ mesh.receiveShadow = true;
5755
+ mesh.frustumCulled = false;
5756
+ h.houseGroup.add(mesh);
5598
5757
  } else {
5599
5758
  IV.items.geometry.dispose();
5600
5759
  IV.items.geometry = gm;
@@ -5728,7 +5887,8 @@ function installInteractablesBridge(K, shared) {
5728
5887
  };
5729
5888
  return IV.pub;
5730
5889
  }
5731
- 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 });
5890
+ 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 };
5891
+ Object.assign(K, defined);
5732
5892
  }
5733
5893
 
5734
5894
  // src/animation/clotheslines.ts
@@ -5753,7 +5913,8 @@ function installAnimationClotheslines(K, shared) {
5753
5913
  }
5754
5914
  invalidate();
5755
5915
  }
5756
- Object.assign(K, { WIND, animateClotheslines });
5916
+ const defined = { WIND, animateClotheslines };
5917
+ Object.assign(K, defined);
5757
5918
  }
5758
5919
 
5759
5920
  // src/build/instance.ts
@@ -5778,7 +5939,8 @@ function installBuildInstance(K, shared) {
5778
5939
  shared.quality = h.quality;
5779
5940
  }
5780
5941
  const tagDamage = (type) => ({ type, hp: HP[type], hpMax: HP[type] });
5781
- Object.assign(K, { props, TYPES, newState, enter, tagDamage });
5942
+ const defined = { props, TYPES, newState, enter, tagDamage };
5943
+ Object.assign(K, defined);
5782
5944
  }
5783
5945
 
5784
5946
  // src/interactables/kit.ts
@@ -5807,17 +5969,20 @@ function installInteractablesKit(K, shared) {
5807
5969
  for (const k of ["wood", "foliage", "flowers", "fruit", "spines"]) roomLightMask(m[k]);
5808
5970
  return m;
5809
5971
  })());
5810
- Object.assign(K, { IVK, VEG, vegMaterials });
5972
+ const defined = { IVK, VEG, vegMaterials };
5973
+ Object.assign(K, defined);
5811
5974
  }
5812
5975
 
5813
5976
  // src/lights/room-light.ts
5977
+ 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 });
5814
5978
  function installLightsRoomLight(K, shared) {
5815
5979
  const { THREE, rectsOf: rectsOf2, cfg } = K;
5816
5980
  const MAX_LIGHTS = 12, EMPTY = [1e9, 1e9, -1e9, -1e9];
5817
5981
  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 } };
5818
5982
  for (let i = 0; i < MAX_LIGHTS; i++) for (const k of ["uRB0", "uRB1", "uRB2", "uREx"]) LZU[k].value.set(EMPTY, i * 4);
5819
- function roomLightMask(m) {
5820
- if (!m || m.userData && m.userData.roomLightMask || !(m.isMeshLambertMaterial || m.isMeshPhongMaterial || m.isMeshStandardMaterial || m.isMeshPhysicalMaterial)) return m;
5983
+ function roomLightMask(material) {
5984
+ const m = material;
5985
+ if (!m || m.userData && m.userData.roomLightMask || !(m.isMeshLambertMaterial || m.isMeshPhongMaterial || m.isMeshStandardMaterial || m.isMeshPhysicalMaterial)) return material;
5821
5986
  m.userData = m.userData || {};
5822
5987
  m.userData.roomLightMask = true;
5823
5988
  const prev = m.onBeforeCompile, pk = m.customProgramCacheKey;
@@ -5845,12 +6010,13 @@ function installLightsRoomLight(K, shared) {
5845
6010
  return (pk ? pk.call(this) : "") + "|rm1";
5846
6011
  };
5847
6012
  m.needsUpdate = true;
5848
- return m;
6013
+ return material;
5849
6014
  }
5850
- function lighting(o) {
5851
- o = o || {};
6015
+ function lighting(options) {
6016
+ const o = options || {};
5852
6017
  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;
5853
- for (const k of Object.keys(shared.mats)) roomLightMask(shared.mats[k]);
6018
+ const mats = shared.mats;
6019
+ for (const k of Object.keys(mats)) roomLightMask(mats[k]);
5854
6020
  const budget = o.budget, lease = budget ? budget.lease({ owner: "floorplan.rooms", point: N, shadows: NS }) : null;
5855
6021
  if (budget && !lease) throw new Error("lighting: the LightBudget has no " + N + " free point slots (" + NS + " with shadow) for the rooms");
5856
6022
  if (budget) for (const [key, width] of [["uRB0", 4], ["uRB1", 4], ["uRB2", 4], ["uRBY", 2], ["uREx", 4]]) {
@@ -5901,9 +6067,8 @@ function installLightsRoomLight(K, shared) {
5901
6067
  }
5902
6068
  for (let i = 0; i < NS; i++) PL[i].shadow.needsUpdate = true;
5903
6069
  };
5904
- A.update = function(houses, focus, op) {
5905
- op = op || {};
5906
- houses = (Array.isArray(houses) ? houses : [houses]).filter(Boolean);
6070
+ A.update = function(houseOrList, focus, options2) {
6071
+ const op = options2 || {}, houses = (Array.isArray(houseOrList) ? houseOrList : [houseOrList]).filter((h) => !!h);
5907
6072
  _f.set(focus.x, focus.y, focus.z);
5908
6073
  const rooms = [], exterior = [];
5909
6074
  for (const house of houses) {
@@ -5915,7 +6080,7 @@ function installLightsRoomLight(K, shared) {
5915
6080
  if (!house.lightOn(l.roomId)) continue;
5916
6081
  const k = l.type === "outdoor" ? "ext:" + (l.id || exterior.length) : l.roomId != null ? l.roomId : l.room;
5917
6082
  let g = by.get(k);
5918
- if (!g) by.set(k, g = { k, house, ls: [], exterior: l.type === "outdoor" });
6083
+ if (!g) by.set(k, g = newGroup(k, house, l.type === "outdoor"));
5919
6084
  g.ls.push(l);
5920
6085
  }
5921
6086
  for (const g of by.values()) {
@@ -5950,9 +6115,10 @@ function installLightsRoomLight(K, shared) {
5950
6115
  }
5951
6116
  }
5952
6117
  g.exclusion = [x0 + 0.03, z0 + 0.03, x1 - 0.03, z1 - 0.03];
5953
- g.lumens = ls[0].lumens != null ? ls[0].lumens : 3.2;
5954
- g.dist = ls[0].dist != null ? ls[0].dist : 5.5;
5955
- g.decay = ls[0].decay != null ? ls[0].decay : 2;
6118
+ const l0 = ls[0];
6119
+ g.lumens = l0.lumens != null ? l0.lumens : 3.2;
6120
+ g.dist = l0.dist != null ? l0.dist : 5.5;
6121
+ g.decay = l0.decay != null ? l0.decay : 2;
5956
6122
  } else {
5957
6123
  const c = house.r.rooms.find((q) => q.id === g.k);
5958
6124
  if (!c) continue;
@@ -6053,8 +6219,8 @@ function installLightsRoomLight(K, shared) {
6053
6219
  }
6054
6220
  const effectsByBudget = /* @__PURE__ */ new WeakMap();
6055
6221
  const OPENING_REACH = 2.5, OPENING_SIDE = 0.6;
6056
- function effectLights(o) {
6057
- o = o || {};
6222
+ function effectLights(options) {
6223
+ const o = options || {};
6058
6224
  const budget = o.budget;
6059
6225
  if (!budget) throw new Error("effectLights: a LightBudget is required");
6060
6226
  const known = effectsByBudget.get(budget);
@@ -6132,7 +6298,7 @@ function installLightsRoomLight(K, shared) {
6132
6298
  const A = {
6133
6299
  /** 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. */
6134
6300
  update(houses) {
6135
- const indoors = cfg.effectLightsIndoors !== false, list = (Array.isArray(houses) ? houses : [houses]).filter(Boolean), cache2 = /* @__PURE__ */ new Map();
6301
+ const indoors = cfg.effectLightsIndoors !== false, list = (Array.isArray(houses) ? houses : [houses]).filter((h) => !!h), cache2 = /* @__PURE__ */ new Map();
6136
6302
  for (let at = 0; at < size; at++) {
6137
6303
  if (ours.has(at)) continue;
6138
6304
  const light = budget.group.children[at];
@@ -6160,12 +6326,13 @@ function installLightsRoomLight(K, shared) {
6160
6326
  if (!o.ours) effectsByBudget.set(budget, A);
6161
6327
  return A;
6162
6328
  }
6163
- Object.assign(K, { MAX_LIGHTS, EMPTY, LZU, roomLightMask, lighting, effectLights });
6329
+ const defined = { MAX_LIGHTS, EMPTY, LZU, roomLightMask, lighting, effectLights };
6330
+ Object.assign(K, defined);
6164
6331
  }
6165
6332
 
6166
6333
  // src/destruction/pieces.ts
6167
6334
  import { assemblyPart, getAssembly } from "@adatechnology/game-destruction";
6168
- import { DENSITY, MEMBER_CAGE, toDestructibleSpec } from "@adatechnology/game-floorplan-structure";
6335
+ import { DENSITY, MEMBER_CAGE, cageResidualCapacity, toDestructibleSpec } from "@adatechnology/game-floorplan-structure";
6169
6336
 
6170
6337
  // src/destruction/panels.ts
6171
6338
  import { resolveSlabPanels, slabPanelView } from "@adatechnology/game-floorplan-structure";
@@ -6345,7 +6512,8 @@ function installDestructionPieces(K, shared) {
6345
6512
  if (!pc || pc.unit) return sp;
6346
6513
  if (pc.role !== "wall" && pc.role !== "partition") {
6347
6514
  const def = getAssembly(pc.assembly || (pc.material === "concrete" && ["slab", "beam", "column", "stair"].includes(pc.role) ? "reinforced_concrete" : ""));
6348
- const out = def && def.reinforcement && !sp.reinforcement ? { ...sp, reinforcement: { ...def.reinforcement } } : sp;
6515
+ const cage = def && def.reinforcement ? pc.role === "column" && sp.shape.kind === "box" ? { ...def.reinforcement, residualCapacity: cageResidualCapacity(sp.shape.size, def.reinforcement, sp.structure?.capacity) } : { ...def.reinforcement } : null;
6516
+ const out = cage && !sp.reinforcement ? { ...sp, reinforcement: cage } : sp;
6349
6517
  if (out.reinforcement && !out.units && pc.material === "concrete" && (pc.role === "beam" || pc.role === "column") && sp.shape.kind === "box") {
6350
6518
  return { ...out, units: { size: [MEMBER_CAGE.unit, MEMBER_CAGE.unit, Math.min(...sp.shape.size)], bond: "stack", mortar: "concrete" } };
6351
6519
  }
@@ -6374,6 +6542,7 @@ function collapseRange(mesh, v0, v1) {
6374
6542
  const a = pos.array;
6375
6543
  const u = mesh.userData;
6376
6544
  if (!u._p0) u._p0 = a.slice();
6545
+ if (!u.plainPositions) Object.defineProperty(u, "plainPositions", { value: u._p0, enumerable: false, configurable: true, writable: true });
6377
6546
  const list = u.collapsedRanges ?? (u.collapsedRanges = []);
6378
6547
  if (!list.some((r) => r[0] === v0 && r[1] === v1)) list.push([v0, v1]);
6379
6548
  const saved = a.slice(v0 * 3, v1 * 3);
@@ -6457,10 +6626,11 @@ function installDestructionBreach(K, _shared) {
6457
6626
  const v = house.worldToLocal(tmp.p.set(p[0], p[1], p[2]));
6458
6627
  return [v.x, v.y, v.z];
6459
6628
  };
6460
- function cells(part, units) {
6629
+ function cells(part, units, mask) {
6461
6630
  const [u0, v0, u1, v1] = part.aabb;
6462
- const alongU = u1 - u0 >= v1 - v0;
6631
+ const alongU = mask.alongU;
6463
6632
  const len = alongU ? u1 - u0 : v1 - v0;
6633
+ const offset = (alongU ? u0 : v0) - mask.start;
6464
6634
  const [ul, uh] = units.size;
6465
6635
  const rows = Math.max(1, Math.round((part.y1 - part.y0) / uh));
6466
6636
  const rowH = (part.y1 - part.y0) / rows;
@@ -6471,7 +6641,7 @@ function installDestructionBreach(K, _shared) {
6471
6641
  const shift = units.bond === "running" && r & 1 ? w / 2 : 0;
6472
6642
  for (let i = 0; i < per + (shift ? 1 : 0); i++) {
6473
6643
  const a = Math.max(0, i * w - shift), b = Math.min(len, i * w - shift + w);
6474
- if (b - a > 1e-3) out.push({ a, b, y0: part.y0 + r * rowH, y1: part.y0 + (r + 1) * rowH, r, i });
6644
+ if (b - a > 1e-3) out.push({ a: offset + a, b: offset + b, y0: part.y0 + r * rowH, y1: part.y0 + (r + 1) * rowH, r, i });
6475
6645
  }
6476
6646
  }
6477
6647
  return out;
@@ -6485,8 +6655,21 @@ function installDestructionBreach(K, _shared) {
6485
6655
  for (const q of structure.parts) {
6486
6656
  if (q.id !== partId && same(q.aabb, part.aabb) && Math.abs(q.y1 - part.y0) < 0.01 && structure.meshesOf(q.id).some((it) => it.mesh)) return q.id;
6487
6657
  }
6658
+ return part.role === "column" ? wallAround(part) : null;
6659
+ }
6660
+ function wallAround(part) {
6661
+ const cu = (part.aabb[0] + part.aabb[2]) / 2, cv = (part.aabb[1] + part.aabb[3]) / 2;
6662
+ for (const q of structure.parts) {
6663
+ if (q.id === part.id || q.role !== "wall" && q.role !== "partition" || !structure.meshesOf(q.id).some((it) => it.mesh)) continue;
6664
+ const inside = cu >= q.aabb[0] - 1e-3 && cu <= q.aabb[2] + 1e-3 && cv >= q.aabb[1] - 1e-3 && cv <= q.aabb[3] + 1e-3;
6665
+ if (inside && Math.min(q.y1, part.y1) - Math.max(q.y0, part.y0) > 0.5) return q.id;
6666
+ }
6488
6667
  return null;
6489
6668
  }
6669
+ const pillarSpans = (view) => structure.parts.filter((q) => q.role === "column" && wallAround(q) === view.host).map((q) => {
6670
+ const a = (view.mask.alongU ? q.aabb[0] : q.aabb[1]) - view.mask.start, b = (view.mask.alongU ? q.aabb[2] : q.aabb[3]) - view.mask.start;
6671
+ return { a, b, y0: q.y0, y1: q.y1 };
6672
+ });
6490
6673
  const riders = (hostId) => structure.parts.filter((q) => q.id !== hostId && specOf(q.id)?.units && hostOf(q.id) === hostId && !structure.meshesOf(q.id).some((it) => it.mesh)).map((q) => q.id);
6491
6674
  function shell(it, mask) {
6492
6675
  const g0 = it.mesh.geometry, g = new THREE.BufferGeometry();
@@ -6575,6 +6758,17 @@ function installDestructionBreach(K, _shared) {
6575
6758
  texture.needsUpdate = true;
6576
6759
  return { data, texture, w, h, alongU, start: alongU ? u0 : v0, len, y0, height: y1 - y0, rect: new THREE.Vector4(alongU ? u0 : v0, y0, len, y1 - y0) };
6577
6760
  }
6761
+ function besidePillars(c, pillars) {
6762
+ let { a, b } = c;
6763
+ for (const k of pillars) {
6764
+ if (c.y1 <= k.y0 || c.y0 >= k.y1 || b <= k.a || a >= k.b) continue;
6765
+ const centre = (a + b) / 2;
6766
+ if (centre > k.a && centre < k.b) return [];
6767
+ if (centre <= k.a) b = Math.min(b, k.a);
6768
+ else a = Math.max(a, k.b);
6769
+ }
6770
+ return b - a > 1e-3 ? [{ ...c, a, b }] : [];
6771
+ }
6578
6772
  const boxDistance = (s, y, a, b, c, d) => Math.hypot(Math.max(a - s, 0, s - b), Math.max(c - y, 0, y - d));
6579
6773
  const ellipseDistance = (s, y, cs, cy, rs, ry) => (Math.hypot((s - cs) / Math.max(rs, 1e-4), (y - cy) / Math.max(ry, 1e-4)) - 1) * Math.min(rs, ry);
6580
6774
  function covered(c, boxes) {
@@ -6597,9 +6791,15 @@ function installDestructionBreach(K, _shared) {
6597
6791
  const discs = [];
6598
6792
  const flakes = [];
6599
6793
  const shown = [];
6794
+ const pillars = pillarSpans(view);
6600
6795
  for (const id of view.parts) {
6601
6796
  const part = structure.byId.get(id), units2 = specOf(id).units, chips = view.chips.get(id), opening = view.openings.get(id), spalls = view.spalls.get(id);
6602
- const all = cells(part, units2);
6797
+ const own = cells(part, units2, mask);
6798
+ const all = id === view.host ? own.flatMap((c) => besidePillars(c, pillars)) : own;
6799
+ if (view.fallen.has(id)) {
6800
+ holes.push(...all);
6801
+ continue;
6802
+ }
6603
6803
  const thick = mask.alongU ? part.aabb[3] - part.aabb[1] : part.aabb[2] - part.aabb[0];
6604
6804
  const mid = mask.alongU ? (part.aabb[1] + part.aabb[3]) / 2 : (part.aabb[0] + part.aabb[2]) / 2;
6605
6805
  if (opening) discs.push({ s: along(opening.center), y: opening.center[1], r: opening.radius });
@@ -6695,52 +6895,55 @@ function installDestructionBreach(K, _shared) {
6695
6895
  }
6696
6896
  return { center: local(chip.center), along: a, up: u };
6697
6897
  }
6898
+ function newView(hostId) {
6899
+ const items = structure.meshesOf(hostId).filter((it) => it.mesh);
6900
+ if (!items.length) return null;
6901
+ const parts = [hostId, ...riders(hostId)].filter((id) => structure.byId.get(id) && specOf(id)?.units);
6902
+ const mask = maskOf(hostId, parts), core = maskOf(hostId, parts);
6903
+ return {
6904
+ host: hostId,
6905
+ parts,
6906
+ items,
6907
+ mask,
6908
+ core,
6909
+ unitMaterial: unitsMaterial(core),
6910
+ shells: [],
6911
+ saved: null,
6912
+ units: null,
6913
+ gone: 0,
6914
+ pits: 0,
6915
+ bounds: drawnBounds(items),
6916
+ chips: new Map(parts.map((id) => [id, []])),
6917
+ spalls: new Map(parts.map((id) => [id, []])),
6918
+ openings: /* @__PURE__ */ new Map(),
6919
+ flakes: 0,
6920
+ fallen: /* @__PURE__ */ new Set()
6921
+ };
6922
+ }
6923
+ function cut(view) {
6924
+ if (view.saved) return;
6925
+ view.shells = view.items.map((it) => shell(it, view.mask));
6926
+ for (const m of view.shells) m.userData.behind = () => view.units;
6927
+ view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
6928
+ }
6698
6929
  function draw(partId, change) {
6699
6930
  if (lod !== 0) return false;
6700
6931
  const hostId = hostOf(partId);
6701
6932
  if (!hostId || !specOf(partId)?.units) return false;
6702
- let view = views.get(hostId);
6703
- if (!view) {
6704
- const items = structure.meshesOf(hostId).filter((it) => it.mesh);
6705
- if (!items.length) return false;
6706
- const parts = [hostId, ...riders(hostId)].filter((id) => structure.byId.get(id) && specOf(id)?.units);
6707
- if (!parts.includes(partId)) return false;
6708
- const mask = maskOf(hostId, parts), core = maskOf(hostId, parts);
6709
- view = {
6710
- host: hostId,
6711
- parts,
6712
- items,
6713
- mask,
6714
- core,
6715
- unitMaterial: unitsMaterial(core),
6716
- shells: [],
6717
- saved: null,
6718
- units: null,
6719
- gone: 0,
6720
- pits: 0,
6721
- bounds: drawnBounds(items),
6722
- chips: new Map(parts.map((id) => [id, []])),
6723
- spalls: new Map(parts.map((id) => [id, []])),
6724
- openings: /* @__PURE__ */ new Map(),
6725
- flakes: 0
6726
- };
6727
- }
6728
- if (!view.chips.has(partId)) return false;
6933
+ const view = views.get(hostId) ?? newView(hostId);
6934
+ if (!view || !view.chips.has(partId)) return false;
6729
6935
  if (change.opening) {
6730
6936
  if (view.openings.has(partId)) return false;
6731
6937
  view.openings.set(partId, { center: local(change.opening.center), radius: change.opening.radius });
6732
6938
  }
6733
6939
  if (change.chip) view.chips.get(partId).push(chipBox(change.chip, view.mask.alongU));
6940
+ for (const chip of change.chips ?? []) view.chips.get(partId).push(chipBox(chip, view.mask.alongU));
6734
6941
  if (change.spall) {
6735
6942
  const list = view.spalls.get(partId);
6736
6943
  list.push({ center: local(change.spall.center), radius: change.spall.radius });
6737
6944
  if (list.length > MAX_FLAKES) list.shift();
6738
6945
  }
6739
- if (!view.saved) {
6740
- view.shells = view.items.map((it) => shell(it, view.mask));
6741
- for (const m of view.shells) m.userData.behind = () => view.units;
6742
- view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
6743
- }
6946
+ cut(view);
6744
6947
  views.set(hostId, view);
6745
6948
  if (opts.deferPaint && change.spall) dirty.add(view);
6746
6949
  else {
@@ -6851,14 +7054,32 @@ function installDestructionBreach(K, _shared) {
6851
7054
  */
6852
7055
  chip(event) {
6853
7056
  if (event.torn) return false;
6854
- return draw(event.part, { chip: { center: event.center, size: event.size ?? [0, 0, 0], rotation: event.rotation ?? [0, 0, 0, 1] } });
7057
+ const rotation = event.rotation ?? [0, 0, 0, 1];
7058
+ if (event.units?.length) return draw(event.part, { chips: event.units.map((unit) => ({ center: unit.center, size: unit.size, rotation })) });
7059
+ return draw(event.part, { chip: { center: event.center, size: event.size ?? [0, 0, 0], rotation } });
6855
7060
  },
6856
7061
  /** The part broke or fell: its damage goes (the plain range stays collapsed, the renderer hides the part). */
6857
7062
  drop(partId) {
6858
- const v = views.get(partId);
6859
- if (!v) return;
7063
+ let host = views.get(partId) ?? [...views.values()].find((view) => view.parts.includes(partId));
7064
+ if (!host && lod === 0 && riders(partId).length > 0) {
7065
+ host = newView(partId);
7066
+ if (host) {
7067
+ cut(host);
7068
+ views.set(partId, host);
7069
+ }
7070
+ }
7071
+ if (!host) return;
7072
+ host.fallen.add(partId);
7073
+ if (host.parts.some((id) => !host.fallen.has(id))) {
7074
+ dirty.delete(host);
7075
+ paint(host);
7076
+ invalidate();
7077
+ invalidateShadow();
7078
+ return;
7079
+ }
7080
+ const v = host;
6860
7081
  dispose(v);
6861
- views.delete(partId);
7082
+ views.delete(v.host);
6862
7083
  if (v.saved) dropped.push(v);
6863
7084
  },
6864
7085
  /** LOD 0 draws the cut wall; LOD 1 and 2 give the wall its box back. */
@@ -7298,10 +7519,11 @@ function installDestructionWorld(K, shared) {
7298
7519
 
7299
7520
  // src/build/build.ts
7300
7521
  import { markKitOrigin } from "@adatechnology/game-contracts";
7522
+ import { isMesh as isMesh5 } from "@adatechnology/game-shapes-three";
7301
7523
  function installBuildBuild(K, shared) {
7302
7524
  const { THREE, cfg, rectsOf: rectsOf2, invalidateShadow, colliderChanged, VERSION: VERSION2, CARS, EPS, 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;
7303
- function build(r0, opts) {
7304
- opts = opts || {};
7525
+ function build(r0, options) {
7526
+ const opts = options || {};
7305
7527
  const r = applyOutbuildings(r0);
7306
7528
  const t0 = performance.now();
7307
7529
  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 };
@@ -7322,7 +7544,7 @@ function installBuildBuild(K, shared) {
7322
7544
  shared.ctx.pieces = /* @__PURE__ */ new Map();
7323
7545
  shared.ctx.pieceObjects = /* @__PURE__ */ new Map();
7324
7546
  shared.ctx.structureIndex = {};
7325
- for (const e of r0.structure && r0.structure.parts || []) shared.ctx.structureIndex[e.id] = e;
7547
+ for (const e of r0.structure?.parts || []) shared.ctx.structureIndex[e.id] = e;
7326
7548
  {
7327
7549
  const view = shared.ctx.panelView = panelViewOf(r0.structure, !!cfg.destruction);
7328
7550
  shared.ctx.panelsOf = /* @__PURE__ */ new Map();
@@ -7334,17 +7556,18 @@ function installBuildBuild(K, shared) {
7334
7556
  else shared.ctx.panelsOf.set(e.slab, [e]);
7335
7557
  }
7336
7558
  }
7337
- shared.ctx.panes = r0.roof && r0.roof.panes || [];
7559
+ shared.ctx.panes = r0.roof?.panes || [];
7338
7560
  shared.ctx.noPiece = false;
7339
7561
  cursor.separate = opts.pieces === "meshes";
7340
7562
  cursor.pc = null;
7563
+ shared.ctx.showPillars = opts.pillars !== "hidden";
7341
7564
  shared.ctx.apartment = r.template === "apartment_modern";
7342
7565
  shared.ctx.pa = Math.max(3, Math.min(20, pr.floors != null ? pr.floors : 5));
7343
7566
  shared.ctx.pf = Math.max(1, Math.min(shared.ctx.pa, pr.floor != null ? pr.floor : 3));
7344
7567
  shared.ctx.pu = Math.max(0, pr.unit != null ? pr.unit : 0);
7345
7568
  shared.ctx.showBuilding = shared.ctx.apartment && (pr.showIt == null ? true : !!pr.showIt);
7346
7569
  shared.ctx.limits = { x0: -2, z0: -2, x1: r.w + 2, z1: r.d + 2 };
7347
- shared.ctx.veg = VEG ? { G: VEG.G, S: VEG.S, mats: vegMaterials, groups: /* @__PURE__ */ new Map(), ok: /* @__PURE__ */ new Map(), opts: shared.quality === "game" ? { quality: "game" } : { lod: 0, triangleBudget: 6e4 } } : null;
7570
+ shared.ctx.veg = VEG ? { G: VEG.G, S: VEG.S, mats: vegMaterials, groups: /* @__PURE__ */ new Map(), ok: /* @__PURE__ */ new Map(), opts: shared.quality === "game" ? { quality: "game" } : { quality: "high", lod: 0, triangleBudget: 6e4 } } : null;
7348
7571
  shared.ctx.vegInfo = null;
7349
7572
  terrain();
7350
7573
  if (r.lot) {
@@ -7394,7 +7617,7 @@ function installBuildBuild(K, shared) {
7394
7617
  const g = gs[gd.name];
7395
7618
  if (!g) continue;
7396
7619
  delete gs[gd.name];
7397
- g.position.set(...gd.pos);
7620
+ g.position.fromArray(gd.pos);
7398
7621
  parent.add(g);
7399
7622
  fo.gs.push(g);
7400
7623
  }
@@ -7409,7 +7632,7 @@ function installBuildBuild(K, shared) {
7409
7632
  root.add(house);
7410
7633
  shared.mirrors.house = house;
7411
7634
  if (shared.ctx.apartment) {
7412
- const u = r.building.units[Math.min(shared.ctx.pu, r.building.units.length - 1)];
7635
+ const units = r.building.units, u = units[Math.min(shared.ctx.pu, units.length - 1)];
7413
7636
  house.position.set(u.u, shared.ctx.showBuilding ? 0 : -r.floors[0].y0, u.v);
7414
7637
  house.rotation.y = u.ry;
7415
7638
  shared.ctx.unitRy = u.ry;
@@ -7525,7 +7748,8 @@ function installBuildBuild(K, shared) {
7525
7748
  const wallAt = (f, axis, L) => r.walls.find((w) => w.floor === f && w.axis === axis && Math.abs((axis === "u" ? w.v0 : w.u0) - L) < EPS);
7526
7749
  for (const j of r.windows) {
7527
7750
  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;
7528
- 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: () => {
7751
+ const jy0 = j.y0, jy1 = j.y1;
7752
+ 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: () => {
7529
7753
  }, t: 0 };
7530
7754
  }
7531
7755
  for (const E of mirrorsCopy) {
@@ -7568,7 +7792,7 @@ function installBuildBuild(K, shared) {
7568
7792
  const countDraw = () => {
7569
7793
  let n = 0, t = 0;
7570
7794
  root.traverseVisible((o) => {
7571
- if (o.isMesh) {
7795
+ if (isMesh5(o)) {
7572
7796
  n++;
7573
7797
  t += (o.geometry.index ? o.geometry.index.count : o.geometry.attributes.position.count) / 3;
7574
7798
  }
@@ -7582,8 +7806,8 @@ function installBuildBuild(K, shared) {
7582
7806
  const budget = opts.drawCallBudget != null ? opts.drawCallBudget : cfg.drawCallBudget;
7583
7807
  const stats = { 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 };
7584
7808
  shared.ctx.tBuild = stats.tBuild;
7585
- const applyLod = (n) => {
7586
- n = Math.max(0, Math.min(2, n | 0));
7809
+ const applyLod = (level) => {
7810
+ const n = Math.max(0, Math.min(2, level | 0));
7587
7811
  if (n === h.lodCurrent) return;
7588
7812
  h.lodCurrent = n;
7589
7813
  for (const o of lodObjects) o.visible = n < 1;
@@ -7660,7 +7884,7 @@ function installBuildBuild(K, shared) {
7660
7884
  lights: (() => {
7661
7885
  const by = {};
7662
7886
  for (const l of shared.ctx.lights) {
7663
- const k = l.roomId != null ? l.roomId : l.room;
7887
+ const k = String(l.roomId != null ? l.roomId : l.room);
7664
7888
  (by[k] || (by[k] = [])).push(l);
7665
7889
  }
7666
7890
  return { list: shared.ctx.lights, byRoom: by };
@@ -7700,9 +7924,9 @@ function installBuildBuild(K, shared) {
7700
7924
  applyLod(Math.max(n, h.lodMin));
7701
7925
  }
7702
7926
  },
7703
- show(o) {
7927
+ show(options2) {
7704
7928
  enter(h);
7705
- o = o || {};
7929
+ const o = options2 || {};
7706
7930
  const rr = shared.ctx.r, nA = rr.floors.length, a = o.floor == null ? -1 : o.floor, sel = a >= nA ? -1 : a, cut = !!o.cut;
7707
7931
  for (const [k, g] of Object.entries(gs)) {
7708
7932
  let v = true;
@@ -7722,7 +7946,7 @@ function installBuildBuild(K, shared) {
7722
7946
  enter(h);
7723
7947
  const a = targetOf(o, opt);
7724
7948
  if (!a) return false;
7725
- 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);
7949
+ 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);
7726
7950
  },
7727
7951
  message() {
7728
7952
  return shared.inter.msg && performance.now() < shared.inter.msg.until ? shared.inter.msg.text : null;
@@ -7779,13 +8003,13 @@ function installBuildBuild(K, shared) {
7779
8003
  }
7780
8004
  return null;
7781
8005
  },
7782
- partAt(p, tol) {
7783
- tol = tol || 0.05;
8006
+ partAt(p, tolerance) {
8007
+ const tol = tolerance || 0.05;
7784
8008
  let m = null;
7785
8009
  for (const k in parts) {
7786
- const a = parts[k].aabb;
8010
+ const part = parts[k], a = part.aabb;
7787
8011
  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) {
7788
- m = parts[k];
8012
+ m = part;
7789
8013
  break;
7790
8014
  }
7791
8015
  }
@@ -7796,8 +8020,8 @@ function installBuildBuild(K, shared) {
7796
8020
  destruction.deactivate();
7797
8021
  if (h.IV) ivDispose(h);
7798
8022
  root.traverse((o) => {
7799
- if (o.isMesh && o.geometry && !o.geometry.userData.shared) o.geometry.dispose();
7800
- if (o.type === "Reflector" && o.dispose) o.dispose();
8023
+ if (isMesh5(o) && o.geometry && !o.geometry.userData.shared) o.geometry.dispose();
8024
+ if (o.type === "Reflector" && "dispose" in o && typeof o.dispose === "function") o.dispose();
7801
8025
  });
7802
8026
  root.removeFromParent();
7803
8027
  },
@@ -7805,7 +8029,8 @@ function installBuildBuild(K, shared) {
7805
8029
  };
7806
8030
  return res;
7807
8031
  }
7808
- Object.assign(K, { build });
8032
+ const defined = { build };
8033
+ Object.assign(K, defined);
7809
8034
  }
7810
8035
 
7811
8036
  // src/build/api.ts
@@ -7827,11 +8052,13 @@ function buildApi(K, shared) {
7827
8052
  lighting,
7828
8053
  effectLights,
7829
8054
  setNight(n) {
7830
- shared.mats.glass.emissive.set(n ? 9067040 : 0);
7831
- shared.mats.glass.opacity = n ? 0.4 : 0.24;
8055
+ const glass = shared.mats.glass;
8056
+ glass.emissive.set(n ? 9067040 : 0);
8057
+ glass.opacity = n ? 0.4 : 0.24;
7832
8058
  },
7833
8059
  /** 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. */
7834
8060
  deferredQueue: () => K.breachPaintQueue,
8061
+ /* the destruction side is typed with the breach */
7835
8062
  cars: { model: carModel, group: carGroup, info: (k, seed) => {
7836
8063
  const m = carModel(k, seed);
7837
8064
  return m && { parts: m.parts.length, tris: m.tris, L: m.L, W: m.W, H: m.H };
@@ -8096,7 +8323,7 @@ function createHouseScenarios(text, at = SPECIMEN_AT) {
8096
8323
  const stopListening = () => {
8097
8324
  for (const off of listening.splice(0)) off?.();
8098
8325
  };
8099
- const collapsed = (list) => list.filter((e) => e.type === "collapse").flatMap((e) => e.parts.map((p) => p.id || p));
8326
+ const collapsed = (list) => list.flatMap((e) => e.type === "collapse" ? e.parts.map((p) => p.id || p) : []);
8100
8327
  const whole = (room, oid, pid) => {
8101
8328
  const p = room.world.part(oid, pid);
8102
8329
  return !!p && p.status !== "broken" && !p.stripped;
@@ -8133,10 +8360,10 @@ function createHouseScenarios(text, at = SPECIMEN_AT) {
8133
8360
  const list = events(room);
8134
8361
  const columns = groundColumns(parts);
8135
8362
  const laj = slabs(parts);
8136
- const first = columns[0];
8137
- const mate = columns.slice(1).filter((p) => Math.abs(p.position[0] - first.position[0]) < 0.5).sort((a, b) => Math.abs(b.position[2] - first.position[2]) - Math.abs(a.position[2] - first.position[2]))[0] ?? columns[1];
8138
- blunt(room, oid, first.id, centre(first.id), 3e6);
8139
- blunt(room, oid, mate.id, centre(mate.id), 3e6);
8363
+ const first = columns.find((p) => !/^wall_column_/.test(p.id)) ?? columns[0];
8364
+ const mate = columns.filter((p) => p !== first && !/^wall_column_/.test(p.id)).filter((p) => Math.abs(p.position[0] - first.position[0]) < 0.5).sort((a, b) => Math.abs(b.position[2] - first.position[2]) - Math.abs(a.position[2] - first.position[2]))[0] ?? columns[1];
8365
+ const along = columns.filter((p) => /^wall_column_/.test(p.id) && Math.abs(p.position[0] - first.position[0]) < 0.5);
8366
+ for (const p of [first, mate, ...along]) blunt(room, oid, p.id, centre(p.id), 3e6);
8140
8367
  step(90);
8141
8368
  const fell = collapsed(list);
8142
8369
  expect(laj.some((id) => fell.includes(id)), fill(T.two_slab_fell, { n: fell.length }));
@@ -8457,9 +8684,10 @@ function createFloorplanTestModule(options = {}) {
8457
8684
  return best;
8458
8685
  };
8459
8686
  const eyeOf = (p) => {
8687
+ const T = THREE;
8460
8688
  const camera = host?.camera;
8461
8689
  const at = toLocal(p, camera.position.x, camera.position.y, camera.position.z);
8462
- const forward = new THREE.Vector3(0, 0, -1).applyQuaternion(camera.quaternion).transformDirection(new THREE.Matrix4().copy(p.house.group.matrixWorld).invert());
8690
+ const forward = new T.Vector3(0, 0, -1).applyQuaternion(camera.quaternion).transformDirection(new T.Matrix4().copy(p.house.group.matrixWorld).invert());
8463
8691
  return { x: at.x, y: at.y, z: at.z, floor: floorOf(p, camera.position.y), yaw: Math.atan2(forward.x, forward.z), pitch: Math.asin(Math.max(-1, Math.min(1, forward.y))) };
8464
8692
  };
8465
8693
  const blocked = (x, z, radius) => {
@@ -8475,8 +8703,9 @@ function createFloorplanTestModule(options = {}) {
8475
8703
  const standAt = (p, u, v, floor, lookU, lookV) => {
8476
8704
  if (!host?.bench) return;
8477
8705
  const y = p.house.y0(floor) + EYE;
8478
- const eye = p.house.group.localToWorld(new THREE.Vector3(u, y, v));
8479
- const target = p.house.group.localToWorld(new THREE.Vector3(lookU, y - 0.1, lookV));
8706
+ const T = THREE;
8707
+ const eye = p.house.group.localToWorld(new T.Vector3(u, y, v));
8708
+ const target = p.house.group.localToWorld(new T.Vector3(lookU, y - 0.1, lookV));
8480
8709
  host.bench.look([eye.x, eye.y, eye.z], [target.x, target.y, target.z]);
8481
8710
  floorNow = floor;
8482
8711
  };
@@ -8526,16 +8755,17 @@ function createFloorplanTestModule(options = {}) {
8526
8755
  host?.log(fill(text.steps.door, { text: String(target.text) }));
8527
8756
  };
8528
8757
  const doorReach = (p, fo) => {
8758
+ const T = THREE;
8529
8759
  const g = fo.gs[0];
8530
8760
  const pivot = fo.handles[0].pivot;
8531
8761
  const at = (angle) => {
8532
8762
  const c = Math.cos(angle);
8533
8763
  const s = Math.sin(angle);
8534
- const v = new THREE.Vector3(pivot[0] * c + pivot[2] * s, pivot[1], -pivot[0] * s + pivot[2] * c).add(g.position);
8764
+ const v = new T.Vector3(pivot[0] * c + pivot[2] * s, pivot[1], -pivot[0] * s + pivot[2] * c).add(g.position);
8535
8765
  return g.parent ? g.parent.localToWorld(v) : v;
8536
8766
  };
8537
8767
  const camera = host?.camera;
8538
- const eye = new THREE.Vector3(camera.position.x, 0, camera.position.z);
8768
+ const eye = new T.Vector3(camera.position.x, 0, camera.position.z);
8539
8769
  const flat = (v) => Math.hypot(v.x - eye.x, v.z - eye.z);
8540
8770
  const closed = at(0);
8541
8771
  const open = at(fo.rot);
@@ -8543,9 +8773,9 @@ function createFloorplanTestModule(options = {}) {
8543
8773
  return {
8544
8774
  handle: () => {
8545
8775
  g.updateMatrixWorld(true);
8546
- return g.localToWorld(new THREE.Vector3(pivot[0], pivot[1], pivot[2])).toArray();
8776
+ return g.localToWorld(new T.Vector3(pivot[0], pivot[1], pivot[2])).toArray();
8547
8777
  },
8548
- hinge: () => g.getWorldPosition(new THREE.Vector3()).toArray(),
8778
+ hinge: () => g.getWorldPosition(new T.Vector3()).toArray(),
8549
8779
  seconds: fo.locked || fo.blockedFlag ? 0.6 : 0.55,
8550
8780
  pull: opening ? flat(open) <= flat(closed) : flat(closed) <= flat(open),
8551
8781
  locked: !!(fo.locked || fo.blockedFlag)
@@ -8879,4 +9109,4 @@ export {
8879
9109
  FLOORPLAN_AREA_ID,
8880
9110
  createFloorplanTestModule
8881
9111
  };
8882
- //# sourceMappingURL=chunk-QUVGWVEC.js.map
9112
+ //# sourceMappingURL=chunk-Y3Y7NYOL.js.map