@adatechnology/game-items-three 0.7.2 → 0.7.4

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.
@@ -89,7 +89,7 @@ var GameItemsThree = (() => {
89
89
  wearableMaterials: () => wearableMaterials
90
90
  });
91
91
 
92
- // ../game-shapes/dist/chunk-M5N2SHNL.js
92
+ // ../game-shapes/dist/chunk-FZQTELDQ.js
93
93
  function canonicalJson(value) {
94
94
  if (value === null) return "null";
95
95
  if (typeof value === "number") return Object.is(value, -0) ? "-0" : Number.isFinite(value) ? String(value) : JSON.stringify(String(value));
@@ -1001,17 +1001,19 @@ var GameItemsThree = (() => {
1001
1001
  if (p.prevZ) p.prevZ.nextZ = p.nextZ;
1002
1002
  if (p.nextZ) p.nextZ.prevZ = p.prevZ;
1003
1003
  }
1004
- function Node(i, x, y) {
1005
- this.i = i;
1006
- this.x = x;
1007
- this.y = y;
1008
- this.prev = null;
1009
- this.next = null;
1010
- this.z = 0;
1011
- this.prevZ = null;
1012
- this.nextZ = null;
1013
- this.steiner = false;
1014
- }
1004
+ var Node = class {
1005
+ constructor(i, x, y) {
1006
+ this.i = i;
1007
+ this.x = x;
1008
+ this.y = y;
1009
+ this.prev = null;
1010
+ this.next = null;
1011
+ this.z = 0;
1012
+ this.prevZ = null;
1013
+ this.nextZ = null;
1014
+ this.steiner = false;
1015
+ }
1016
+ };
1015
1017
  function signedArea(data, start, end, dim) {
1016
1018
  let sum = 0;
1017
1019
  for (let i = start, j = end - dim; i < end; i += dim) {
@@ -1969,6 +1971,9 @@ var GameItemsThree = (() => {
1969
1971
  }
1970
1972
  return releaseObject3D(list2, { keep });
1971
1973
  }
1974
+ function isMesh(o) {
1975
+ return !!o && o.isMesh === true;
1976
+ }
1972
1977
 
1973
1978
  // src/kit.ts
1974
1979
  var WEAR_TAGS = ["metal", "wood", "cloth", "plastic", "paper", "food", "glass"];
@@ -2731,6 +2736,19 @@ var GameItemsThree = (() => {
2731
2736
  "drink",
2732
2737
  "sticky"
2733
2738
  ]
2739
+ },
2740
+ {
2741
+ id: "mud",
2742
+ color: 4008988,
2743
+ opacity: 0.95,
2744
+ stainColor: 3811866,
2745
+ viscosity: 40,
2746
+ density: 1600,
2747
+ dryTime: 900,
2748
+ gloss: 0.4,
2749
+ tags: [
2750
+ "dirty"
2751
+ ]
2734
2752
  }
2735
2753
  ];
2736
2754
  var LIQUIDS = liquids_default;
@@ -13254,6 +13272,22 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
13254
13272
  return angle === 0 ? q : quat.mul(q, quat.fromAxisAngle([0, 0, 1], angle));
13255
13273
  };
13256
13274
  var clamp = (v, a, b) => Math.max(a, Math.min(b, v));
13275
+ var splitAlong = (box4, count, axis, rnd) => {
13276
+ const shares = Array.from({ length: count }, () => 0.25 + 1.5 * rnd());
13277
+ const total = shares.reduce((sum, share) => sum + share, 0);
13278
+ const out = [];
13279
+ let from = box4.c[axis] - box4.s[axis] / 2;
13280
+ for (const share of shares) {
13281
+ const length = box4.s[axis] * share / total;
13282
+ const c = [box4.c[0], box4.c[1], box4.c[2]];
13283
+ const size = [box4.s[0], box4.s[1], box4.s[2]];
13284
+ c[axis] = from + length / 2;
13285
+ size[axis] = length;
13286
+ out.push({ c, s: size });
13287
+ from += length;
13288
+ }
13289
+ return out;
13290
+ };
13257
13291
  var splinterBox = (inp, box4, limit = inp.maxFragments) => {
13258
13292
  const { rnd } = inp;
13259
13293
  const dims = box4.s;
@@ -13263,35 +13297,81 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
13263
13297
  const w = Math.max(fmin * 1.5, 0.01);
13264
13298
  const c = clamp(Math.round(dims[a] * dims[b] / (w * w)), 3, Math.max(3, Math.floor(limit / 2)));
13265
13299
  const maxLen = fmax * 4;
13266
- const cells = bsp(box4, c, [a, b], rnd);
13300
+ const cells = [];
13301
+ for (const cell of bsp(box4, c, [a, b], rnd)) {
13302
+ const wide = cell.s[a] >= cell.s[b] ? a : b;
13303
+ if (rnd() < 0.4 && cell.s[wide] > fmin * 0.5) for (const part of splitAlong(cell, 2, wide, rnd)) cells.push(part);
13304
+ else cells.push(cell);
13305
+ }
13267
13306
  const pieces = [];
13268
13307
  for (const cell of cells) {
13269
- const extra = rnd() < 0.4 ? 1 : 0;
13308
+ const extra = Math.floor(rnd() * 3);
13270
13309
  const k = Math.max(1, Math.ceil(dims[g] / maxLen)) + extra;
13271
- for (const p of bsp(cell, k, [g], rnd)) pieces.push(p);
13310
+ for (const p of splitAlong(cell, k, g, rnd)) pieces.push(p);
13272
13311
  }
13273
13312
  return pieces.slice(0, limit).map((p) => ({ center: p.c, size: [p.s[g], p.s[a], p.s[b]], q: frame(g, a, b), shape: "splinter", weight: p.s[0] * p.s[1] * p.s[2] }));
13274
13313
  };
13314
+ var PLY = 3e-3;
13315
+ var PLY_GAP = 0.6;
13316
+ var PLY_SHEET = 0.012;
13317
+ var plyBreak = (inp, root, limit) => {
13318
+ const { rnd } = inp;
13319
+ const dims = root.s;
13320
+ const sorted = [0, 1, 2].sort((x, y) => dims[x] - dims[y]);
13321
+ const t = sorted[0];
13322
+ const [u, v] = [sorted[1], sorted[2]].sort((x, y) => x - y);
13323
+ const along = dims[u] >= dims[v] ? u : v;
13324
+ const across2 = along === u ? v : u;
13325
+ const layers = clamp(Math.round(dims[t] / PLY / 2), 2, 3);
13326
+ const pitch = dims[t] / layers;
13327
+ const th = Math.min(pitch, PLY_SHEET);
13328
+ const per = Math.max(2, Math.floor(limit / layers));
13329
+ const out = [];
13330
+ for (let k = 0; k < layers; k++) {
13331
+ const layer = { c: [root.c[0], root.c[1], root.c[2]], s: [dims[0], dims[1], dims[2]] };
13332
+ layer.c[t] = root.c[t] + (-dims[t] / 2 + (k + 0.5) * pitch) * (pitch > PLY_SHEET ? 1 : 1 + PLY_GAP);
13333
+ layer.s[t] = th;
13334
+ for (const cell of bsp(layer, per, [u, v], rnd)) {
13335
+ if (out.length >= limit) return out;
13336
+ if (rnd() < 0.35) {
13337
+ const strand = cell.s[across2] * (0.15 + 0.2 * rnd());
13338
+ out.push({ center: cell.c, size: [cell.s[along], strand, th * 0.7], q: frame(along, across2, t), shape: "splinter", weight: cell.s[along] * strand * th });
13339
+ } else {
13340
+ out.push({ center: cell.c, size: [cell.s[u], cell.s[v], th], q: frame(u, v, t, (rnd() - 0.5) * 0.5), shape: "scrap", weight: cell.s[u] * cell.s[v] * th });
13341
+ }
13342
+ }
13343
+ }
13344
+ return out;
13345
+ };
13346
+ var granules = (inp, box4, count) => bsp(box4, count, [0, 1, 2], inp.rnd).map((b) => ({ center: b.c, size: b.s, q: quat.identity(), shape: "chunk", weight: b.s[0] * b.s[1] * b.s[2] }));
13347
+ var CRUMBS = 6;
13275
13348
  var severAt = (inp, root, at2, gap) => {
13276
13349
  const dims = root.s;
13277
13350
  const L = [0, 1, 2].sort((x, y) => dims[y] - dims[x])[0];
13278
13351
  const half = dims[L] / 2;
13279
13352
  const lo = clamp(at2 - gap / 2, -half, half), hi = clamp(at2 + gap / 2, -half, half);
13280
13353
  const out = [];
13281
- const stub = (from, to) => {
13354
+ const fibrous = inp.form === "slivers" || inp.form === "plies";
13355
+ const [a, b] = [0, 1, 2].filter((i) => i !== L);
13356
+ const stub = (from, to, breakAtEnd) => {
13282
13357
  if (to - from < 0.02) return;
13283
13358
  const c = [root.c[0], root.c[1], root.c[2]], sz = [dims[0], dims[1], dims[2]];
13284
13359
  c[L] = (from + to) / 2;
13285
13360
  sz[L] = to - from;
13286
- out.push({ center: c, size: sz, q: quat.identity(), shape: "slab", weight: sz[0] * sz[1] * sz[2] });
13361
+ const weight = sz[0] * sz[1] * sz[2];
13362
+ if (fibrous) out.push({ center: c, size: [sz[L], sz[a], sz[b]], q: frame(L, a, b, breakAtEnd ? 0 : Math.PI), shape: "slab", weight });
13363
+ else out.push({ center: c, size: sz, q: quat.identity(), shape: "slab", weight });
13287
13364
  };
13288
- stub(-half, lo);
13289
- stub(hi, half);
13365
+ stub(-half, lo, true);
13366
+ stub(hi, half, false);
13290
13367
  const band = { c: [root.c[0], root.c[1], root.c[2]], s: [dims[0], dims[1], dims[2]] };
13291
13368
  band.c[L] = (lo + hi) / 2;
13292
13369
  band.s[L] = Math.max(hi - lo, 0.01);
13293
- if (inp.style === "snap") {
13294
- for (const b of bsp(band, Math.max(3, Math.min(6, inp.maxFragments - out.length)), [0, 1, 2], inp.rnd)) out.push({ center: b.c, size: b.s, q: quat.identity(), shape: "chunk", weight: b.s[0] * b.s[1] * b.s[2] });
13370
+ const room = inp.maxFragments - out.length;
13371
+ if (inp.style === "snap" && inp.form === "plies") for (const p of plyBreak(inp, band, Math.max(3, room))) out.push(p);
13372
+ else if (inp.style === "snap" && inp.form === "granules") for (const p of granules(inp, band, clamp(room, 3, 12))) out.push(p);
13373
+ else if (inp.style === "snap") {
13374
+ for (const b2 of bsp(band, Math.max(3, Math.min(6, room)), [0, 1, 2], inp.rnd)) out.push({ center: b2.c, size: b2.s, q: quat.identity(), shape: "chunk", weight: b2.s[0] * b2.s[1] * b2.s[2] });
13295
13375
  } else for (const p of splinterBox(inp, band, Math.max(3, inp.maxFragments - out.length))) out.push(p);
13296
13376
  return out;
13297
13377
  };
@@ -13324,8 +13404,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
13324
13404
  const [u, v] = [sorted[1], sorted[2]].sort((a, b) => a - b);
13325
13405
  if (style === "snap") {
13326
13406
  if (inp.cut) return severAt(inp, root, inp.cut.at, inp.cut.gap);
13407
+ if (inp.form === "plies") return plyBreak(inp, root, maxFragments);
13327
13408
  const n2 = Math.min(maxFragments, 2 + Math.floor(rnd() * 3));
13328
13409
  for (const b of bsp(root, n2, [0, 1, 2], rnd)) out.push({ center: b.c, size: b.s, q: idq, shape: "slab", weight: b.s[0] * b.s[1] * b.s[2] });
13410
+ if (inp.form !== "granules") return out;
13411
+ const crumbs = Math.min(CRUMBS, maxFragments - out.length);
13412
+ if (crumbs <= 0) return out;
13413
+ const band = { c: [0, 0, 0], s: [0, 0, 0] };
13414
+ for (let i = 0; i < 3; i++) {
13415
+ band.s[i] = Math.min(dims[i], Math.max(fmin, dims[i] * 0.2));
13416
+ band.c[i] = clamp(inp.hit[i], -dims[i] / 2 + band.s[i] / 2, dims[i] / 2 - band.s[i] / 2);
13417
+ }
13418
+ for (const p of granules(inp, band, crumbs)) out.push({ ...p, weight: p.weight * 0.5 });
13329
13419
  return out;
13330
13420
  }
13331
13421
  if (style === "crumble" || style === "none") {
@@ -13432,6 +13522,88 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
13432
13522
  }
13433
13523
  return marks;
13434
13524
  };
13525
+ var JOINT_GAP = 1e-4;
13526
+ var MIN_BEARING_SHARE = 0.25;
13527
+ var unsupportedCells = (cells, thin, dims, standing) => {
13528
+ if (thin === 1) return [];
13529
+ const [u, v] = planeAxes(thin);
13530
+ const bottom = -dims[v] / 2;
13531
+ const rowOf = (y) => Math.round((y - bottom) * 1e4);
13532
+ const rows = /* @__PURE__ */ new Map();
13533
+ for (let i = 0; i < cells.length; i++) {
13534
+ if (!standing(i)) continue;
13535
+ const cell = cells[i];
13536
+ const key2 = rowOf(cell.center[v] - cell.size[v] / 2);
13537
+ const row = rows.get(key2);
13538
+ if (row) row.push(i);
13539
+ else rows.set(key2, [i]);
13540
+ }
13541
+ const held = /* @__PURE__ */ new Set();
13542
+ const queue = [];
13543
+ for (const i of rows.get(0) ?? []) {
13544
+ held.add(i);
13545
+ queue.push(i);
13546
+ }
13547
+ const overlap = (a, b) => Math.min(a.center[u] + a.size[u] / 2, b.center[u] + b.size[u] / 2) - Math.max(a.center[u] - a.size[u] / 2, b.center[u] - b.size[u] / 2);
13548
+ const climb = () => {
13549
+ while (queue.length > 0) {
13550
+ const cell = cells[queue.pop()];
13551
+ for (const j of rows.get(rowOf(cell.center[v] + cell.size[v] / 2)) ?? []) {
13552
+ const other = cells[j];
13553
+ if (held.has(j) || overlap(cell, other) <= Math.max(JOINT_GAP, MIN_BEARING_SHARE * Math.min(cell.size[u], other.size[u]))) continue;
13554
+ held.add(j);
13555
+ queue.push(j);
13556
+ }
13557
+ }
13558
+ };
13559
+ for (const row of rows.values()) row.sort((a, b) => cells[a].center[u] - cells[b].center[u]);
13560
+ const touching = (a, b) => Math.abs(a.center[u] + a.size[u] / 2 - (b.center[u] - b.size[u] / 2)) <= 1e-3;
13561
+ for (let wedged = true; wedged; ) {
13562
+ climb();
13563
+ wedged = false;
13564
+ for (const row of rows.values()) {
13565
+ for (let k = 1; k < row.length - 1; k++) {
13566
+ const i = row[k];
13567
+ if (held.has(i) || !held.has(row[k - 1]) || !held.has(row[k + 1])) continue;
13568
+ if (!touching(cells[row[k - 1]], cells[i]) || !touching(cells[i], cells[row[k + 1]])) continue;
13569
+ held.add(i);
13570
+ queue.push(i);
13571
+ wedged = true;
13572
+ }
13573
+ }
13574
+ }
13575
+ const loose = [];
13576
+ for (const row of rows.values()) for (const i of row) if (!held.has(i)) loose.push(i);
13577
+ return loose;
13578
+ };
13579
+ var clumpCells = (cells, thin, cap) => {
13580
+ if (cells.length <= cap) return [...cells];
13581
+ const [u, v] = planeAxes(thin);
13582
+ let lo0 = Infinity, lo1 = Infinity, hi0 = -Infinity, hi1 = -Infinity;
13583
+ for (const cell of cells) {
13584
+ lo0 = Math.min(lo0, cell.center[u] - cell.size[u] / 2);
13585
+ hi0 = Math.max(hi0, cell.center[u] + cell.size[u] / 2);
13586
+ lo1 = Math.min(lo1, cell.center[v] - cell.size[v] / 2);
13587
+ hi1 = Math.max(hi1, cell.center[v] + cell.size[v] / 2);
13588
+ }
13589
+ let side = Math.sqrt((hi0 - lo0) * (hi1 - lo1) / cap);
13590
+ for (; ; ) {
13591
+ const bins = /* @__PURE__ */ new Map();
13592
+ for (const cell of cells) {
13593
+ const key2 = `${Math.floor((cell.center[u] - lo0) / side)}:${Math.floor((cell.center[v] - lo1) / side)}`;
13594
+ const bin = bins.get(key2) ?? { lo: [Infinity, Infinity, Infinity], hi: [-Infinity, -Infinity, -Infinity] };
13595
+ for (let k = 0; k < 3; k++) {
13596
+ bin.lo[k] = Math.min(bin.lo[k], cell.center[k] - cell.size[k] / 2);
13597
+ bin.hi[k] = Math.max(bin.hi[k], cell.center[k] + cell.size[k] / 2);
13598
+ }
13599
+ bins.set(key2, bin);
13600
+ }
13601
+ if (bins.size <= cap) {
13602
+ return [...bins.values()].map(({ lo, hi }) => ({ center: [(lo[0] + hi[0]) / 2, (lo[1] + hi[1]) / 2, (lo[2] + hi[2]) / 2], size: [hi[0] - lo[0], hi[1] - lo[1], hi[2] - lo[2]] }));
13603
+ }
13604
+ side *= 1.25;
13605
+ }
13606
+ };
13435
13607
  var MAX_SPALLS = 64;
13436
13608
  var thinAxisOf = (dims) => dims[0] <= dims[1] && dims[0] <= dims[2] ? 0 : dims[1] <= dims[2] ? 1 : 2;
13437
13609
  var resolveLayer = (def, index, mat) => ({ index, def, mat, energy: mat.penetration * def.thickness * 1e3 });
@@ -14411,6 +14583,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
14411
14583
  },
14412
14584
  {
14413
14585
  id: "wood_soft",
14586
+ splitForm: "slivers",
14414
14587
  density: 500,
14415
14588
  hpPerKg: 90,
14416
14589
  penetration: 9,
@@ -14456,6 +14629,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
14456
14629
  },
14457
14630
  {
14458
14631
  id: "wood_hard",
14632
+ splitForm: "slivers",
14459
14633
  density: 750,
14460
14634
  hpPerKg: 140,
14461
14635
  penetration: 14,
@@ -14500,6 +14674,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
14500
14674
  },
14501
14675
  {
14502
14676
  id: "plywood",
14677
+ splitForm: "plies",
14503
14678
  density: 600,
14504
14679
  hpPerKg: 70,
14505
14680
  penetration: 7,
@@ -14547,6 +14722,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
14547
14722
  },
14548
14723
  {
14549
14724
  id: "mdf",
14725
+ splitForm: "granules",
14550
14726
  density: 750,
14551
14727
  hpPerKg: 45,
14552
14728
  penetration: 6,
@@ -14713,6 +14889,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
14713
14889
  floor: 60
14714
14890
  }
14715
14891
  },
14892
+ ricochetDeg: 12,
14716
14893
  hitDebris: "chips",
14717
14894
  breakDebris: "dust",
14718
14895
  visual: { innerColor: 10197652 },
@@ -14744,6 +14921,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
14744
14921
  0.04,
14745
14922
  0.12
14746
14923
  ],
14924
+ ricochetDeg: 10,
14747
14925
  hitDebris: "chips",
14748
14926
  breakDebris: "dust",
14749
14927
  visual: { innerColor: 12085567 },
@@ -14801,6 +14979,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
14801
14979
  0.06,
14802
14980
  0.3
14803
14981
  ],
14982
+ ricochetDeg: 15,
14804
14983
  hitDebris: "chips",
14805
14984
  breakDebris: "dust",
14806
14985
  visual: { innerColor: 9407364 },
@@ -15058,6 +15237,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
15058
15237
  },
15059
15238
  {
15060
15239
  id: "green_wood",
15240
+ splitForm: "slivers",
15061
15241
  density: 650,
15062
15242
  hpPerKg: 5,
15063
15243
  penetration: 10,
@@ -15228,6 +15408,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
15228
15408
  0.03,
15229
15409
  0.15
15230
15410
  ],
15411
+ ricochetDeg: 8,
15231
15412
  hitDebris: "chips",
15232
15413
  breakDebris: "dust",
15233
15414
  thermal: {
@@ -15327,6 +15508,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
15327
15508
  0.02,
15328
15509
  0.08
15329
15510
  ],
15511
+ ricochetDeg: 8,
15330
15512
  hitDebris: "chips",
15331
15513
  breakDebris: "dust",
15332
15514
  thermal: {
@@ -15338,6 +15520,127 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
15338
15520
  "brittle"
15339
15521
  ],
15340
15522
  compressive: 1e5
15523
+ },
15524
+ {
15525
+ id: "mud",
15526
+ density: 1700,
15527
+ hpPerKg: 1,
15528
+ penetration: 5,
15529
+ ductility: 0.8,
15530
+ fracture: "crumble",
15531
+ fragmentSize: [
15532
+ 0.02,
15533
+ 0.08
15534
+ ],
15535
+ hitDebris: "dust",
15536
+ breakDebris: "dust",
15537
+ thermal: {
15538
+ conductivity: 0.5,
15539
+ heatCapacity: 3.2
15540
+ },
15541
+ tags: [
15542
+ "soil",
15543
+ "wet"
15544
+ ],
15545
+ compressive: 5e3
15546
+ },
15547
+ {
15548
+ id: "clay",
15549
+ density: 1800,
15550
+ hpPerKg: 5,
15551
+ penetration: 7,
15552
+ ductility: 0.05,
15553
+ fracture: "crumble",
15554
+ fragmentSize: [
15555
+ 0.02,
15556
+ 0.1
15557
+ ],
15558
+ hitDebris: "chips",
15559
+ breakDebris: "dust",
15560
+ thermal: {
15561
+ conductivity: 0.15,
15562
+ heatCapacity: 2.2
15563
+ },
15564
+ tags: [
15565
+ "soil",
15566
+ "brittle"
15567
+ ],
15568
+ compressive: 6e4
15569
+ },
15570
+ {
15571
+ id: "snow",
15572
+ density: 300,
15573
+ hpPerKg: 1,
15574
+ penetration: 3,
15575
+ ductility: 0.6,
15576
+ fracture: "crumble",
15577
+ fragmentSize: [
15578
+ 0.01,
15579
+ 0.05
15580
+ ],
15581
+ hitDebris: "dust",
15582
+ breakDebris: "dust",
15583
+ thermal: {
15584
+ conductivity: 0.1,
15585
+ heatCapacity: 2.1
15586
+ },
15587
+ tags: [
15588
+ "soil",
15589
+ "frozen"
15590
+ ],
15591
+ compressive: 1e3
15592
+ },
15593
+ {
15594
+ id: "cobble",
15595
+ density: 2650,
15596
+ hpPerKg: 25,
15597
+ penetration: 25,
15598
+ penetrationClass: "concrete",
15599
+ penetrationScale: 0.9,
15600
+ ductility: 0.03,
15601
+ fracture: "crumble",
15602
+ fragmentSize: [
15603
+ 0.05,
15604
+ 0.15
15605
+ ],
15606
+ ricochetDeg: 15,
15607
+ hitDebris: "chips",
15608
+ breakDebris: "chips",
15609
+ thermal: {
15610
+ conductivity: 0.2,
15611
+ heatCapacity: 2.5
15612
+ },
15613
+ tags: [
15614
+ "masonry",
15615
+ "brittle"
15616
+ ],
15617
+ compressive: 3e5
15618
+ },
15619
+ {
15620
+ id: "paver",
15621
+ density: 2300,
15622
+ hpPerKg: 14,
15623
+ penetration: 18,
15624
+ penetrationClass: "concrete",
15625
+ penetrationScale: 1,
15626
+ ductility: 0.03,
15627
+ fracture: "crumble",
15628
+ fragmentSize: [
15629
+ 0.04,
15630
+ 0.12
15631
+ ],
15632
+ ricochetDeg: 12,
15633
+ hitDebris: "chips",
15634
+ breakDebris: "chips",
15635
+ thermal: {
15636
+ conductivity: 0.15,
15637
+ heatCapacity: 2.5
15638
+ },
15639
+ tags: [
15640
+ "masonry",
15641
+ "brittle"
15642
+ ],
15643
+ compressive: 35e4
15341
15644
  }
15342
15645
  ];
15343
15646
  var material_hints_default = {
@@ -15550,6 +15853,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
15550
15853
  var BREACH_BLAST_FACTOR = 6;
15551
15854
  var BREACH_AREA = 0.25;
15552
15855
  var BREACH_BLAST_REACH = 0.12;
15856
+ var MEMBER_CUT_REACH = 0.5;
15857
+ var BLAST_REFERENCE_RESISTANCE = 200 * 1900 * 0.13;
15858
+ var BLAST_EDGE_RAGGED = 0.3;
15859
+ var BLAST_EDGE_LOOSE = 1.35;
15860
+ var BLAST_EDGE_WEAR = 0.6;
15553
15861
  var RESIDUAL_CAPACITY = 0.15;
15554
15862
  var SEVER_BAND = 0.1;
15555
15863
  var SEVER_ASPECT = 3;
@@ -16802,7 +17110,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16802
17110
  if (j.st.open) continue;
16803
17111
  if (j.spec.kind === "rebar" && (isReinforced(o.parts[j.ia].spec) || isReinforced(o.parts[j.ib].spec))) continue;
16804
17112
  if (near && jointReach(o, j, near) > Math.max(radius, jointReachLimit(o, j))) continue;
16805
- j.st.hp -= span === void 0 ? amount : amount * Math.min(1, span / Math.max(jointLength(o, j), 1e-6));
17113
+ j.st.hp -= span === void 0 ? amount : Math.min(amount, j.st.maxHp) * Math.min(1, span / Math.max(jointLength(o, j), 1e-6));
16806
17114
  if (j.st.hp <= 0) {
16807
17115
  j.st.hp = 0;
16808
17116
  j.st.open = true;
@@ -16930,6 +17238,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16930
17238
  const worn = (_a = p.rt).chips ?? (_a.chips = {});
16931
17239
  const cut = (_b = p.rt).craters ?? (_b.craters = {});
16932
17240
  const out = [];
17241
+ const wholeBefore = Object.values(worn).filter((w) => w === -1).length;
16933
17242
  const shot = kind === "ballistic";
16934
17243
  for (let i = 0; i < grid.length; i++) {
16935
17244
  const cell = grid[i];
@@ -16988,6 +17297,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16988
17297
  emit({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [cell.size[0], cell.size[1], cell.size[2]], rotation: q, fragments });
16989
17298
  debris(o, p, p.mat.breakDebris, center, vec.scale(dir ?? [0, 1, 0], -1), 6, 2, src);
16990
17299
  }
17300
+ if (Object.values(worn).filter((w) => w === -1).length > wholeBefore) dropUnsupported(o, p, src);
16991
17301
  if (p.spec.reinforcement) exposeRebar(o, p, src);
16992
17302
  for (const cell of out) addBreach(o, p, toWorld(c, q, cell.center), cell.size[u] * cell.size[v], energy, dir, src);
16993
17303
  if (p.structural && !isLost(p)) {
@@ -17091,10 +17401,122 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
17091
17401
  setStage(o, p, 1, {}, src);
17092
17402
  setStage(o, p, 2, { opening: { center: worldCenter, radius }, fragments }, src);
17093
17403
  debris(o, p, p.mat.breakDebris, worldCenter, vec.scale(dir ?? [0, 1, 0], -1), 14, 3, src);
17404
+ dropUnsupported(o, p, src);
17094
17405
  const reinforcement = p.spec.reinforcement;
17095
17406
  if (reinforcement) exposeRebar(o, p, src);
17096
17407
  if (p.structural) solveStructure(o);
17097
17408
  };
17409
+ const blastReachOf = (p, energy) => {
17410
+ const perKg = p.mat.hits?.blunt?.unitJoules ?? chipEnergy;
17411
+ const resistance = Math.max(1, perKg * p.mat.density * p.thickness);
17412
+ return BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3) * clamp2(Math.cbrt(BLAST_REFERENCE_RESISTANCE / resistance), 0.3, 2);
17413
+ };
17414
+ const blastUnits = (o, p, wp, energy, dist, src) => {
17415
+ var _a, _b;
17416
+ if (!p.staged || p.st.stripped || isLost(p) || chipEnergy <= 0) return false;
17417
+ const reach = blastReachOf(p, energy);
17418
+ if (dist >= reach) return false;
17419
+ const radius = Math.sqrt(reach * reach - dist * dist);
17420
+ const [u, v] = planeAxes(p.thin);
17421
+ const lp = toLocal(p.pos, p.q, objLocal(o, wp));
17422
+ const op = p.st.opening ? toLocal(p.pos, p.q, p.st.opening.center) : null;
17423
+ const grid = gridOf(p);
17424
+ const worn = (_a = p.rt).chips ?? (_a.chips = {});
17425
+ const perKg = p.mat.hits?.blunt?.unitJoules ?? chipEnergy;
17426
+ const lobes = [rnd() * 2 * Math.PI, rnd() * 2 * Math.PI];
17427
+ const out = [];
17428
+ for (let i = 0; i < grid.length; i++) {
17429
+ const cell = grid[i];
17430
+ if (worn[i] === -1) continue;
17431
+ if (op && p.st.opening && Math.hypot(cell.center[u] - op[u], cell.center[v] - op[v]) <= p.st.opening.radius) continue;
17432
+ const du = cell.center[u] - lp[u], dv = cell.center[v] - lp[v];
17433
+ const angle = Math.atan2(dv, du);
17434
+ const edge = radius * (1 + BLAST_EDGE_RAGGED * (0.5 * Math.sin(3 * angle + lobes[0]) + 0.3 * Math.sin(5 * angle + lobes[1]) + 0.4 * (rnd() - 0.5)));
17435
+ const d = Math.hypot(du, dv);
17436
+ if (d <= edge) {
17437
+ worn[i] = -1;
17438
+ out.push(i);
17439
+ } else if (d <= edge * BLAST_EDGE_LOOSE) {
17440
+ const mass = p.mat.density * cell.size[0] * cell.size[1] * cell.size[2];
17441
+ worn[i] = Math.max(worn[i] ?? 0, perKg * mass * BLAST_EDGE_WEAR);
17442
+ }
17443
+ }
17444
+ if (out.length === 0) return false;
17445
+ const loose = unsupportedCells(grid, p.thin, p.dims, (i) => worn[i] !== -1 && !(op && p.st.opening && Math.hypot(grid[i].center[u] - op[u], grid[i].center[v] - op[v]) <= p.st.opening.radius));
17446
+ for (const i of loose) worn[i] = -1;
17447
+ const blown = out.map((i) => grid[i]), fallen = loose.map((i) => grid[i]);
17448
+ const volume = (cells2) => cells2.reduce((sum, cell) => sum + cell.size[0] * cell.size[1] * cell.size[2], 0);
17449
+ const blownMass = Math.min(p.st.mass, p.mat.density * volume(blown));
17450
+ const fallenMass = Math.min(p.st.mass - blownMass, p.mat.density * volume(fallen));
17451
+ const speed = clamp2(Math.sqrt(2 * energy * 0.02 / Math.max(blownMass, 0.05)), 1, 12);
17452
+ const { c, q } = partXf(o, p);
17453
+ const chipped = (_b = p.st).chipped ?? (_b.chipped = []);
17454
+ const tag = `x${chipped.length}_`;
17455
+ const fragments = [
17456
+ ...cellFragments(o, p, clumpCells(blown, p.thin, maxFragments), wp, null, speed, blownMass, tag, true),
17457
+ ...fallen.length > 0 ? cellFragments(o, p, clumpCells(fallen, p.thin, Math.max(2, Math.round(maxFragments / 4))), wp, null, 0.3, fallenMass, `${tag}f`, true) : []
17458
+ ];
17459
+ const cells = [...blown, ...fallen];
17460
+ const holes = localHolesOf(p);
17461
+ p.st.holes = p.st.holes.filter((_, k) => !cells.some((cell) => marksInBox(cell.center, cell.size, void 0, [holes[k]]).length > 0));
17462
+ const lo = [Infinity, Infinity, Infinity], hi = [-Infinity, -Infinity, -Infinity];
17463
+ for (const cell of cells) {
17464
+ chipped.push({ center: [cell.center[0], cell.center[1], cell.center[2]], size: [cell.size[0], cell.size[1], cell.size[2]] });
17465
+ for (let k = 0; k < 3; k++) {
17466
+ lo[k] = Math.min(lo[k], cell.center[k] - cell.size[k] / 2);
17467
+ hi[k] = Math.max(hi[k], cell.center[k] + cell.size[k] / 2);
17468
+ }
17469
+ }
17470
+ p.st.mass = Math.max(0, p.st.mass - blownMass - fallenMass);
17471
+ p.rt.removed = (p.rt.removed ?? 0) + blownMass + fallenMass;
17472
+ markDamaged(p);
17473
+ setStage(o, p, 1, {}, src);
17474
+ const center = toWorld(c, q, [(lo[0] + hi[0]) / 2, (lo[1] + hi[1]) / 2, (lo[2] + hi[2]) / 2]);
17475
+ const units = cells.map((cell) => ({ center: toWorld(c, q, cell.center), size: [cell.size[0], cell.size[1], cell.size[2]] }));
17476
+ emit({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [hi[0] - lo[0], hi[1] - lo[1], hi[2] - lo[2]], rotation: q, fragments, units });
17477
+ debris(o, p, p.mat.breakDebris, center, vec.normalize(vec.sub(center, wp), [0, 1, 0]), 14, 3, src);
17478
+ if (p.spec.reinforcement) exposeRebar(o, p, src);
17479
+ if (p.structural && !isLost(p)) {
17480
+ solveStructure(o);
17481
+ collapseCheck(o, src);
17482
+ }
17483
+ return true;
17484
+ };
17485
+ const dropUnsupported = (o, p, src) => {
17486
+ var _a, _b;
17487
+ if (!p.spec.units || p.spec.units.mortar === p.spec.material || p.st.stripped || isLost(p)) return 0;
17488
+ const [u, v] = planeAxes(p.thin);
17489
+ const grid = gridOf(p);
17490
+ const worn = (_a = p.rt).chips ?? (_a.chips = {});
17491
+ const op = p.st.opening ? toLocal(p.pos, p.q, p.st.opening.center) : null;
17492
+ const opened = (cell) => !!op && !!p.st.opening && Math.hypot(cell.center[u] - op[u], cell.center[v] - op[v]) <= p.st.opening.radius;
17493
+ const loose = unsupportedCells(grid, p.thin, p.dims, (i) => worn[i] !== -1 && !opened(grid[i]));
17494
+ if (loose.length === 0) return 0;
17495
+ for (const i of loose) worn[i] = -1;
17496
+ const fallen = loose.map((i) => grid[i]);
17497
+ const mass = Math.min(p.st.mass, p.mat.density * fallen.reduce((sum, cell) => sum + cell.size[0] * cell.size[1] * cell.size[2], 0));
17498
+ const { c, q } = partXf(o, p);
17499
+ const chipped = (_b = p.st).chipped ?? (_b.chipped = []);
17500
+ const lo = [Infinity, Infinity, Infinity], hi = [-Infinity, -Infinity, -Infinity];
17501
+ for (const cell of fallen) {
17502
+ for (let k = 0; k < 3; k++) {
17503
+ lo[k] = Math.min(lo[k], cell.center[k] - cell.size[k] / 2);
17504
+ hi[k] = Math.max(hi[k], cell.center[k] + cell.size[k] / 2);
17505
+ }
17506
+ }
17507
+ const center = toWorld(c, q, [(lo[0] + hi[0]) / 2, (lo[1] + hi[1]) / 2, (lo[2] + hi[2]) / 2]);
17508
+ const fragments = cellFragments(o, p, clumpCells(fallen, p.thin, Math.max(2, Math.round(maxFragments / 4))), vec.add(center, [0, 1, 0]), null, 0.3, mass, `u${chipped.length}_`, true);
17509
+ const holes = localHolesOf(p);
17510
+ p.st.holes = p.st.holes.filter((_, k) => !fallen.some((cell) => marksInBox(cell.center, cell.size, void 0, [holes[k]]).length > 0));
17511
+ for (const cell of fallen) chipped.push({ center: [cell.center[0], cell.center[1], cell.center[2]], size: [cell.size[0], cell.size[1], cell.size[2]] });
17512
+ p.st.mass = Math.max(0, p.st.mass - mass);
17513
+ p.rt.removed = (p.rt.removed ?? 0) + mass;
17514
+ markDamaged(p);
17515
+ const units = fallen.map((cell) => ({ center: toWorld(c, q, cell.center), size: [cell.size[0], cell.size[1], cell.size[2]] }));
17516
+ emit({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [hi[0] - lo[0], hi[1] - lo[1], hi[2] - lo[2]], rotation: q, fragments, units });
17517
+ debris(o, p, p.mat.breakDebris, center, [0, -1, 0], 6, 1, src);
17518
+ return loose.length;
17519
+ };
17098
17520
  const stripPart = (o, p, reinforcement, src) => {
17099
17521
  const bars = rebarBars(p.dims, p.thin, reinforcement.spacing);
17100
17522
  p.st.stripped = true;
@@ -17161,6 +17583,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
17161
17583
  const unitPlan = p.spec.units ? unitFragmentPlan(p, maxFragments * UNIT_FRAGMENT_FACTOR) : [];
17162
17584
  const axis = style === "splinter" || style === "snap" ? severAxis(p) : -1;
17163
17585
  const cutAt2 = axis < 0 ? void 0 : p.rt.cutAt ?? (origin ? hitLocal[axis] : void 0);
17586
+ const planRnd = p.mat.splitForm ? splitStream(o.id, p.spec.id, hitLocal) : rnd;
17164
17587
  const plan = unitPlan.length > 0 ? unitPlan : planFragments({
17165
17588
  style,
17166
17589
  dims: p.dims,
@@ -17169,8 +17592,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
17169
17592
  hit: hitLocal,
17170
17593
  fragmentSize: p.mat.fragmentSize ?? [0.04, 0.2],
17171
17594
  maxFragments,
17172
- rnd,
17595
+ rnd: planRnd,
17173
17596
  sheet: p.mat.sheet,
17597
+ ...p.mat.splitForm ? { form: p.mat.splitForm } : {},
17174
17598
  ...cutAt2 !== void 0 ? { cut: { at: cutAt2, gap: SEVER_BAND } } : {}
17175
17599
  });
17176
17600
  const holes = p.st.holes.length > 0 ? localHolesOf(p) : [];
@@ -17309,7 +17733,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
17309
17733
  const fragments = [];
17310
17734
  for (let i = 0; i < n; i++) {
17311
17735
  const back = !exit || i % 3 === 2;
17312
- const len = scale * (fibre ? 1.2 + 1.2 * rnd() : 3 + 4 * rnd()), w = scale * (0.8 + 0.8 * rnd()), t = scale * (fibre ? 0.7 + 0.6 * rnd() : 0.4 + 0.4 * rnd());
17736
+ const plies = p.mat.splitForm === "plies";
17737
+ const len = scale * (fibre ? 1.2 + 1.2 * rnd() : 3 + 4 * rnd()), w = scale * (0.8 + 0.8 * rnd()), t = scale * (fibre ? 0.7 + 0.6 * rnd() : plies ? 0.15 + 0.15 * rnd() : 0.4 + 0.4 * rnd());
17313
17738
  const size = [w, w, w];
17314
17739
  size[along] = len;
17315
17740
  size[(along + 1) % 3] = w;
@@ -17470,7 +17895,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
17470
17895
  checkIgnite(o, p, src);
17471
17896
  }
17472
17897
  }
17473
- wearJoints(o, p, Ein * 0.5, void 0, 0, src);
17898
+ wearJoints(o, p, Ein * 0.5, void 0, 0, src, false, 2 * BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3));
17474
17899
  const amount = Ein * DMG_PER_J * (mat.damageScale?.explosive ?? 1);
17475
17900
  if (blastFrontSpeed > 0 && dist > 0 && mat.tags?.includes("glass")) {
17476
17901
  frontQueue.push({ o, p, due: time + dist / blastFrontSpeed, amount, fragEnergy: Ein * 0.3, point, ...src !== void 0 ? { src } : {} });
@@ -17480,7 +17905,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
17480
17905
  const dealt = applyDamage(o, p, amount, "explosive", point, null, Ein * 0.3, 40, src);
17481
17906
  res.damage += dealt;
17482
17907
  if (p.bend && flexure.enabled) bendByBlast(o, p, point, energy, radius, reach, src);
17483
- if (dist <= BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3)) addBreach(o, p, wp, breachAreaOf(p, dealt, true), Ein, null, src);
17908
+ const breachReach = BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3);
17909
+ if (p.spec.units && p.spec.units.mortar !== p.spec.material) blastUnits(o, p, wp, energy, dist, src);
17910
+ else if (p.spec.reinforcement && p.spec.units && dist > MEMBER_CUT_REACH * breachReach) blastUnits(o, p, wp, energy, dist, src);
17911
+ else if (dist <= breachReach) addBreach(o, p, wp, breachAreaOf(p, dealt, true), Ein, null, src);
17484
17912
  return reach;
17485
17913
  };
17486
17914
  const blastProbe = { partsTested: 0, partsNear: 0 };
@@ -17726,6 +18154,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
17726
18154
  }
17727
18155
  return h | 0;
17728
18156
  };
18157
+ const splitStream = (objectId, partId, hit) => {
18158
+ const codes = Array.from(`${objectId}|${partId}`, (char) => char.charCodeAt(0) / 1e3);
18159
+ const stream = createRng(seedOf2(rng3.state() / 1e3, ...codes, hit[0], hit[1], hit[2]));
18160
+ return () => stream.next();
18161
+ };
17729
18162
  const throwFragment = (frag, objectId, from, g, centre, index, src, shields, results, reports, mult) => {
17730
18163
  const v = frag.velocity;
17731
18164
  const speed = Math.hypot(v[0], v[1], v[2]);
@@ -19021,7 +19454,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
19021
19454
  var DEFAULT_DENSITY = 500;
19022
19455
  var densityOf = (material) => DENSITY[material] ?? DEFAULT_DENSITY;
19023
19456
  var OPEN_ROOM_TYPES = ["balcony", "terrace", "porch"];
19457
+ var WALL_PILLAR_SIDE = 0.2;
19458
+ var HALF = WALL_PILLAR_SIDE / 2;
19024
19459
  var CLOSED_ONLY = [...OPEN_ROOM_TYPES, "void"];
19460
+ var HALF_PILLAR = WALL_PILLAR_SIDE / 2;
19025
19461
  var entry = (itemId, min, max, group, pickable, weight) => ({ itemId, min, max, group, pickable, weight });
19026
19462
  var FRIDGE = [
19027
19463
  entry("water_bottle", 1, 3, "water", true, 3),
@@ -19756,6 +20192,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
19756
20192
  }
19757
20193
  var LINTEL_DEPTH2 = 0.2;
19758
20194
  var LINTEL_BEARING2 = 0.2;
20195
+ var SILL_BEAM_DEPTH = 0.1;
20196
+ var LINTEL_SPAN_RATIO = 10;
19759
20197
  var MIN_PIECE = 0.05;
19760
20198
  var frameOf = (wall) => {
19761
20199
  const alongU = wall.aabb[2] - wall.aabb[0] >= wall.aabb[3] - wall.aabb[1];
@@ -19769,6 +20207,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
19769
20207
  const drafts = [];
19770
20208
  const piers = [];
19771
20209
  const lintels = [];
20210
+ const sillBeams = [];
19772
20211
  const spandrels = [];
19773
20212
  const height = wall.y1 - wall.y0;
19774
20213
  let cursor = frame2.from;
@@ -19779,23 +20218,26 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
19779
20218
  };
19780
20219
  own.forEach((opening2, k) => {
19781
20220
  addPier(Math.max(cursor, opening2.from));
19782
- const lintelTop = Math.min(wall.y1, opening2.y1 + Math.max(LINTEL_DEPTH2, style.lintelDepth?.(opening2.to - opening2.from) ?? 0));
20221
+ const span = opening2.to - opening2.from;
20222
+ const lintelTop = Math.min(wall.y1, opening2.y1 + Math.max(LINTEL_DEPTH2, style.lintelDepth?.(span) ?? 0, (span + LINTEL_BEARING2) / LINTEL_SPAN_RATIO));
19783
20223
  const lintelFrom = Math.max(frame2.from, opening2.from - LINTEL_BEARING2);
19784
20224
  const lintelTo = Math.min(frame2.to, opening2.to + LINTEL_BEARING2);
19785
20225
  const lintelHeight = lintelTop - opening2.y1;
19786
- if (opening2.y0 - wall.y0 > MIN_PIECE) drafts.push({ id: `${wall.id}_sill_${k}`, role: "partition", material: wall.material, from: opening2.from, to: opening2.to, y0: wall.y0, y1: opening2.y0, volume: (opening2.to - opening2.from) * (opening2.y0 - wall.y0) });
20226
+ const sillTop = style.sillBeam && opening2.y0 - wall.y0 > SILL_BEAM_DEPTH + MIN_PIECE ? opening2.y0 - SILL_BEAM_DEPTH : opening2.y0;
20227
+ if (sillTop - wall.y0 > MIN_PIECE) drafts.push({ id: `${wall.id}_sill_${k}`, role: "partition", material: wall.material, from: opening2.from, to: opening2.to, y0: wall.y0, y1: sillTop, volume: (opening2.to - opening2.from) * (sillTop - wall.y0) });
20228
+ if (sillTop < opening2.y0) sillBeams.push({ id: `${wall.id}_sillbeam_${k}`, role: "beam", material: style.lintelMaterial, from: lintelFrom, to: lintelTo, y0: sillTop, y1: opening2.y0, volume: (lintelTo - lintelFrom) * SILL_BEAM_DEPTH });
19787
20229
  lintels.push({ id: `${wall.id}_lintel_${k}`, role: "beam", material: style.lintelMaterial, from: lintelFrom, to: lintelTo, y0: opening2.y1, y1: lintelTop, volume: (lintelTo - lintelFrom) * lintelHeight });
19788
20230
  spandrels.push(wall.y1 - lintelTop > MIN_PIECE ? { id: `${wall.id}_spandrel_${k}`, role: roleOf2, material: wall.material, from: opening2.from, to: opening2.to, y0: lintelTop, y1: wall.y1, volume: (opening2.to - opening2.from) * (wall.y1 - lintelTop) } : void 0);
19789
20231
  cursor = opening2.to;
19790
20232
  });
19791
20233
  addPier(frame2.to);
19792
20234
  for (const pier of piers) {
19793
- for (const lintel of lintels) {
20235
+ for (const lintel of [...lintels, ...sillBeams]) {
19794
20236
  const overlap = Math.max(0, Math.min(pier.to, lintel.to) - Math.max(pier.from, lintel.from));
19795
20237
  pier.volume -= overlap * (lintel.y1 - lintel.y0);
19796
20238
  }
19797
20239
  }
19798
- const all = [...piers, ...drafts, ...lintels, ...spandrels.filter((d) => d !== void 0)];
20240
+ const all = [...piers, ...drafts, ...sillBeams, ...lintels, ...spandrels.filter((d) => d !== void 0)];
19799
20241
  const total = all.reduce((sum, d) => sum + d.volume, 0);
19800
20242
  const pieces = all.map((d) => ({
19801
20243
  id: d.id,
@@ -19810,6 +20252,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
19810
20252
  ...d.role === "beam" ? style.lintelAssembly ? { assembly: style.lintelAssembly } : {} : wall.assembly ? { assembly: wall.assembly } : {}
19811
20253
  }));
19812
20254
  const internal = [];
20255
+ for (const beam of sillBeams) {
20256
+ const sill = drafts.find((d) => d.id === beam.id.replace("_sillbeam_", "_sill_"));
20257
+ if (sill) internal.push({ part: beam.id, on: sill.id, joint: style.lintelJoint });
20258
+ for (const pier of piers) if (Math.min(pier.to, beam.to) - Math.max(pier.from, beam.from) > 0) internal.push({ part: beam.id, on: pier.id, joint: style.lintelJoint });
20259
+ }
19813
20260
  lintels.forEach((lintel, k) => {
19814
20261
  for (const pier of piers) if (Math.min(pier.to, lintel.to) - Math.max(pier.from, lintel.from) > 0) internal.push({ part: lintel.id, on: pier.id, joint: style.lintelJoint });
19815
20262
  const spandrel = spandrels[k];
@@ -19839,7 +20286,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
19839
20286
  ...system.timber ? {} : { lintelAssembly: "reinforced_concrete" },
19840
20287
  lintelJoint: system.joints.beam,
19841
20288
  wallJoint: system.joints.wall,
19842
- ...lintelDepth && !system.timber ? { lintelDepth } : {}
20289
+ ...lintelDepth && !system.timber ? { lintelDepth } : {},
20290
+ ...construction.system === "masonry" ? { sillBeam: true } : {}
19843
20291
  });
19844
20292
  if (split.pieces.length > 1) splits.set(part.id, split);
19845
20293
  }
@@ -19847,7 +20295,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
19847
20295
  }
19848
20296
  function applyPanels(input, structure, detail, lintelDepth) {
19849
20297
  if (detail === "coarse") return input;
19850
- return applySplits(input, panelSplits(input, structure, lintelDepth));
20298
+ return onJambPillars(applySplits(input, panelSplits(input, structure, lintelDepth)));
20299
+ }
20300
+ var OPENING_BEAM = /_(lintel|sillbeam)_\d+$/;
20301
+ var overlaps2 = (a, b) => a[0] < b[2] && a[2] > b[0] && a[1] < b[3] && a[3] > b[1];
20302
+ function onJambPillars(split) {
20303
+ const pillars = split.parts.filter((part) => part.role === "column" && part.material === "concrete");
20304
+ const extra = [];
20305
+ for (const beam of split.parts) {
20306
+ if (beam.role !== "beam" || !OPENING_BEAM.test(beam.id)) continue;
20307
+ for (const pillar of pillars) if (pillar.floor === beam.floor && overlaps2(pillar.aabb, beam.aabb) && pillar.y0 <= beam.y0 && pillar.y1 >= beam.y1 - 0.01) extra.push({ part: beam.id, on: pillar.id, joint: "rebar" });
20308
+ }
20309
+ return extra.length ? { parts: split.parts, supports: [...split.supports, ...extra] } : split;
19851
20310
  }
19852
20311
  function applyUnits(input, structure) {
19853
20312
  const splits = /* @__PURE__ */ new Map();
@@ -19909,21 +20368,35 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
19909
20368
  };
19910
20369
  var MEMBER_CAGE = { spacing: 0.1, diameter: 8e-3, unit: 0.1 };
19911
20370
  var CAGED_ROLES = /* @__PURE__ */ new Set(["beam", "column"]);
20371
+ var CAGE_COVER = 0.03;
20372
+ var CAGE_BUCKLING_SHARE = 0.5;
20373
+ var DEFAULT_RESIDUAL = 0.15;
20374
+ function cageResidualCapacity(size, reinforcement, capacity) {
20375
+ const [a = 0, b = 0] = [...size].sort((x, y) => x - y);
20376
+ const perSide = (w) => Math.max(2, Math.floor(Math.max(0, w - 2 * CAGE_COVER) / reinforcement.spacing) + 1);
20377
+ const bars = 2 * perSide(a) + 2 * perSide(b) - 4;
20378
+ const steel = MATERIALS2.find((m) => m.id === reinforcement.material)?.compressive ?? 0;
20379
+ const carries2 = bars * Math.PI * (reinforcement.diameter / 2) ** 2 * steel * CAGE_BUCKLING_SHARE;
20380
+ if (!capacity || capacity <= 0 || carries2 <= 0) return DEFAULT_RESIDUAL;
20381
+ return Math.min(1, Math.max(DEFAULT_RESIDUAL, carries2 / capacity));
20382
+ }
19912
20383
  var caged = (spec, part, rebar2) => {
19913
20384
  if (!rebar2 || part.material !== "concrete" || !CAGED_ROLES.has(part.role) || spec.reinforcement) return spec;
19914
20385
  const size = spec.shape.kind === "box" ? spec.shape.size : null;
19915
20386
  if (!size) return spec;
19916
20387
  const thin = Math.min(...size);
20388
+ const reinforcement = { material: rebar2, spacing: MEMBER_CAGE.spacing, diameter: MEMBER_CAGE.diameter };
19917
20389
  return {
19918
20390
  ...spec,
19919
- reinforcement: { material: rebar2, spacing: MEMBER_CAGE.spacing, diameter: MEMBER_CAGE.diameter },
20391
+ reinforcement: part.role === "column" ? { ...reinforcement, residualCapacity: cageResidualCapacity(size, reinforcement, spec.structure?.capacity) } : reinforcement,
19920
20392
  units: { size: [MEMBER_CAGE.unit, MEMBER_CAGE.unit, thin], bond: "stack", mortar: "concrete" }
19921
20393
  };
19922
20394
  };
19923
20395
  var partSpecOf = (part, capacity, detailed, rebar2) => {
19924
20396
  if (detailed && part.assembly) return assemblySpec(part, capacity);
19925
20397
  const spec = boxSpec(part, capacity);
19926
- return detailed ? caged(spec, part, rebar2) : spec;
20398
+ const out = detailed ? caged(spec, part, rebar2) : spec;
20399
+ return part.beamKind === "ground_beam" ? { ...out, anchored: true, structure: { role: "foundation" } } : out;
19927
20400
  };
19928
20401
  function toDestructibleSpec(structure, options = {}) {
19929
20402
  const { safety = 0.65, redundancy = 0.97, safetyOthers = 0.45 } = options;
@@ -19939,7 +20412,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
19939
20412
  const walled = applyPanels(slabbed, structure, detail, slabOptions && structure.construction.frame.rebar ? (span) => beamDepthFor(span, slabOptions) : void 0);
19940
20413
  const panels = slabOptions && detail !== "coarse" ? deepenBondBeams(walled, structure, slabOptions) : walled;
19941
20414
  const sizing = { safety, redundancy, safetyOthers };
19942
- const sized = { ...panels, capacities: options.sized === false ? /* @__PURE__ */ new Map() : sizeCapacities(panels.parts, panels.supports, sizing) };
20415
+ const foundation = new Set(panels.parts.filter((part) => part.beamKind === "ground_beam").map((part) => part.id));
20416
+ const onFoundation = foundation.size ? panels.supports.filter((s) => !foundation.has(s.part)).map((s) => foundation.has(s.on) ? { ...s, on: GROUND } : s) : panels.supports;
20417
+ const sized = { ...panels, capacities: options.sized === false ? /* @__PURE__ */ new Map() : sizeCapacities(panels.parts.filter((part) => !foundation.has(part.id)), onFoundation, sizing) };
19943
20418
  const { parts, supports, capacities } = detail === "units" ? applyUnits(sized, structure) : sized;
19944
20419
  const specs = parts.map((part) => partSpecOf(part, capacities.get(part.id), detail !== "coarse", structure.construction.frame.rebar));
19945
20420
  const margin = options.terrainMargin ?? TERRAIN_MARGIN;
@@ -20004,6 +20479,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
20004
20479
  out.parts = out.parts.map((p, i) => i === ground ? raft2 : p);
20005
20480
  return out;
20006
20481
  }
20482
+ var LOW_WINDOW = SILL_BEAM_DEPTH + 0.05;
20007
20483
  var slabId = (g, f) => f === g.floors - 1 && g.roof ? "roof" : `slab_${f}`;
20008
20484
  var storeyBase = (g, f) => f * (g.height + g.slab);
20009
20485
  var slabHalf = (g) => [(g.spanX + g.columnSize + 0.2) / 2, (g.spanZ + g.columnSize + 0.2) / 2];
@@ -20162,7 +20638,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
20162
20638
  parts.push({ id, material: c.material, shape: box3(size), position, structure: { role: "partition" }, tags: ["infill"] });
20163
20639
  for (const o of on) rests(joints, id, o, "mortar");
20164
20640
  };
20165
- const bay = (side, k, along, centre, fixed, length, c1, c2) => {
20641
+ const bay = (side, k, along, centre2, fixed, length, c1, c2) => {
20166
20642
  const clear = length - g.columnSize;
20167
20643
  const win = clear * c.window;
20168
20644
  const pier = (clear - win) / 2;
@@ -20173,11 +20649,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
20173
20649
  wall(`infill_${f}_${side}_${k}_${name}`, size(u, h), [p[0], y, p[2]], on);
20174
20650
  };
20175
20651
  const id = (name) => `infill_${f}_${side}_${k}_${name}`;
20176
- put("sill", clear, sill, yb + sill / 2, centre, [c1, c2]);
20177
- put("pl", pier, head - sill, yb + sill + (head - sill) / 2, centre - clear / 2 + pier / 2, [c1, id("sill")]);
20178
- put("pr", pier, head - sill, yb + sill + (head - sill) / 2, centre + clear / 2 - pier / 2, [c2, id("sill")]);
20179
- put("head", clear, room - head, yb + head + (room - head) / 2, centre, [c1, c2]);
20180
- const gp = at2(centre);
20652
+ put("sill", clear, sill, yb + sill / 2, centre2, [c1, c2]);
20653
+ put("pl", pier, head - sill, yb + sill + (head - sill) / 2, centre2 - clear / 2 + pier / 2, [c1, id("sill")]);
20654
+ put("pr", pier, head - sill, yb + sill + (head - sill) / 2, centre2 + clear / 2 - pier / 2, [c2, id("sill")]);
20655
+ put("head", clear, room - head, yb + head + (room - head) / 2, centre2, [c1, c2]);
20656
+ const gp = at2(centre2);
20181
20657
  const gid = `glass_${f}_${side}_${k}`;
20182
20658
  parts.push({
20183
20659
  id: gid,
@@ -20644,7 +21120,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
20644
21120
  }
20645
21121
  var towerLocales = { en: { labels: en_default.labels }, "pt-BR": { labels: pt_BR_default.labels } };
20646
21122
 
20647
- // ../game-floorplan-three/dist/chunk-QUVGWVEC.js
21123
+ // ../game-floorplan-three/dist/chunk-Y3Y7NYOL.js
21124
+ var __defProp2 = Object.defineProperty;
21125
+ var __defNormalProp = (obj, key2, value) => key2 in obj ? __defProp2(obj, key2, { enumerable: true, configurable: true, writable: true, value }) : obj[key2] = value;
21126
+ var __publicField = (obj, key2, value) => __defNormalProp(obj, typeof key2 !== "symbol" ? key2 + "" : key2, value);
20648
21127
  var en2 = {
20649
21128
  "prompt.open": "E: open {what}",
20650
21129
  "prompt.close": "E: close {what}",
@@ -20728,6 +21207,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
20728
21207
  const WITH_MAP = { roughcast: 1, block: 1 };
20729
21208
  class Accumulator {
20730
21209
  constructor() {
21210
+ __publicField(this, "cv");
21211
+ __publicField(this, "ci");
21212
+ __publicField(this, "p");
21213
+ __publicField(this, "n");
21214
+ __publicField(this, "c");
21215
+ __publicField(this, "u");
21216
+ __publicField(this, "i");
21217
+ __publicField(this, "nv");
21218
+ __publicField(this, "ni");
21219
+ __publicField(this, "lim");
21220
+ __publicField(this, "cur");
21221
+ __publicField(this, "piece0");
21222
+ __publicField(this, "mat", "");
21223
+ __publicField(this, "group", "");
20731
21224
  this.cv = 2048;
20732
21225
  this.ci = 3072;
20733
21226
  this.p = new Float32Array(this.cv * 3);
@@ -20790,7 +21283,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
20790
21283
  g.position.copy(u.pose0.p);
20791
21284
  g.quaternion.copy(u.pose0.q);
20792
21285
  g.scale.copy(u.pose0.s);
20793
- const e = new THREE.Vector3(...a.axis || [0, 1, 0]);
21286
+ const [ax, ay, az] = a.axis || [0, 1, 0];
21287
+ const e = new THREE.Vector3(ax, ay, az);
20794
21288
  if (a.type === "swing" || a.type === "toggle") g.rotateOnAxis(e, (a.angle || 0) * t);
20795
21289
  else if (a.type === "slide") g.translateOnAxis(e, (a.dist || 0) * t);
20796
21290
  else if (a.type === "scale") {
@@ -20885,7 +21379,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
20885
21379
  }
20886
21380
  if (uvr) {
20887
21381
  let gu = G.u[k * 2], gv = G.u[k * 2 + 1];
20888
- for (let r = uvr.rot | 0; r > 0; r--) {
21382
+ for (let r = (uvr.rot ?? 0) | 0; r > 0; r--) {
20889
21383
  const t = gu;
20890
21384
  gu = gv;
20891
21385
  gv = 1 - t;
@@ -20983,14 +21477,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
20983
21477
  A.nv += n;
20984
21478
  }
20985
21479
  let bxImpl = bxBase;
20986
- function bx(...a) {
20987
- return bxImpl(...a);
20988
- }
20989
- K.getBx = () => bxImpl;
20990
- K.setBx = (f) => {
21480
+ const bx = (...a) => bxImpl(...a);
21481
+ const getBx = () => bxImpl;
21482
+ const setBx = (f) => {
20991
21483
  bxImpl = f;
20992
21484
  };
20993
- 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 });
21485
+ 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 };
21486
+ Object.assign(K, defined);
20994
21487
  }
20995
21488
  function installKernelNoise(K, _shared) {
20996
21489
  const _h2 = (x, z) => {
@@ -21006,15 +21499,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21006
21499
  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;
21007
21500
  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)];
21008
21501
  }
21009
- Object.assign(K, { _h2, vnoise, macroGround });
21502
+ const defined = { _h2, vnoise, macroGround };
21503
+ Object.assign(K, defined);
21010
21504
  }
21011
21505
  function installMaterialsTextures(K, _shared) {
21012
21506
  const { DOC, THREE, cfg } = K;
21013
21507
  function texture(n, f, rep = true, rx = 1, ry = 1) {
21508
+ if (!DOC) throw new Error("game-floorplan-three: the procedural textures need a document (options.document)");
21014
21509
  const c = DOC.createElement("canvas");
21015
21510
  c.width = n;
21016
21511
  c.height = n;
21017
21512
  const g = c.getContext("2d");
21513
+ if (!g) throw new Error("game-floorplan-three: no 2d canvas context");
21018
21514
  f(g, n);
21019
21515
  const t = new THREE.CanvasTexture(c);
21020
21516
  t.colorSpace = THREE.SRGBColorSpace;
@@ -21133,7 +21629,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21133
21629
  const TEX = {};
21134
21630
  for (const k of Object.keys(TEXGEN)) TEX[k] = cfg.textures && cfg.textures[k] || TEXGEN[k]();
21135
21631
  const ATLAS = {};
21136
- Object.assign(K, { texture, rngTexture, TEXGEN, TEX, ATLAS });
21632
+ const defined = { texture, rngTexture, TEXGEN, TEX, ATLAS };
21633
+ Object.assign(K, defined);
21634
+ }
21635
+ function context2d(c) {
21636
+ const g = c.getContext("2d");
21637
+ if (!g) throw new Error("game-floorplan-three: no 2d canvas context");
21638
+ return g;
21137
21639
  }
21138
21640
  function installMaterialsMaterials(K, _shared) {
21139
21641
  const { THREE, cfg, ATLAS, TEX, rngTexture } = K;
@@ -21146,7 +21648,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21146
21648
  return t;
21147
21649
  };
21148
21650
  if (!(cfg.atlas && cfg.atlas.floorKind)) {
21149
- const pc = props.atlas("floor").canvas, g = pc.getContext("2d");
21651
+ const pc = props.atlas("floor").canvas, g = context2d(pc);
21150
21652
  for (const c of [0, 1]) {
21151
21653
  g.save();
21152
21654
  g.globalCompositeOperation = "screen";
@@ -21161,7 +21663,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21161
21663
  g.restore();
21162
21664
  }
21163
21665
  if (!(cfg.atlas && cfg.atlas.floorKind)) {
21164
- const pc = props.atlas("floor").canvas, g = pc.getContext("2d");
21666
+ const pc = props.atlas("floor").canvas, g = context2d(pc);
21165
21667
  g.save();
21166
21668
  g.fillStyle = "rgba(128,92,62,0.52)";
21167
21669
  g.fillRect(256, 256, 256, 256);
@@ -21258,7 +21760,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21258
21760
  }
21259
21761
  const ORDER = { glass: 3, water: 2, screen: 3, building: 4 };
21260
21762
  const NO_SHADOW = /* @__PURE__ */ new Set(["dirt", "glass", "water", "screen", "building", "picture", "floor", "emissive"]);
21261
- Object.assign(K, { createMaterials, antiTile, dirtMaterial, CLOTHES_UNIFORMS, clothesMaterial, ORDER, NO_SHADOW });
21763
+ const defined = { createMaterials, antiTile, dirtMaterial, CLOTHES_UNIFORMS, clothesMaterial, ORDER, NO_SHADOW };
21764
+ Object.assign(K, defined);
21262
21765
  }
21263
21766
  function installKernelCloseScene(K, shared2) {
21264
21767
  const { THREE, NO_SHADOW, ORDER, PARTS, applyPart, cursor } = K;
@@ -21267,15 +21770,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21267
21770
  const assembleVegetation = (...a) => K.assembleVegetation(...a);
21268
21771
  function markMesh(m, A) {
21269
21772
  const L = A.lim, fx = [];
21773
+ const pieces = shared2.ctx.pieces;
21270
21774
  for (let k = 0; k < L.length; k++) {
21271
- if (!L[k].pc) continue;
21272
- const v1 = k + 1 < L.length ? L[k + 1].v : A.nv, i1 = k + 1 < L.length ? L[k + 1].i : A.ni;
21273
- if (v1 > L[k].v) fx.push({ id: L[k].pc.id, v0: L[k].v, v1, i0: L[k].i, i1 });
21775
+ const lim = L[k], pc = lim.pc;
21776
+ if (!pc) continue;
21777
+ const next = L[k + 1];
21778
+ const v1 = next ? next.v : A.nv, i1 = next ? next.i : A.ni;
21779
+ if (v1 > lim.v) fx.push({ id: pc.id, v0: lim.v, v1, i0: lim.i, i1 });
21274
21780
  }
21275
21781
  if (!fx.length) return;
21276
21782
  const u = m.userData, ids = [...new Set(fx.map((f) => f.id))], weight = {};
21277
21783
  for (const f of fx) {
21278
- const mt = shared2.ctx.pieces.get(f.id).mat;
21784
+ const mt = pieces.get(f.id).mat;
21279
21785
  weight[mt] = (weight[mt] || 0) + f.v1 - f.v0;
21280
21786
  }
21281
21787
  u.ranges = fx;
@@ -21283,7 +21789,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21283
21789
  u.destructionMaterial = Object.keys(weight).sort((a, b) => weight[b] - weight[a])[0];
21284
21790
  if (ids.length === 1) {
21285
21791
  u.destructionPart = ids[0];
21286
- const pc = shared2.ctx.pieces.get(ids[0]);
21792
+ const pc = pieces.get(ids[0]);
21287
21793
  if (pc.role) u.structuralRole = pc.role;
21288
21794
  }
21289
21795
  }
@@ -21334,7 +21840,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21334
21840
  assembleVegetation(groups);
21335
21841
  return groups;
21336
21842
  }
21337
- Object.assign(K, { markMesh, closeScene });
21843
+ const defined = { markMesh, closeScene };
21844
+ Object.assign(K, defined);
21338
21845
  }
21339
21846
  function installHouseHelpers(K, shared2) {
21340
21847
  shared2.ctx = {};
@@ -21370,8 +21877,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21370
21877
  for (const h of holes) L = L.flatMap((r) => subRect(r, h));
21371
21878
  return L;
21372
21879
  }
21373
- const wallColor = (c) => c && c.color && colorOf(c.color.wall) != null ? colorOf(c.color.wall) : 14999768;
21374
- const floorColor = (c) => c && c.color && colorOf(c.color.floor) != null ? colorOf(c.color.floor) : 11577496;
21880
+ const wallColor = (c) => {
21881
+ const k = c && c.color ? colorOf(c.color.wall) : null;
21882
+ return k != null ? k : 14999768;
21883
+ };
21884
+ const floorColor = (c) => {
21885
+ const k = c && c.color ? colorOf(c.color.floor) : null;
21886
+ return k != null ? k : 11577496;
21887
+ };
21375
21888
  function stairFootprint(m) {
21376
21889
  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]);
21377
21890
  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]))];
@@ -21382,10 +21895,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21382
21895
  const pitch = A[f + 1].y0 - A[f].y0;
21383
21896
  return h > pitch && h - pitch <= 0.45 ? pitch : h;
21384
21897
  }
21385
- Object.assign(K, { OPEN_ROOM_TYPES: OPEN_ROOM_TYPES22, NO_CEILING, OPEN_AREA, EPS: EPS3, Y0, colorOf, rectsOf: rectsOf2, roomAt, subRect, subRects, wallColor, floorColor, stairFootprint, effectiveHeight });
21898
+ const defined = { OPEN_ROOM_TYPES: OPEN_ROOM_TYPES22, NO_CEILING, OPEN_AREA, EPS: EPS3, Y0, colorOf, rectsOf: rectsOf2, roomAt, subRect, subRects, wallColor, floorColor, stairFootprint, effectiveHeight };
21899
+ Object.assign(K, defined);
21386
21900
  }
21387
21901
  function installHouseWalls(K, shared2) {
21388
21902
  const { EPS: EPS3, Y0, boxC, bx, cursor, effectiveHeight, pieceRecord, structurePiece, wallColor } = K;
21903
+ const sh = (...a) => K.sh(...a);
21389
21904
  function wallBox(alongU, L, a, b, ya, yb, th, cL, cH, mL, mH) {
21390
21905
  if (yb - ya < 1e-4 || b - a < 1e-4) return;
21391
21906
  if (alongU) {
@@ -21429,8 +21944,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21429
21944
  function walls() {
21430
21945
  const R = shared2.ctx.r, cut = shared2.ctx.cut, nA = R.floors.length, vMin = Math.min(...R.walls.map((w) => w.axis === "u" ? w.v0 : Math.min(w.v0, w.v1)));
21431
21946
  const corners = /* @__PURE__ */ new Map();
21947
+ const looks = /* @__PURE__ */ new Map();
21432
21948
  for (const w of R.walls) {
21433
- const f = w.floor;
21949
+ const f = w.floor, colliders = shared2.ctx.colliders;
21434
21950
  cursor.group = "f" + f;
21435
21951
  cursor.pc = pieceOf(w);
21436
21952
  const y0 = Y0(f), pitch = f + 1 < nA ? Y0(f + 1) - y0 : Infinity, th = w.thickness || 0.15, alongU = w.axis === "u";
@@ -21438,7 +21954,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21438
21954
  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);
21439
21955
  const front = alongU && Math.abs(L - vMin) < 0.05;
21440
21956
  const sideL = sideOf(w.sides[0], front), sideH = sideOf(w.sides[1], front);
21441
- shared2.ctx.colliders.push({ type: "wall", piece: w.id, f, x0: alongU ? s0 : L - th / 2, z0: alongU ? L - th / 2 : s0, x1: alongU ? s1 : L + th / 2, z1: alongU ? L + th / 2 : s1 });
21957
+ if (w.id) {
21958
+ const face = sideL.exterior ? sideL : sideH;
21959
+ looks.set(w.id, { mat: face.mat, color: face.color, top: y0 + hh });
21960
+ }
21961
+ 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 });
21442
21962
  if (w.type === "railing") {
21443
21963
  const c0 = shared2.ctx.colors.metal != null ? shared2.ctx.colors.metal : 9080466;
21444
21964
  const sx = alongU ? 1 : 0, sz = alongU ? 0 : 1, len = s1 - s0, n = Math.max(1, Math.round(len / 1.4));
@@ -21484,8 +22004,28 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21484
22004
  cursor.group = "f" + e.f;
21485
22005
  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);
21486
22006
  }
22007
+ if (shared2.ctx.showPillars) wallPillars(looks);
21487
22008
  }
21488
- Object.assign(K, { wallBox, sideOf, pieceOf, nearestWall, walls });
22009
+ const PILLAR_IN_WALL = /^(wall_column_|column_\d|jamb_column_)/;
22010
+ const wallOf = (pillar, parts) => {
22011
+ const u = (pillar.aabb[0] + pillar.aabb[2]) / 2, v = (pillar.aabb[1] + pillar.aabb[3]) / 2;
22012
+ 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);
22013
+ };
22014
+ function wallPillars(looks) {
22015
+ const parts = Object.values(shared2.ctx.structureIndex);
22016
+ for (const e of parts) {
22017
+ if (e.role !== "column" || !PILLAR_IN_WALL.test(e.id)) continue;
22018
+ const host = wallOf(e, parts);
22019
+ const look = host && looks.get(host.id);
22020
+ if (!host || !look) continue;
22021
+ cursor.group = "f" + e.floor;
22022
+ cursor.pc = structurePiece(host.id);
22023
+ 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));
22024
+ }
22025
+ cursor.pc = null;
22026
+ }
22027
+ const defined = { wallBox, sideOf, pieceOf, nearestWall, walls, wallPillars };
22028
+ Object.assign(K, defined);
21489
22029
  }
21490
22030
  function installHouseDoors(K, shared2) {
21491
22031
  const seedKey = (id) => K.seedKey(id);
@@ -21502,7 +22042,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21502
22042
  }
21503
22043
  shared2.doorState = /* @__PURE__ */ new Map();
21504
22044
  function doors() {
21505
- shared2.ctx.leaves = [];
22045
+ const leaves = shared2.ctx.leaves = [], doorState = shared2.doorState, colliders = shared2.ctx.colliders;
21506
22046
  const R = shared2.ctx.r, cut = shared2.ctx.cut, C = shared2.ctx.colors, wood = C.wood != null ? C.wood : 8016948, frame2 = sh(wood, 0.55);
21507
22047
  for (const p of R.doors) {
21508
22048
  const f = p.floor;
@@ -21533,21 +22073,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21533
22073
  }
21534
22074
  const leaf = (u0, u1, y_0, y_1, tt, color2, mat = "wood") => alongU ? bx(mat, u0, y0 + y_0, L - tt / 2, u1, y0 + y_1, L + tt / 2, color2) : bx(mat, L - tt / 2, y0 + y_0, u0, L + tt / 2, y0 + y_1, u1, color2);
21535
22075
  const extC = wood;
21536
- const open0 = p.blocked ? false : shared2.doorState.has(p.id) ? shared2.doorState.get(p.id) : !!p.open;
21537
- shared2.doorState.set(p.id, open0);
22076
+ const open0 = p.blocked ? false : doorState.has(p.id) ? doorState.get(p.id) === true : !!p.open;
22077
+ doorState.set(p.id, open0);
21538
22078
  const dc = alongU ? [p.at, L] : [L, p.at];
21539
- 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 };
22079
+ 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 };
21540
22080
  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 };
21541
- shared2.ctx.colliders.push(colR);
22081
+ colliders.push(colR);
21542
22082
  fo.col = colR;
21543
22083
  const leafBox = (hu, d0, d1, y_0, y_1, tt, color2, mat) => alongU ? bx(mat, d0, y_0, -tt / 2, d1, y_1, tt / 2, color2) : bx(mat, -tt / 2, y_0, d0, tt / 2, y_1, d1, color2);
21544
- const newGroup = (k, hu, topY) => {
22084
+ const newGroup2 = (k, hu, topY) => {
21545
22085
  cursor.group = "dyn:" + p.id + ":" + k;
21546
22086
  fo.groups.push({ name: cursor.group, pos: alongU ? [hu, topY != null ? y0 + topY : y0, L] : [L, topY != null ? y0 + topY : y0, hu] });
21547
22087
  };
21548
22088
  if (p.model === "steel") {
21549
- const light = [14276044, 13223615, 14999766], pal = ((R.seed | 0) + p.id.length * 7) % 4, color2 = pal === 3 ? wood : light[pal], mid = (a + b) / 2;
21550
- newGroup(0, mid, visH);
22089
+ const light = [14276044, 13223615, 14999766], pal = ((Number(R.seed) | 0) + p.id.length * 7) % 4, color2 = pal === 3 ? wood : light[pal], mid = (a + b) / 2;
22090
+ newGroup2(0, mid, visH);
21551
22091
  const la = a + jw - mid, lb = b - jw - mid, nSec = Math.max(4, Math.round(visH / 0.5)), hs = visH / nSec, grv = sh(color2, 0.55);
21552
22092
  leafBox(0, la, lb, -visH, 0, 0.05, color2, "metal");
21553
22093
  for (let k = 1; k < nSec; k++) leafBox(0, la, lb, -k * hs - 0.012, -k * hs + 0.012, 0.07, grv, "metal");
@@ -21562,7 +22102,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21562
22102
  for (let k = 0; k < nf; k++) {
21563
22103
  const u0 = nf === 2 ? k ? (aa + bb) / 2 : aa : aa, u1 = nf === 2 ? k ? bb : (aa + bb) / 2 : bb, color2 = p.exterior ? extC : wood;
21564
22104
  const hingeAt = nf === 2 ? k ? u1 : u0 : p.hinge === "end" ? u1 : u0, dir = hingeAt === u0 ? 1 : -1, len = u1 - u0;
21565
- newGroup(k, hingeAt);
22105
+ newGroup2(k, hingeAt);
21566
22106
  const d0 = dir > 0 ? 5e-3 : -len + 5e-3, d1 = dir > 0 ? len - 5e-3 : -5e-3;
21567
22107
  leafBox(hingeAt, d0, d1, 0, visH, 0.04, color2, PMAT);
21568
22108
  {
@@ -21598,7 +22138,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21598
22138
  fo.rot = Math.atan2(n[0] * A[1] - n[1] * A[0], A[0] * n[0] + A[1] * n[1]);
21599
22139
  }
21600
22140
  }
21601
- shared2.ctx.leaves.push(fo);
22141
+ leaves.push(fo);
21602
22142
  cursor.group = "f" + f;
21603
22143
  if (p.blocked) {
21604
22144
  part("window_boards", [0, 0, 0], () => {
@@ -21626,11 +22166,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21626
22166
  }
21627
22167
  }
21628
22168
  }, { id: "boards:" + p.id }, "f" + f);
21629
- shared2.ctx.colliders.push({ type: "board", f, x0: alongU ? a : L - th / 2, z0: alongU ? L - th / 2 : a, x1: alongU ? b : L + th / 2, z1: alongU ? L + th / 2 : b });
22169
+ 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 });
21630
22170
  }
21631
22171
  }
21632
22172
  }
21633
- Object.assign(K, { doorLineSides, doors });
22173
+ const defined = { doorLineSides, doors };
22174
+ Object.assign(K, defined);
21634
22175
  }
21635
22176
  function installHouseWindows(K, shared2) {
21636
22177
  const { EPS: EPS3, Y0, boxC, bx, cursor, pieceRecord, roomAt } = K;
@@ -21688,7 +22229,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21688
22229
  }
21689
22230
  }
21690
22231
  }
21691
- Object.assign(K, { FRAME_COLORS, SILL_COLORS, windows });
22232
+ const defined = { FRAME_COLORS, SILL_COLORS, windows };
22233
+ Object.assign(K, defined);
21692
22234
  }
21693
22235
  function installHouseFloors(K, shared2) {
21694
22236
  const { rectsOf: rectsOf2, EPS: EPS3, OPEN_AREA, Y0, bx, cursor, floorColor, stairFootprint, structurePiece, subRects } = K;
@@ -21696,7 +22238,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21696
22238
  if (shared2.ctx._flights && shared2.ctx._flights.r === shared2.ctx.r) return shared2.ctx._flights.l;
21697
22239
  const R = shared2.ctx.r, mp = /* @__PURE__ */ new Map();
21698
22240
  for (const m of R.items) {
21699
- if (m.type !== "stairs" || !m.link) continue;
22241
+ if (m.type !== "stairs" || !m.link || typeof m.link !== "object") continue;
21700
22242
  const k = [m.link.from, m.link.to, m.x.toFixed(2), m.z.toFixed(2), (m.ry || 0).toFixed(2)].join("|");
21701
22243
  if (!mp.has(k)) mp.set(k, { m, from: m.link.from, to: m.link.to, rect: stairFootprint(m) });
21702
22244
  }
@@ -21715,7 +22257,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21715
22257
  }
21716
22258
  const panelRects = (p) => p.footprint && p.footprint.length ? p.footprint : [p.aabb];
21717
22259
  function tilesOf(parent, rc) {
21718
- const ps = parent && shared2.ctx.panelsOf && shared2.ctx.panelsOf.get(parent);
22260
+ const ps = parent ? shared2.ctx.panelsOf && shared2.ctx.panelsOf.get(parent) : void 0;
21719
22261
  if (!ps) return [[parent ? structurePiece(parent) : null, rc]];
21720
22262
  const out = [], taken = [];
21721
22263
  for (const p of ps) for (const q of panelRects(p)) {
@@ -21777,13 +22319,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21777
22319
  const { rectsOf: rectsOf2, Y0, boxC, bx, cursor, flights, stairFootprint, structurePiece } = K;
21778
22320
  const sh = (...a) => K.sh(...a);
21779
22321
  function buildStairs() {
21780
- const R = shared2.ctx.r;
21781
- shared2.ctx.stairs = [];
22322
+ const R = shared2.ctx.r, stairs = shared2.ctx.stairs = [];
21782
22323
  for (const vo of flights()) {
21783
22324
  const m = vo.m, f = vo.from, Dr = m.d - (vo.LP || 0);
21784
22325
  cursor.group = "f" + f;
21785
22326
  cursor.pc = structurePiece("stairs_" + vo.from + "_" + vo.to);
21786
- 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);
22327
+ 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);
21787
22328
  const wood = shared2.ctx.colors.wood != null ? shared2.ctx.colors.wood : 9071176, under = sh(wood, 0.7);
21788
22329
  const P = (lx, lz) => [m.x + lx * c + lz * s, m.z - lx * s + lz * c];
21789
22330
  const boxL = (mat, lx, y, lz, w, h, d, color2, rx = 0) => {
@@ -21806,7 +22347,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21806
22347
  }
21807
22348
  }
21808
22349
  cursor.pc = null;
21809
- shared2.ctx.stairs.push({ m, f, to: vo.to, y0, H, rect: stairFootprint(m), landingPoint: (vo.LP || 0) / m.d });
22350
+ stairs.push({ m, f, to: vo.to, y0, H, rect: stairFootprint(m), landingPoint: (vo.LP || 0) / m.d });
21810
22351
  }
21811
22352
  }
21812
22353
  function elevator() {
@@ -21823,7 +22364,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21823
22364
  }
21824
22365
  }
21825
22366
  }
21826
- Object.assign(K, { buildStairs, elevator });
22367
+ const defined = { buildStairs, elevator };
22368
+ Object.assign(K, defined);
21827
22369
  }
21828
22370
  function installLightsFixtures(K, shared2) {
21829
22371
  const seedKey = (id) => K.seedKey(id);
@@ -21861,14 +22403,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21861
22403
  c: (mat, x, y, z, r, h, color2, seg2) => api.cylinder(M, mat, x, y0 + y, z, r, h, color2, 0, 0, seg2),
21862
22404
  e: (mat, x, y, z, r, h, color2) => api.cylinder(M, mat, x, y0 + y - h / 2, z, r, h, color2, 0, 0, "sphere"),
21863
22405
  t(mat, p, q, r, color2, seg2) {
22406
+ const tc = color2 ?? NaN;
21864
22407
  const dx = q[0] - p[0], dy = q[1] - p[1], dz = q[2] - p[2], L = Math.hypot(dx, dy, dz);
21865
22408
  if (L < 1e-5) return;
21866
22409
  const nx = dx / L, ny = dy / L, nz = dz / L;
21867
22410
  if (Math.abs(nx) < 1e-4 && Math.abs(nz) < 1e-4) {
21868
- api.cylinder(M, mat, p[0], y0 + Math.min(p[1], q[1]), p[2], r, L, color2, 0, 0, seg2);
22411
+ api.cylinder(M, mat, p[0], y0 + Math.min(p[1], q[1]), p[2], r, L, tc, 0, 0, seg2);
21869
22412
  return;
21870
22413
  }
21871
- api.cylinder(M, mat, (p[0] + q[0]) / 2, y0 + (p[1] + q[1]) / 2, (p[2] + q[2]) / 2, r, L, color2, Math.atan2(nz, ny), -Math.asin(nx), seg2);
22414
+ api.cylinder(M, mat, (p[0] + q[0]) / 2, y0 + (p[1] + q[1]) / 2, (p[2] + q[2]) / 2, r, L, tc, Math.atan2(nz, ny), -Math.asin(nx), seg2);
21872
22415
  },
21873
22416
  polyFace: (mat, pts, color2, hint) => polyFace(mat, pts.map((p) => W(p[0], p[1], p[2])), color2, hint && [hint[0] * c + hint[2] * s, hint[1], -hint[0] * s + hint[2] * c]),
21874
22417
  part(type, lx, ly, lz, fn, meta) {
@@ -22047,7 +22590,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22047
22590
  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 });
22048
22591
  }
22049
22592
  }
22050
- Object.assign(K, { hashString: hashString2, rngString, SEED, STYLE, kit2, arcPoints, TEMP_WARM, TEMP_NEUTRAL, TEMP_COOL, colorTemperature, lightStyle, ceilingLamp, tableLamp, floorLamp, sconce, outdoorLamp, lightSwitch });
22593
+ const defined = { hashString: hashString2, rngString, SEED, STYLE, kit2, arcPoints, TEMP_WARM, TEMP_NEUTRAL, TEMP_COOL, colorTemperature, lightStyle, ceilingLamp, tableLamp, floorLamp, sconce, outdoorLamp, lightSwitch };
22594
+ Object.assign(K, defined);
22051
22595
  }
22052
22596
  function installLightsDecor(K, shared2) {
22053
22597
  const { EPS: EPS3, OPEN_AREA, SEED, Y0, cursor, rngString, roomAt, stairFootprint } = K;
@@ -22112,7 +22656,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22112
22656
  void sd;
22113
22657
  }
22114
22658
  }
22115
- Object.assign(K, { decorLights });
22659
+ const defined = { decorLights };
22660
+ Object.assign(K, defined);
22116
22661
  }
22117
22662
  function installLotTerrain(K, shared2) {
22118
22663
  const { rectsOf: rectsOf2, MIRRORS, PARTS, bx, cursor } = K;
@@ -22163,7 +22708,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22163
22708
  if (x < b) out.push([x, b]);
22164
22709
  return out.filter((q) => q[1] - q[0] > 0.3);
22165
22710
  }
22166
- Object.assign(K, { terrain, freeSpans });
22711
+ const defined = { terrain, freeSpans };
22712
+ Object.assign(K, defined);
22167
22713
  }
22168
22714
  function installLotPerimeter(K, shared2) {
22169
22715
  const { EPS: EPS3, boxC, bx, colorOf, cursor, freeSpans, pieceRecord } = K;
@@ -22181,7 +22727,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22181
22727
  for (const s of lt.perimeter) {
22182
22728
  const alongU = Math.abs(s.v1 - s.v0) < EPS3, 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);
22183
22729
  cursor.pc = pieceRecord("lot_wall:" + s.id, s.type === "wall" ? "brick" : s.type === "fence" ? "wood_soft" : "steel", null, { tags: ["wall"] });
22184
- const th = s.thickness || 0.15, h = s.height, color2 = colorOf(s.color) != null ? colorOf(s.color) : C.wall || 12104874, len = b - a;
22730
+ const th = s.thickness || 0.15, h = s.height, color2 = colorOf(s.color) ?? (C.wall || 12104874), len = b - a;
22185
22731
  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);
22186
22732
  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 };
22187
22733
  shared2.ctx.colliders.push(col);
@@ -22255,7 +22801,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22255
22801
  }
22256
22802
  }
22257
22803
  }
22258
- Object.assign(K, { perimeter, paths });
22804
+ const defined = { perimeter, paths };
22805
+ Object.assign(K, defined);
22259
22806
  }
22260
22807
  function installLotGates(K, shared2) {
22261
22808
  const { bx, colorOf, cursor, cylBase } = K;
@@ -22269,7 +22816,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22269
22816
  cursor.group = "lot";
22270
22817
  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;
22271
22818
  for (const g of lt.gates) {
22272
- 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";
22819
+ 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";
22273
22820
  const sd = cz - v >= 0 ? 1 : -1;
22274
22821
  const pil = (x0, x1, high) => {
22275
22822
  bx("plaster", x0, 0, v - 0.13, x1, high, v + 0.13, wall);
@@ -22341,7 +22888,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22341
22888
  if (!g.open || ped) shared2.ctx.colliders.push({ type: "gate", f: -1, x0: a, z0: v - 0.1, x1: b, z1: v + 0.1 });
22342
22889
  }
22343
22890
  }
22344
- Object.assign(K, { slideDirection, gates });
22891
+ const defined = { slideDirection, gates };
22892
+ Object.assign(K, defined);
22345
22893
  }
22346
22894
  function installRoofRoofs(K, shared2) {
22347
22895
  const { rectsOf: rectsOf2, EPS: EPS3, OPEN_AREA, Y0, bx, cursor } = K;
@@ -22353,13 +22901,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22353
22901
  function roofs() {
22354
22902
  const R = shared2.ctx.r, F = R.facade, C = shared2.ctx.colors, nA = R.floors.length, type = F.roof;
22355
22903
  cursor.group = "roof";
22356
- shared2.ctx.roofRects = [];
22357
- shared2.ctx.gutter = gutterConfig();
22358
- shared2.ctx.gutter.ncond = 0;
22359
- shared2.ctx.gutter.nbuz = 0;
22360
- shared2.ctx.gutter.bz = /* @__PURE__ */ new Set();
22904
+ const roofRects = shared2.ctx.roofRects = [];
22905
+ const G = shared2.ctx.gutter = gutterConfig();
22906
+ G.ncond = 0;
22907
+ G.nbuz = 0;
22908
+ G.bz = /* @__PURE__ */ new Set();
22361
22909
  shared2.ctx.gutterInfo = { gutters: [], downpipes: [], drains: [] };
22362
- const roofColor = C.roof != null ? C.roof : 11031610, gable = (R.seed | 0) % 2 === 0;
22910
+ const roofColor = C.roof != null ? C.roof : 11031610, gable = (Number(R.seed) | 0) % 2 === 0;
22363
22911
  for (let f = 0; f < nA; f++) {
22364
22912
  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);
22365
22913
  if (!rs.length) continue;
@@ -22381,7 +22929,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22381
22929
  return Y0(f) + Math.max(...cs.map((c) => c.ceiling)) + 0.2;
22382
22930
  };
22383
22931
  if (type === "slab") {
22384
- for (let j = 0; j < nz; j++) for (let i = 0; i < nx; i++) if (O(j, i)) shared2.ctx.roofRects.push({ f, r: [xs[i], zs[j], xs[i + 1], zs[j + 1]], slab: true, yb: pe(xs[i], zs[j], xs[i + 1], zs[j + 1]) + 0.03 });
22932
+ 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 });
22385
22933
  slabs(f, xs, zs, O, U, nx, nz, full, pe, C);
22386
22934
  cursor.pc = null;
22387
22935
  continue;
@@ -22404,16 +22952,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22404
22952
  if (U(q.j0 - 1, i)) touchesU[1] = 1;
22405
22953
  if (U(q.j1 + 1, i)) touchesU[3] = 1;
22406
22954
  }
22407
- shared2.ctx.roofRects.push({ f, r: [x0, z0, x1, z1], touchesU });
22955
+ roofRects.push({ f, r: [x0, z0, x1, z1], touchesU });
22408
22956
  const ybq = pe(x0, z0, x1, z1);
22409
22957
  roofRect(type, x0, z0, x1, z1, ybq, roofColor, gable && single, F, touchesU);
22410
22958
  cursor.pc = null;
22411
- if (shared2.ctx.gutter.on) gutter(type, f, x0, z0, x1, z1, ybq, touchesU);
22959
+ if (G.on) gutter(type, f, x0, z0, x1, z1, ybq, touchesU);
22412
22960
  }
22413
22961
  }
22414
22962
  for (const e of shared2.ctx.outbuildingList || []) {
22415
22963
  const [x0, z0, x1, z1] = e.aabb, yb = Y0(0) + (e.ceiling || 2.6) + 0.2;
22416
- shared2.ctx.roofRects.push({ f: 0, r: [x0, z0, x1, z1], outbuilding: e.id });
22964
+ roofRects.push({ f: 0, r: [x0, z0, x1, z1], outbuilding: e.id });
22417
22965
  if (type === "slab") {
22418
22966
  const c = C.facade != null ? C.facade : 14209216;
22419
22967
  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));
@@ -22424,11 +22972,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22424
22972
  roofRect(type, x0, z0, x1, z1, yb, roofColor, true, F, [0, 0, 0, 0]);
22425
22973
  cursor.pc = null;
22426
22974
  shared2.ctx.noPiece = false;
22427
- if (shared2.ctx.gutter.on) gutter(type, 0, x0, z0, x1, z1, yb, [0, 0, 0, 0]);
22975
+ if (G.on) gutter(type, 0, x0, z0, x1, z1, yb, [0, 0, 0, 0]);
22428
22976
  }
22429
22977
  }
22430
- Object.assign(K, { roofs });
22978
+ const defined = { roofs };
22979
+ Object.assign(K, defined);
22431
22980
  }
22981
+ var paletteMeta = (colors) => colors.meta;
22432
22982
  function installRoofGutters(K, shared2) {
22433
22983
  const { boxC, bx, cursor, roomAt } = K;
22434
22984
  const sh = (...a) => K.sh(...a);
@@ -22445,7 +22995,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22445
22995
  const draw = rnd() < p, light = rnd() < 0.6;
22446
22996
  void draw;
22447
22997
  const on = true;
22448
- return { on, rnd, color: high ? 3816770 : light ? 15527921 : 10857392, bad: (shared2.ctx.colors.meta && shared2.ctx.colors.meta.state) === "abandoned" || R.state === "abandoned", fallback: false };
22998
+ return { on, rnd, color: high ? 3816770 : light ? 15527921 : 10857392, bad: paletteMeta(shared2.ctx.colors)?.state === "abandoned" || R.state === "abandoned", fallback: false };
22449
22999
  }
22450
23000
  function gutter(type, f, X0, Z0, X1, Z1, yb, touchesU) {
22451
23001
  const G = shared2.ctx.gutter, o = type === "fiber_cement" ? 0.3 : 0.45, x0 = X0 - (touchesU[0] ? 0 : o), x1 = X1 + (touchesU[2] ? 0 : o), z0 = Z0 - (touchesU[1] ? 0 : o), z1 = Z1 + (touchesU[3] ? 0 : o), c = G.color, y = yb - 0.05;
@@ -22487,7 +23037,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22487
23037
  const px = cx + sx * 0.06, pz = cz + sz * 0.06;
22488
23038
  if (!freeAt(px, pz, sx, sz)) return false;
22489
23039
  const floats = G.bad && G.ncond === 1, yt = yb - 0.1, ybx = floats ? 0.7 : 0.04;
22490
- G.ncond++;
23040
+ G.ncond = (G.ncond ?? 0) + 1;
22491
23041
  if (run2 >= 2) boxC("plain", (sides[run2][4] + px) / 2, yt, pz, Math.abs(sides[run2][4] - px), 0.07, 0.07, c);
22492
23042
  else boxC("plain", px, yt, (sides[run2][4] + pz) / 2, 0.07, 0.07, Math.abs(sides[run2][4] - pz), c);
22493
23043
  boxC("plain", px, (ybx + yt) / 2, pz, 0.08, yt - ybx, 0.08, c);
@@ -22521,7 +23071,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22521
23071
  function drain(x, z, px, pz, c) {
22522
23072
  const g0 = cursor.group;
22523
23073
  cursor.group = "f0";
22524
- 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));
23074
+ 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));
22525
23075
  const t = 0.045;
22526
23076
  bx("plain", x - 0.12, 0, z - 0.12, x + 0.12, t - 6e-3, z + 0.12, 12170668);
22527
23077
  bx("metal", x - 0.11, t, z - 0.11, x + 0.11, t + 0.012, z + 0.11, 5922145);
@@ -22532,7 +23082,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22532
23082
  bx("metal", x - 0.085, t + 0.012, z - 6e-3, x + 0.085, t + 0.02, z + 6e-3, 9080466);
22533
23083
  cursor.group = g0;
22534
23084
  }
22535
- Object.assign(K, { gutterConfig, gutter, drain });
23085
+ const defined = { gutterConfig, gutter, drain };
23086
+ Object.assign(K, defined);
22536
23087
  }
22537
23088
  function installRoofSlabs(K, shared2) {
22538
23089
  const { boxC, bx, cursor, drain, roomAt, structurePiece } = K;
@@ -22564,15 +23115,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22564
23115
  side(free(j, i + 1), x1 + o - t, z0 - ez0, x1 + o, z1 + ez1);
22565
23116
  side(free(j - 1, i), x0 - ex0, z0 - o, x1 + ex1, z0 - o + t);
22566
23117
  side(free(j + 1, i), x0 - ex0, z1 + o - t, x1 + ex1, z1 + o);
22567
- if (shared2.ctx.gutter && shared2.ctx.gutter.on) for (const [ok, dx, dz] of [[free(j - 1, i), 0, -1], [free(j + 1, i), 0, 1], [free(j, i - 1), -1, 0], [free(j, i + 1), 1, 0]]) {
23118
+ const G = shared2.ctx.gutter;
23119
+ 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]]) {
22568
23120
  const kd = f + ":" + dx + ":" + dz;
22569
- if (!ok || shared2.ctx.gutter.bz.has(kd)) continue;
22570
- shared2.ctx.gutter.bz.add(kd);
22571
- shared2.ctx.gutter.nbuz++;
22572
- const mx = (x0 + x1) / 2, mz = (z0 + z1) / 2, ex = dx ? dx < 0 ? x0 - o : x1 + o : mx, ez = dz ? dz < 0 ? z0 - o : z1 + o : mz, cc = shared2.ctx.gutter.color;
23121
+ if (!ok || G.bz.has(kd)) continue;
23122
+ G.bz.add(kd);
23123
+ G.nbuz = (G.nbuz ?? 0) + 1;
23124
+ 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;
22573
23125
  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);
22574
23126
  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));
22575
- if (shared2.ctx.gutter.bad) boxC("plain", ex + dx * 0.05, yb + 0.5 * 0, ez + dz * 0.05, dx ? 0.06 : 0.3, 0.02, dz ? 0.06 : 0.3, 4868674);
23127
+ 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);
22576
23128
  {
22577
23129
  const tx = ex + dx * 0.38, tz = ez + dz * 0.38;
22578
23130
  let lv = true;
@@ -22592,7 +23144,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22592
23144
  }
22593
23145
  }
22594
23146
  }
22595
- Object.assign(K, { slabs });
23147
+ const defined = { slabs };
23148
+ Object.assign(K, defined);
22596
23149
  }
22597
23150
  function installRoofTiles(K, shared2) {
22598
23151
  const { UV_SCALE, _Y, _h2, _q, accFor, cursor, put, rgbOf, structurePiece } = K;
@@ -22723,7 +23276,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22723
23276
  }
22724
23277
  return m ? structurePiece(m.id) : null;
22725
23278
  }
22726
- Object.assign(K, { R_STYLE, tileRelief, ridge, pieceOfPane });
23279
+ const defined = { R_STYLE, tileRelief, ridge, pieceOfPane };
23280
+ Object.assign(K, defined);
22727
23281
  }
22728
23282
  function installRoofRect(K, shared2) {
22729
23283
  const { R_STYLE, bx, cursor, pieceOfPane, polyFace, ridge, tileRelief } = K;
@@ -22767,7 +23321,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22767
23321
  }
22768
23322
  const rm = alongX ? dz / 2 : dx / 2;
22769
23323
  {
22770
- const rr = shared2.ctx.roofRects[shared2.ctx.roofRects.length - 1];
23324
+ const roofRects = shared2.ctx.roofRects, rr = roofRects[roofRects.length - 1];
22771
23325
  if (rr && !rr.yb) Object.assign(rr, { yb, tp, gable: !!gable, alongX, exterior: [x0, z0, x1, z1], rm });
22772
23326
  }
22773
23327
  if (gable) {
@@ -22804,7 +23358,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22804
23358
  }
22805
23359
  }
22806
23360
  }
22807
- Object.assign(K, { roofRect });
23361
+ const defined = { roofRect };
23362
+ Object.assign(K, defined);
22808
23363
  }
22809
23364
  function installMirrors(K, shared2) {
22810
23365
  const { DOC, THREE, Reflector, MIRRORS, Y0, _Y, roomAt } = K;
@@ -22813,9 +23368,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22813
23368
  function mirrorEnv() {
22814
23369
  if (shared2.mirrorEnv) return shared2.mirrorEnv;
22815
23370
  const mk = (f) => {
23371
+ if (!DOC) throw new Error("game-floorplan-three: the mirrors need a document (options.document)");
22816
23372
  const c = DOC.createElement("canvas");
22817
23373
  c.width = c.height = 64;
22818
23374
  const g = c.getContext("2d");
23375
+ if (!g) throw new Error("game-floorplan-three: no 2d canvas context");
22819
23376
  f(g);
22820
23377
  return c;
22821
23378
  };
@@ -22874,7 +23431,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22874
23431
  B.N.push(v.x, v.y, v.z);
22875
23432
  B.U.push(ua.getX(i), ua.getY(i));
22876
23433
  }
22877
- for (const k of geo.index.array) B.I.push(B.nv + k);
23434
+ for (const k of geo.index?.array ?? []) B.I.push(B.nv + k);
22878
23435
  B.nv += pa.count;
22879
23436
  geo.dispose();
22880
23437
  }
@@ -22952,7 +23509,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22952
23509
  m.fake.visible = !on;
22953
23510
  }
22954
23511
  }
22955
- Object.assign(K, { mirrorEnv, newMirrorState, assembleMirrors, floorAtY, chooseMirror });
23512
+ const defined = { mirrorEnv, newMirrorState, assembleMirrors, floorAtY, chooseMirror };
23513
+ Object.assign(K, defined);
22956
23514
  }
22957
23515
  function installCars(K, shared2) {
22958
23516
  const { THREE, FLEET, _Y } = K;
@@ -22963,13 +23521,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22963
23521
  high: ["electric_hatch", "hybrid_suv", "midsize_suv", "v8_coupe", "large_suv", "midsize_pickup", "crossover_pickup", "fastback_sedan"]
22964
23522
  }, K.cfg.carKinds);
22965
23523
  const CAR_CACHE = /* @__PURE__ */ new Map();
22966
- function materialSignature(m) {
23524
+ function materialSignature(material) {
23525
+ const m = material;
22967
23526
  const f = (v) => v == null ? "" : typeof v === "number" ? v.toFixed(3) : v.isColor ? v.getHexString() : v.uuid || String(v);
22968
23527
  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("|");
22969
23528
  }
22970
23529
  const BUCKETS = /* @__PURE__ */ new Map();
22971
- function bucketMaterial(m) {
22972
- if (m.type !== "MeshStandardMaterial" || m.map || m.alphaTest || m.vertexColors || !m.color) return null;
23530
+ function bucketMaterial(material) {
23531
+ if (material.type !== "MeshStandardMaterial") return null;
23532
+ const m = material;
23533
+ if (m.map || m.alphaTest || m.vertexColors || !m.color) return null;
22973
23534
  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 : "");
22974
23535
  let b = BUCKETS.get(sig);
22975
23536
  if (!b) {
@@ -22981,7 +23542,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22981
23542
  }
22982
23543
  function carModel(k, seed) {
22983
23544
  const kc = k + "|" + shared2.quality + "|" + (seed || 0);
22984
- if (CAR_CACHE.has(kc)) return CAR_CACHE.get(kc);
23545
+ if (CAR_CACHE.has(kc)) return CAR_CACHE.get(kc) ?? null;
22985
23546
  if (!FLEET) return null;
22986
23547
  let res = null;
22987
23548
  try {
@@ -22989,8 +23550,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22989
23550
  c.root.updateMatrixWorld(true);
22990
23551
  const inv = new THREE.Matrix4();
22991
23552
  const byMaterial = /* @__PURE__ */ new Map(), tmp = new THREE.Matrix4(), v = new THREE.Vector3(), nm = new THREE.Matrix3(), bb = new THREE.Box3();
22992
- c.g.traverse((o) => {
22993
- if (!o.isMesh || o.isInstancedMesh || o.isSkinnedMesh || !o.geometry || !o.geometry.attributes.position) return;
23553
+ c.g.traverse((node) => {
23554
+ if (!isMesh(node)) return;
23555
+ const o = node;
23556
+ if (o.isInstancedMesh || o.isSkinnedMesh || !o.geometry || !o.geometry.attributes.position) return;
22994
23557
  for (let p = o; p; p = p.parent) if (p.visible === false) return;
22995
23558
  const mats = Array.isArray(o.material) ? o.material : [o.material];
22996
23559
  let geo = o.geometry;
@@ -23004,7 +23567,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23004
23567
  const pa = geo.attributes.position, na = geo.attributes.normal, ua = geo.attributes.uv, total = pa.count;
23005
23568
  const grs = Array.isArray(o.material) && o.geometry.groups.length ? o.geometry.groups : [{ start: 0, count: total, materialIndex: 0 }];
23006
23569
  for (const gr of grs) {
23007
- const m = mats[gr.materialIndex] || mats[0];
23570
+ const m = (gr.materialIndex != null ? mats[gr.materialIndex] : void 0) || mats[0];
23008
23571
  if (!m) continue;
23009
23572
  const a0 = Math.min(gr.start, total), n0 = Math.min(gr.count, total - a0) - Math.min(gr.count, total - a0) % 3;
23010
23573
  if (n0 < 3) continue;
@@ -23105,7 +23668,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23105
23668
  return g;
23106
23669
  }
23107
23670
  function assembleCars(groups) {
23108
- if (shared2.quality === "game") return assembleMergedCars(groups);
23671
+ if (shared2.quality === "game") {
23672
+ assembleMergedCars(groups);
23673
+ return;
23674
+ }
23109
23675
  for (const C of CARS) {
23110
23676
  const g = carGroup(C.k, C.w, C.d, C.seed);
23111
23677
  if (!g) continue;
@@ -23156,7 +23722,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23156
23722
  (groups[B.parent] || (groups[B.parent] = new THREE.Group())).add(m);
23157
23723
  }
23158
23724
  }
23159
- Object.assign(K, { CARS, CAR_BY_STYLE, CAR_CACHE, materialSignature, BUCKETS, bucketMaterial, carModel, carGroup, assembleCars, assembleMergedCars });
23725
+ const defined = { CARS, CAR_BY_STYLE, CAR_CACHE, materialSignature, BUCKETS, bucketMaterial, carModel, carGroup, assembleCars, assembleMergedCars };
23726
+ Object.assign(K, defined);
23160
23727
  }
23161
23728
  function installHouseBuilding(K, shared2) {
23162
23729
  const { bx, cursor } = K;
@@ -23210,12 +23777,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23210
23777
  bx("plaster", Math.min(hall[0] - 3, color2[0]), ytop, Math.min(un[1] ? unitBox(un[1])[1] : 0, el[1]), Math.max(color2[2], un0[2]), ytop + 0.2, Math.max(un0[3], un[1] ? unitBox(un[1])[3] : 0), 11841704);
23211
23778
  shared2.ctx.limits = { x0: Math.min(hall[0] - 3, color2[0]), z0: Math.min(el[1], un[1] ? unitBox(un[1])[1] : 0), x1: Math.max(color2[2], un0[2]), z1: Math.max(un0[3], un[1] ? unitBox(un[1])[3] : 0) };
23212
23779
  }
23213
- Object.assign(K, { building });
23780
+ const defined = { building };
23781
+ Object.assign(K, defined);
23214
23782
  }
23215
23783
  function installUtilitiesWater(K, shared2) {
23216
23784
  const { THREE, _Y, _q, cursor, cylBase, part, pieceRecord, put } = K;
23217
23785
  function createWater(r, state) {
23218
- const H = r.utilities.plumbing, cap = H ? +H.capacityL || 0 : 0, ls = { dry: [], full: [] }, points = {}, itemPoint = {};
23786
+ const H = r.utilities?.plumbing, cap = H ? +H.capacityL || 0 : 0, ls = { dry: [], full: [] }, points = {}, itemPoint = {};
23219
23787
  if (H) for (const p of H.points) {
23220
23788
  points[p.id] = p;
23221
23789
  itemPoint[p.item] = p.id;
@@ -23304,14 +23872,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23304
23872
  }
23305
23873
  const _v3 = new THREE.Vector3();
23306
23874
  function waterPipes() {
23307
- const H = shared2.ctx.r.utilities.plumbing;
23875
+ const H = shared2.ctx.r.utilities?.plumbing;
23308
23876
  if (!H || !H.visibleRuns) return;
23309
23877
  const nA = shared2.ctx.r.floors.length;
23310
23878
  const groupOf = (c) => c && c.floor >= 0 ? "f" + Math.min(c.floor, nA - 1) : "lot", xyz = (p) => [p[0], p[2], p[1]];
23311
23879
  for (const tr of H.visibleRuns) {
23312
23880
  const pts = tr.points.map(xyz), d = tr.diameter || 0.025;
23313
23881
  if (tr.exposed === "wall") {
23314
- const pt = H.points.find((p) => p.run === tr.id), com = shared2.ctx.roomById[tr.to], g2 = groupOf(com || pt && { floor: pt.floor });
23882
+ const pt = H.points.find((p) => p.run === tr.id), com = tr.to != null ? shared2.ctx.roomById[tr.to] : void 0, g2 = groupOf(com || pt && { floor: pt.floor });
23315
23883
  part("wall_pipe", [0, 0, 0], () => {
23316
23884
  for (let i = 0; i + 1 < pts.length; i++) pipe(pts[i], pts[i + 1], d, PIPE_COLOR);
23317
23885
  for (const p of pts) cylBase("plain", p[0], p[1] - d, p[2], d * 0.7, d * 2, PIPE_COLOR);
@@ -23333,16 +23901,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23333
23901
  cursor.pc = null;
23334
23902
  }
23335
23903
  }
23336
- Object.assign(K, { createWater, PIPE_COLOR, pipe, _v3, waterPipes });
23904
+ const defined = { createWater, PIPE_COLOR, pipe, _v3, waterPipes };
23905
+ Object.assign(K, defined);
23337
23906
  }
23338
23907
  function installUtilitiesElectrical(K, shared2) {
23339
23908
  const { _Y, _q, _v3, bx, cursor, cylBase, pieceRecord, put } = K;
23340
23909
  const sh = (...a) => K.sh(...a);
23341
23910
  function electricalStructure() {
23342
- const E = shared2.ctx.r.utilities.electrical;
23911
+ const R = shared2.ctx.r, E = R.utilities?.electrical;
23343
23912
  shared2.ctx.electricalInfo = null;
23344
23913
  if (!E) return;
23345
- const R = shared2.ctx.r, nA = R.floors.length, lotGroup = R.lot ? "lot" : "f0", concreteColor = 11973547, iron = 4869200, wireRun = 1842206, info = { pole: null, meter: null, panel: null, conduits: [], outlets: [], switches: [], circuits: E.circuits || [], exposed: !!E.exposed };
23914
+ 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 };
23346
23915
  const en22 = E.serviceEntrance, KV = shared2.ctx.iv ? shared2.ctx.iv.plane : null;
23347
23916
  const wireL = (a, b, r_ = 8e-3) => {
23348
23917
  const L = Math.hypot(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
@@ -23447,7 +24016,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23447
24016
  _q.setFromUnitVectors(_Y, _v3.set(dx / L, dy / L, dz / L));
23448
24017
  put("plain", "cyl", (a[0] + b[0]) / 2, (a[1] + b[1]) / 2, (a[2] + b[2]) / 2, _q, diameter, L, diameter, color2);
23449
24018
  }
23450
- Object.assign(K, { electricalStructure, pipe2 });
24019
+ const defined = { electricalStructure, pipe2 };
24020
+ Object.assign(K, defined);
23451
24021
  }
23452
24022
  function installHouseBaseboard(K, shared2) {
23453
24023
  const { Y0, bx, cursor, sideOf } = K;
@@ -23483,7 +24053,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23483
24053
  strip(W, y0, y0 + 0.045, 0, W, "sidewalk", cal);
23484
24054
  }
23485
24055
  }
23486
- Object.assign(K, { baseboardAndSidewalk });
24056
+ const defined = { baseboardAndSidewalk };
24057
+ Object.assign(K, defined);
23487
24058
  }
23488
24059
  function installUtilitiesSolar(K, shared2) {
23489
24060
  const { Y0, boxC, bx, cursor, cylBase } = K;
@@ -23496,6 +24067,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23496
24067
  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);
23497
24068
  continue;
23498
24069
  }
24070
+ if (!rr.exterior || rr.tp == null || rr.rm == null) continue;
23499
24071
  const [x0, z0, x1, z1] = rr.exterior;
23500
24072
  if (u < x0 || u > x1 || v < z0 || v > z1) continue;
23501
24073
  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);
@@ -23504,7 +24076,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23504
24076
  return y;
23505
24077
  }
23506
24078
  function solar() {
23507
- const R = shared2.ctx.r, S = R.utilities.solar;
24079
+ const R = shared2.ctx.r, S = R.utilities?.solar;
23508
24080
  shared2.ctx.solarInfo = null;
23509
24081
  if (!S || !S.panels || !S.panels.length) return;
23510
24082
  cursor.group = "roof";
@@ -23547,13 +24119,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23547
24119
  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);
23548
24120
  bx("emissive", iv.u - 0.03, y0 - 0.12, iv.v + fa0, iv.u + 0.03, y0 - 0.09, iv.v + fa1, 6479994);
23549
24121
  }
23550
- const top = Math.max(...(shared2.ctx.roofRects || []).filter((t2) => t2.yb != null).map((t2) => t2.yb), Y0(fa) + 2.8);
24122
+ const top = Math.max(...(shared2.ctx.roofRects || []).flatMap((t2) => t2.yb != null ? [t2.yb] : []), Y0(fa) + 2.8);
23551
24123
  cylBase("plain", iv.u, y0 + h / 2, iv.v, 0.016, Math.max(0.2, top - 0.2 - (y0 + h / 2)), 15262936);
23552
24124
  info.inverter = { id: iv.id, pos: [iv.u, y0, iv.v], side: iv.side, link: iv.link };
23553
24125
  }
23554
24126
  shared2.ctx.solarInfo = info;
23555
24127
  }
23556
- Object.assign(K, { roofHeightAt, solar });
24128
+ const defined = { roofHeightAt, solar };
24129
+ Object.assign(K, defined);
23557
24130
  }
23558
24131
  function installHouseOutbuildings(K, shared2) {
23559
24132
  const { t, bx, cursor, floorColor } = K;
@@ -23566,7 +24139,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23566
24139
  counts.set(w.floor, i + 1);
23567
24140
  return w.id ? w : Object.assign({}, w, { id: `wall_${w.floor}_${i}` });
23568
24141
  }) });
23569
- const E = (r.outbuildings || []).filter((e) => e && e.walls && e.walls.length && e.interior && e.interior.length);
24142
+ const E = (r.outbuildings || []).filter((e) => !!(e && e.walls && e.walls.length && e.interior && e.interior.length));
23570
24143
  if (!E.length) return r;
23571
24144
  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");
23572
24145
  for (const e of E) {
@@ -23580,7 +24153,22 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23580
24153
  const alongU = p.axis === "u", below = p.pos < (alongU ? cz : cx);
23581
24154
  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 });
23582
24155
  }
23583
- 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 });
24156
+ for (const j of e.windows || []) windows.push({
24157
+ id: j.id,
24158
+ floor: 0,
24159
+ u: j.u,
24160
+ v: j.v,
24161
+ axis: j.axis,
24162
+ pos: j.pos,
24163
+ at: j.at,
24164
+ width: j.width,
24165
+ y0: j.y0 ?? 1,
24166
+ y1: j.y1 ?? 2,
24167
+ /* the structure always gives a window its sill and head (1.0, 2.0) */
24168
+ room: e.id,
24169
+ side: j.side,
24170
+ outbuilding: e.id
24171
+ });
23584
24172
  (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" }));
23585
24173
  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 });
23586
24174
  }
@@ -23601,7 +24189,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23601
24189
  }
23602
24190
  }
23603
24191
  }
23604
- Object.assign(K, { OUTBUILDING_USE, applyOutbuildings, outbuildings });
24192
+ const defined = { OUTBUILDING_USE, applyOutbuildings, outbuildings };
24193
+ Object.assign(K, defined);
23605
24194
  }
23606
24195
  function installFurnitureApi(K, _shared) {
23607
24196
  const { _e, _h2, _q, boxC, cursor, macroGround, polyFace, put } = K;
@@ -23664,7 +24253,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23664
24253
  return { b: (mat, x, y, z, w, h, d, color2, ry, rx, rz) => A.box(M, mat, x, y0 + y, z, w, h, d, color2, ry || 0, rx || 0, rz || 0), c: (mat, x, y, z, r, h, color2, rx, rz, seg2) => A.cylinder(M, mat, x, y0 + y, z, r, h, color2, rx || 0, rz || 0, seg2), rnd: rngOf(M), wood: paletteColor(M, "wood", 8016948), met: paletteColor(M, "metal", 10133154) };
23665
24254
  }
23666
24255
  const PE = Math.PI / 2;
23667
- Object.assign(K, { MATERIAL_MAP: MATERIAL_MAP2, mm, LIGHTS, makeApi, sh, paletteColor, rngOf, kk, PE });
24256
+ const defined = { MATERIAL_MAP: MATERIAL_MAP2, mm, LIGHTS, makeApi, sh, paletteColor, rngOf, kk, PE };
24257
+ Object.assign(K, defined);
23668
24258
  }
23669
24259
  function installFurnitureBuilders(K, _shared) {
23670
24260
  const { PE, _q, kit2, kk, paletteColor, put, rngOf, sh } = K;
@@ -23790,7 +24380,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23790
24380
  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);
23791
24381
  },
23792
24382
  wardrobe(M, A) {
23793
- 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));
24383
+ 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));
23794
24384
  lb("wood", 0, 0.06, 0, w, h - 0.06, d, wood);
23795
24385
  lb("wood", 0, h, 0, w + 0.04, 0.04, d + 0.04, sh(wood, 0.8));
23796
24386
  lb("wood", 0, 0, 0, w - 0.04, 0.06, d - 0.04, sh(wood, 0.4));
@@ -24182,7 +24772,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24182
24772
  lb("metal", 0, h - 0.04, d / 2, w, 0.03, 0.03, 3815994);
24183
24773
  }
24184
24774
  };
24185
- Object.assign(K, { FURNITURE });
24775
+ const defined = { FURNITURE };
24776
+ Object.assign(K, defined);
24186
24777
  }
24187
24778
  function installFurnitureTypeTable(K, _shared) {
24188
24779
  const { FURNITURE, kk, paletteColor } = K;
@@ -24190,7 +24781,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24190
24781
  function typeTable(props) {
24191
24782
  const B = props.builders, T2 = {};
24192
24783
  const mv = (type, id) => {
24193
- if (B[id || type]) T2[type] = { f: B[id || type], source: "props3d" };
24784
+ const f = B[id || type];
24785
+ if (f) T2[type] = { f, source: "props3d" };
24194
24786
  };
24195
24787
  const mine = (type, f, source = "game") => {
24196
24788
  T2[type] = { f, source };
@@ -24329,7 +24921,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24329
24921
  extraTypes(T2, props);
24330
24922
  return T2;
24331
24923
  }
24332
- Object.assign(K, { typeTable });
24924
+ const defined = { typeTable };
24925
+ Object.assign(K, defined);
24333
24926
  }
24334
24927
  function installFurnitureTaps(K, shared2) {
24335
24928
  shared2.tapCount = 0;
@@ -24391,7 +24984,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24391
24984
  }, { id: id + "_a", target: id, hidden: true, fluid: "water" });
24392
24985
  return id;
24393
24986
  }
24394
- Object.assign(K, { counterTap, wallTap });
24987
+ const defined = { counterTap, wallTap };
24988
+ Object.assign(K, defined);
24395
24989
  }
24396
24990
  function installFurnitureFixtures(K, _shared) {
24397
24991
  const seedKey = (id) => K.seedKey(id);
@@ -24500,7 +25094,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24500
25094
  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;
24501
25095
  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;
24502
25096
  K2.e("plant", cx + dx, cy + dy + r * 0.5, cz + dz, r, alt, sh(green2, f));
24503
- if (o.flower && rnd() < o.flower) {
25097
+ if (o.flower && o.flowers && rnd() < o.flower) {
24504
25098
  const fa = rnd() * 6.283;
24505
25099
  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]);
24506
25100
  }
@@ -24613,7 +25207,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24613
25207
  else blobs(K2, x, bh - 0.05, z, 0.24 + rnd() * 0.08, 6, green2, rnd, { flatten: true, flower: tp === "flower" ? 0.9 : 0.25, flowers: FLOWERS.slice(i % 3, i % 3 + 3) });
24614
25208
  }
24615
25209
  }
24616
- Object.assign(K, { GREENS: GREENS2, FLOWERS, blobs, potModel, arcLeaf, tuft, palm_tree, treeModel, shrubModel, potPlant, tablePot, planterModel });
25210
+ const defined = { GREENS: GREENS2, FLOWERS, blobs, potModel, arcLeaf, tuft, palm_tree, treeModel, shrubModel, potPlant, tablePot, planterModel };
25211
+ Object.assign(K, defined);
24617
25212
  }
24618
25213
  function installFurnitureYard(K, shared2) {
24619
25214
  const seedKey = (id) => K.seedKey(id);
@@ -24767,7 +25362,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24767
25362
  };
24768
25363
  FURNITURE.mailbox = function(M, A) {
24769
25364
  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");
24770
- if (M.pole !== false && !(M.y > 0)) {
25365
+ if (M.pole !== false && !(M.y != null && M.y > 0)) {
24771
25366
  K2.b("plain", 0, 0, -d / 2 - 0.1, 0.12, y, 0.12, 12104874);
24772
25367
  }
24773
25368
  K2.b("metal", 0, y, 0, w, h * 0.78, d, pc);
@@ -24787,7 +25382,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24787
25382
  );
24788
25383
  K2.b("plain", 0, y + h * 0.62, d / 2 + 4e-3, 0.08, 0.05, 4e-3, 15921386);
24789
25384
  };
24790
- Object.assign(K, { CLOTHES_COLORS, strip, garment: garment2 });
25385
+ const defined = { CLOTHES_COLORS, strip, garment: garment2 };
25386
+ Object.assign(K, defined);
24791
25387
  }
24792
25388
  function installFurnitureExtraTypes(K, _shared) {
24793
25389
  const seedKey = (id) => K.seedKey(id);
@@ -24845,7 +25441,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24845
25441
  tuft(K2, 0, 0, 0, Math.max(0.2, (M.w || 0.4) / 2), 16, 5212738, rnd);
24846
25442
  });
24847
25443
  }
24848
- Object.assign(K, { extraTypes });
25444
+ const defined = { extraTypes };
25445
+ Object.assign(K, defined);
24849
25446
  }
24850
25447
  function installFurniturePlaceItems(K, shared2) {
24851
25448
  const { THREE, Y0, _col, boxC, colorOf, cursor, decorLights, makeApi, structurePiece } = K;
@@ -24865,8 +25462,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24865
25462
  if (m.type === "stairs") continue;
24866
25463
  const exterior = m.outdoor || m.floor < 0, f = exterior ? -1 : Math.min(m.floor, R.floors.length - 1);
24867
25464
  cursor.group = exterior ? "lot" : "f" + f;
24868
- const com = shared2.ctx.roomById[m.room], base = exterior ? 0 : Y0(f);
24869
- const M = { x: m.x, z: m.z, ry: m.ry || 0, w: m.w, d: m.d, h: m.h, y: m.y || 0, base, floor: exterior ? -1 : f, palette: shared2.ctx.colors, color: m.category === "ground_cover" ? void 0 : colorOf(m.color) != null ? colorOf(m.color) : void 0, seed: m.id, room: m.room, typeWith: com ? com.type : null, ceiling: com ? com.ceiling : 2.9, on: shared2.ctx.night, light: shared2.ctx.night, lit: shared2.ctx.night, open: !!m.doorOpen, overhead: m.overhead, assembly: m.assembly, hose: m.hose };
25465
+ const com = m.room != null ? shared2.ctx.roomById[m.room] : void 0, base = exterior ? 0 : Y0(f);
25466
+ const M = { x: m.x, z: m.z, ry: m.ry || 0, w: m.w, d: m.d, h: m.h, y: m.y || 0, base, floor: exterior ? -1 : f, palette: shared2.ctx.colors, color: m.category === "ground_cover" ? void 0 : colorOf(m.color) ?? void 0, seed: m.id, room: m.room, typeWith: com ? com.type : null, ceiling: com ? com.ceiling : 2.9, on: shared2.ctx.night, light: shared2.ctx.night, lit: shared2.ctx.night, open: !!m.doorOpen, overhead: m.overhead, assembly: m.assembly, hose: m.hose };
24870
25467
  if (m.category === "ground_cover" && m.polygon) {
24871
25468
  const xs = m.polygon.map((p) => p[0]), zs = m.polygon.map((p) => p[1]);
24872
25469
  M.x = (Math.min(...xs) + Math.max(...xs)) / 2;
@@ -24943,7 +25540,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24943
25540
  boxC("plain", m.x, M.base + (m.y || 0) + h / 2, m.z, m.w, h, m.d, color2, 0, m.ry || 0, 0);
24944
25541
  shared2.ctx.labels.push({ pos: new THREE.Vector3(m.x, M.base + (m.y || 0) + h + 0.15, m.z), text: m.type, group, type: "no_model" });
24945
25542
  }
24946
- Object.assign(K, { houseItems, waterTankOfHouse, hashColor, labeledBox });
25543
+ const defined = { houseItems, waterTankOfHouse, hashColor, labeledBox };
25544
+ Object.assign(K, defined);
24947
25545
  }
24948
25546
  function installVegetationBridge(K, shared2) {
24949
25547
  const seedKey = (id) => K.seedKey(id);
@@ -24976,7 +25574,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24976
25574
  const ids = VEG_MAP[m.type], can2 = VEG_PLANTER[m.type];
24977
25575
  if (!ids && !can2) return false;
24978
25576
  const rnd = rngString(SEED() + "|" + seedKey(m.id) + "|veg"), pick2 = (l) => l[Math.min(l.length - 1, rnd() * l.length | 0)], ok = (id) => {
24979
- if (V.ok.has(id)) return V.ok.get(id);
25577
+ if (V.ok.has(id)) return V.ok.get(id) === true;
24980
25578
  let r = true;
24981
25579
  try {
24982
25580
  V.S.toSpec(id);
@@ -25022,7 +25620,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25022
25620
  obj.position.y = G.y;
25023
25621
  obj.name = "vegetation";
25024
25622
  obj.traverse((o) => {
25025
- if (o.isMesh) {
25623
+ if (isMesh(o)) {
25026
25624
  o.castShadow = true;
25027
25625
  o.receiveShadow = true;
25028
25626
  o.name = "veg/" + o.name;
@@ -25037,7 +25635,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25037
25635
  }
25038
25636
  shared2.ctx.vegInfo = { plants: pl, triangles: tri, colliders: col, lodCounts: lod, materials: mats };
25039
25637
  }
25040
- Object.assign(K, { VEG_POT, VEG_CACTUS, VEG_MAP, VEG_PLANTER, vegItem, assembleVegetation });
25638
+ const defined = { VEG_POT, VEG_CACTUS, VEG_MAP, VEG_PLANTER, vegItem, assembleVegetation };
25639
+ Object.assign(K, defined);
25041
25640
  }
25042
25641
  function installInteractionState(K, shared2) {
25043
25642
  const { THREE, cfg, colliderChanged, invalidateShadow, invalidate, UV_SCALE, applyPart, texture } = K;
@@ -25103,12 +25702,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25103
25702
  shared2.inter.msg = { text, until: performance.now() + MESSAGE_MS };
25104
25703
  if (cfg.onMessage) cfg.onMessage(text);
25105
25704
  };
25106
- function definePiece(name, def) {
25705
+ const I = () => shared2.inter;
25706
+ function definePiece(name, definition) {
25707
+ const def = definition;
25107
25708
  def.name = name;
25108
25709
  def.meshes = [];
25109
25710
  def.t = def.target = shared2.partState.has(name) ? shared2.partState.get(name) : def.t0 || 0;
25110
- shared2.inter.defs.set(name, def);
25111
- shared2.inter.pieces.push(def);
25711
+ I().defs.set(name, def);
25712
+ I().pieces.push(def);
25112
25713
  return def;
25113
25714
  }
25114
25715
  const localOf = (M, lx, lz) => {
@@ -25120,17 +25721,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25120
25721
  return true;
25121
25722
  }
25122
25723
  function assembleInteractive(gs) {
25123
- for (const [name, def] of shared2.inter.defs) {
25724
+ const inter = I();
25725
+ for (const [name, def] of inter.defs) {
25124
25726
  const g = gs[name];
25125
25727
  if (!g) continue;
25126
25728
  delete gs[name];
25127
25729
  const outer = new THREE.Group();
25128
- outer.position.set(...def.pivot);
25730
+ outer.position.fromArray(def.pivot);
25129
25731
  outer.rotation.y = def.ry || 0;
25130
25732
  outer.updateMatrix();
25131
- const inv = new THREE.Matrix4().compose(new THREE.Vector3(...def.pivot), new THREE.Quaternion().setFromAxisAngle(_EY, def.ry || 0), _UM3).invert();
25733
+ const inv = new THREE.Matrix4().compose(new THREE.Vector3().fromArray(def.pivot), new THREE.Quaternion().setFromAxisAngle(_EY, def.ry || 0), _UM3).invert();
25132
25734
  g.traverse((o) => {
25133
- if (o.isMesh) {
25735
+ if (isMesh(o)) {
25134
25736
  o.geometry.applyMatrix4(inv);
25135
25737
  o.userData.piece = def;
25136
25738
  def.meshes.push(o);
@@ -25142,13 +25744,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25142
25744
  const parent = def.leaf ? def.leaf.gs[def.k] : gs[def.parent] || (gs[def.parent] = new THREE.Group());
25143
25745
  if (parent) parent.add(outer);
25144
25746
  if (def.roomId) {
25145
- if (!shared2.inter.lights.has(def.roomId)) shared2.inter.lights.set(def.roomId, []);
25146
- shared2.inter.lights.get(def.roomId).push(def);
25747
+ let lamps = inter.lights.get(def.roomId);
25748
+ if (!lamps) inter.lights.set(def.roomId, lamps = []);
25749
+ lamps.push(def);
25147
25750
  }
25148
25751
  applyPiece(def);
25149
25752
  }
25150
- for (const roomId of shared2.inter.litRooms) applyLight(roomId);
25151
- shared2.inter.defs.forEach((d) => {
25753
+ for (const roomId of inter.litRooms) applyLight(roomId);
25754
+ inter.defs.forEach((d) => {
25152
25755
  if (d.col) d.col.off = d.t > 0.5;
25153
25756
  });
25154
25757
  }
@@ -25156,6 +25759,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25156
25759
  const n = p.inner;
25157
25760
  if (!n) return;
25158
25761
  switch (p.kind) {
25762
+ /* each kind always sets its dimensions (sgn, angle, travel, k, axis) */
25159
25763
  case "swing":
25160
25764
  n.rotation.y = p.sgn * p.t * p.angle;
25161
25765
  break;
@@ -25188,8 +25792,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25188
25792
  }
25189
25793
  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 };
25190
25794
  function animateInteractive(dt) {
25191
- if (!shared2.inter.anim.size) return;
25192
- for (const p of shared2.inter.anim) {
25795
+ const inter = I();
25796
+ if (!inter.anim.size) return;
25797
+ for (const p of inter.anim) {
25193
25798
  const step = dt / (DURATION[p.kind] || 0.5), d = p.target - p.t;
25194
25799
  p.t = Math.abs(d) <= step ? p.target : p.t + Math.sign(d) * step;
25195
25800
  applyPiece(p);
@@ -25197,7 +25802,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25197
25802
  p.col.off = p.target > 0.5;
25198
25803
  colliderChanged(p.col);
25199
25804
  }
25200
- if (p.t === p.target) shared2.inter.anim.delete(p);
25805
+ if (p.t === p.target) inter.anim.delete(p);
25201
25806
  }
25202
25807
  invalidateShadow();
25203
25808
  }
@@ -25208,7 +25813,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25208
25813
  p.col.off = p.target > 0.5;
25209
25814
  colliderChanged(p.col);
25210
25815
  }
25211
- shared2.inter.anim.add(p);
25816
+ I().anim.add(p);
25212
25817
  }
25213
25818
  const lightBase = (roomId) => roomId == null ? true : shared2.partState.has("light:" + roomId) ? !!shared2.partState.get("light:" + roomId) : !!shared2.ctx.night;
25214
25819
  const lightOn = (roomId) => {
@@ -25216,20 +25821,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25216
25821
  return S ? S.ef : lightBase(roomId);
25217
25822
  };
25218
25823
  function applyLight(roomId) {
25219
- const on = lightOn(roomId);
25220
- for (const d of shared2.inter.lights.get(roomId) || []) for (const m of d.meshes) if (m.name.endsWith("/emissive")) m.material = on ? shared2.mats.emissive : shared2.mats.off;
25221
- const sw = shared2.inter.defs.get("ix:int:" + roomId);
25824
+ const on = lightOn(roomId), inter = I(), mats = shared2.mats;
25825
+ 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;
25826
+ const sw = inter.defs.get("ix:int:" + roomId);
25222
25827
  if (sw) {
25223
25828
  sw.target = on ? 1 : 0;
25224
- if (sw.t !== sw.target) shared2.inter.anim.add(sw);
25829
+ if (sw.t !== sw.target) inter.anim.add(sw);
25225
25830
  }
25226
25831
  invalidate();
25227
25832
  }
25228
25833
  function toggleLight(roomId) {
25229
25834
  const S = shared2.ctx.iv && shared2.ctx.iv.roomStates.get(roomId);
25230
25835
  if (S) {
25231
- ivRoomLight(shared2.ctx.iv, roomId, !S.ef);
25232
- const ef = ivRoomEffective(shared2.ctx.iv, S);
25836
+ const IV = shared2.ctx.iv;
25837
+ ivRoomLight(IV, roomId, !S.ef);
25838
+ const ef = ivRoomEffective(IV, S);
25233
25839
  if (ef !== S.ef) {
25234
25840
  S.ef = ef;
25235
25841
  applyLight(roomId);
@@ -25241,9 +25847,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25241
25847
  applyLight(roomId);
25242
25848
  if (cfg.onLight) cfg.onLight(roomId, lightOn(roomId));
25243
25849
  }
25244
- Object.assign(K, { newInteractiveState, MESSAGE_MS, createInteractiveMaterials, _EY, _UM3, hudMessage, definePiece, localOf, visibleChain, assembleInteractive, applyPiece, DURATION, animateInteractive, togglePiece, lightBase, lightOn, applyLight, toggleLight });
25850
+ const defined = { newInteractiveState, MESSAGE_MS, createInteractiveMaterials, _EY, _UM3, hudMessage, definePiece, localOf, visibleChain, assembleInteractive, applyPiece, DURATION, animateInteractive, togglePiece, lightBase, lightOn, applyLight, toggleLight };
25851
+ Object.assign(K, defined);
25245
25852
  }
25246
25853
  function installInteractionCollision(K, shared2) {
25854
+ const inter = () => shared2.inter;
25247
25855
  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)/;
25248
25856
  function registerCollision(m, M) {
25249
25857
  const h = m.h || 0, y = M.y || 0;
@@ -25253,7 +25861,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25253
25861
  w = Math.min(w, 0.5);
25254
25862
  d = Math.min(d, 0.5);
25255
25863
  }
25256
- shared2.inter.objs.push({ f: M.floor, cx: m.x, cz: m.z, c: Math.cos(M.ry), s: Math.sin(M.ry), hw: w / 2, hd: d / 2, type: m.type });
25864
+ 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 });
25257
25865
  }
25258
25866
  function objectDistance(o, x, z) {
25259
25867
  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;
@@ -25261,7 +25869,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25261
25869
  }
25262
25870
  function collideObject(x, z, fx, fz, floor) {
25263
25871
  const R = 0.2;
25264
- for (const o of shared2.inter.objs) {
25872
+ for (const o of inter().objs) {
25265
25873
  if (o.f !== -1 ? o.f !== floor : floor !== 0) continue;
25266
25874
  const d1 = objectDistance(o, x, z);
25267
25875
  if (d1 < R && d1 < objectDistance(o, fx, fz) - 1e-6) return true;
@@ -25281,13 +25889,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25281
25889
  const de = opt.from || [x + 1e4, z + 1e4];
25282
25890
  return collideObject(x, z, de[0], de[1], floor);
25283
25891
  }
25284
- Object.assign(K, { NO_COLLIDE, registerCollision, objectDistance, collideObject, collideAt });
25892
+ const defined = { NO_COLLIDE, registerCollision, objectDistance, collideObject, collideAt };
25893
+ Object.assign(K, defined);
25285
25894
  }
25286
25895
  function installInteractionItems(K, shared2) {
25287
25896
  const { t, LIGHTS, cursor, definePiece, localOf, registerCollision, togglePiece } = K;
25288
25897
  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)$/;
25289
25898
  const DRAWER_ITEM = /^(console_table|dresser|nightstand|vanity_table)$/;
25290
25899
  const LIGHT_TYPES = /* @__PURE__ */ new Set(["ceiling_light", "pendant", "chandelier", "track_spot", "hanging_plant"]);
25900
+ const I = () => shared2.inter;
25291
25901
  function objectName(type, drawer) {
25292
25902
  return drawer ? "drawer" : /^wardrobe/.test(type) ? "wardrobe" : /fridge|refrig|freezer/.test(type) ? "fridge" : /pantry/.test(type) ? "pantry" : "cabinet";
25293
25903
  }
@@ -25316,8 +25926,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25316
25926
  cursor.group = parent;
25317
25927
  }
25318
25928
  for (let i = n0; i < LIGHTS.length; i++) LIGHTS[i].roomId = m.room;
25319
- if (!shared2.inter.defs.has(name)) definePiece(name, { kind: "light", pivot: [0, 0, 0], ry: 0, parent, roomId: m.room });
25320
- shared2.inter.litRooms.add(m.room);
25929
+ if (!I().defs.has(name)) definePiece(name, { kind: "light", pivot: [0, 0, 0], ry: 0, parent, roomId: m.room });
25930
+ I().litRooms.add(m.room);
25321
25931
  }
25322
25932
  function curtainItem(m, M, ent, api, parent) {
25323
25933
  M.open = false;
@@ -25345,12 +25955,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25345
25955
  for (const c of body) api[c[0]](M, ...c[1]);
25346
25956
  if (!parts.length) return;
25347
25957
  const [ax, az] = localOf(M, 0, 0.2);
25348
- shared2.inter.items.push({ type: "curtain", id: m.id, floor: M.floor, anchor: [ax, M.base + (M.y || 0) + (m.h || 2) * 0.5, az], range: 2.4, angle: 1, pieces: parts, text: () => t(parts[0].target > 0.5 ? "prompt.close" : "prompt.open", { what: t("what.curtain") }), action: () => {
25349
- const al = parts[0].target > 0.5 ? 0 : 1;
25958
+ const first = parts[0];
25959
+ 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: () => {
25960
+ const al = first.target > 0.5 ? 0 : 1;
25350
25961
  for (const p of parts) {
25351
25962
  p.target = al;
25352
25963
  shared2.partState.set(p.name, al);
25353
- shared2.inter.anim.add(p);
25964
+ I().anim.add(p);
25354
25965
  }
25355
25966
  } });
25356
25967
  }
@@ -25371,7 +25982,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25371
25982
  calls.forEach((c, i) => {
25372
25983
  if (owner.has(i)) return;
25373
25984
  const a = c[1];
25374
- let x0, x1, y0, y1, ok = false, grip = 0, wide = false;
25985
+ let x0 = 0, x1 = 0, y0 = 0, y1 = 0, ok = false, grip = 0, wide = false;
25375
25986
  if (c[0] === "box") {
25376
25987
  const [mat, x, y, z, w, h, d, , ry, rx, rz] = a;
25377
25988
  if (ry || rx || rz || d > 0.05 || z + d / 2 < front - 5e-3 || w > M.w * 1.01) return;
@@ -25403,8 +26014,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25403
26014
  return;
25404
26015
  }
25405
26016
  candidate.sort((p, q) => overlap(x0, x1, q.x0, q.x1) - overlap(x0, x1, p.x0, p.x1));
25406
- owner.set(i, candidate[0]);
25407
- if (grip) candidate[0].grip = grip;
26017
+ const best = candidate[0];
26018
+ owner.set(i, best);
26019
+ if (grip) best.grip = grip;
25408
26020
  });
25409
26021
  const name = objectName(m.type, drawer), parts = [];
25410
26022
  panels.forEach((p, k) => {
@@ -25420,8 +26032,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25420
26032
  p.def = def;
25421
26033
  parts.push(def);
25422
26034
  const [ax, az] = localOf(M, cx, front + 0.08);
25423
- shared2.inter.items.push({ type: drawer ? "drawer" : "cabinet", id: m.id, floor: M.floor, anchor: [ax, M.base + (M.y || 0) + (p.y0 + p.y1) / 2, az], range: 1.6, angle: 0.4, pieces: [def], text: () => t(def.target > 0.5 ? "prompt.close" : "prompt.open", { what: t("what." + name) }), action: () => togglePiece(def) });
25424
- def.item = shared2.inter.items[shared2.inter.items.length - 1];
26035
+ 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) });
26036
+ def.item = I().items[I().items.length - 1];
25425
26037
  });
25426
26038
  calls.forEach((c, i) => {
25427
26039
  const p = owner.get(i);
@@ -25435,12 +26047,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25435
26047
  }
25436
26048
  cursor.group = parent;
25437
26049
  }
25438
- Object.assign(K, { DOOR_ITEM, DRAWER_ITEM, LIGHT_TYPES, objectName, recordApi, buildItem: buildItem2, lightItem, curtainItem, furnitureItem });
26050
+ const defined = { DOOR_ITEM, DRAWER_ITEM, LIGHT_TYPES, objectName, recordApi, buildItem: buildItem2, lightItem, curtainItem, furnitureItem };
26051
+ Object.assign(K, defined);
25439
26052
  }
25440
26053
  function installInteractionFittings(K, shared2) {
25441
26054
  const { t, EPS: EPS3, OPEN_AREA, Y0, applyPiece, bx, cursor, definePiece, gates, lightOn, roomAt, slideDirection, toggleLight, togglePiece } = K;
26055
+ const I = () => shared2.inter;
26056
+ const house = () => shared2.ctx.r;
25442
26057
  function gatesInteractive() {
25443
- const lt = shared2.ctx.r.lot;
26058
+ const lt = house().lot;
25444
26059
  if (!lt) return;
25445
26060
  const cz0 = (lt.rect[1] + lt.rect[3]) / 2;
25446
26061
  const orig = K.getBx(), gs = lt.gates, opening = gs.map((g) => g.open), reg = gs.map((g) => {
@@ -25460,9 +26075,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25460
26075
  return;
25461
26076
  }
25462
26077
  }
25463
- return orig(mat, x0, y0, z0, x1, y1, z1, color2);
26078
+ orig(mat, x0, y0, z0, x1, y1, z1, color2);
25464
26079
  });
25465
- const n0 = shared2.ctx.colliders.length;
26080
+ const colliders = shared2.ctx.colliders, n0 = colliders.length;
25466
26081
  try {
25467
26082
  gs.forEach((g) => {
25468
26083
  g.open = false;
@@ -25474,7 +26089,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25474
26089
  g.open = opening[i];
25475
26090
  });
25476
26091
  }
25477
- const cols = shared2.ctx.colliders.slice(n0), cz = (lt.rect[1] + lt.rect[3]) / 2, cu = (lt.rect[0] + lt.rect[2]) / 2;
26092
+ const cols = colliders.slice(n0), cz = (lt.rect[1] + lt.rect[3]) / 2, cu = (lt.rect[0] + lt.rect[2]) / 2;
25478
26093
  reg.forEach((r, i) => {
25479
26094
  const g = r.g;
25480
26095
  if (!isFinite(r.x0)) return;
@@ -25483,25 +26098,25 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25483
26098
  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 }));
25484
26099
  if (p.col) p.col.off = p.target > 0.5;
25485
26100
  const text = () => t(p.target > 0.5 ? "prompt.close" : "prompt.open", { what: t(ped ? "what.pedestrianGate" : "what.garageGate") });
25486
- shared2.inter.items.push({ type: "gate", id: g.id, floor: -1, anchor: [g.u, 1, g.v + sd * 0.4], range: 2.8, angle: 0.9, pieces: [p], text, action: () => togglePiece(p), noWall: true });
26101
+ 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 });
25487
26102
  });
25488
26103
  }
25489
26104
  function mailboxInteractive() {
25490
- for (const m of shared2.ctx.r.items) {
26105
+ for (const m of house().items) {
25491
26106
  if (m.type !== "mailbox") continue;
25492
26107
  const g = shared2.ctx.parts && shared2.ctx.parts["mailbox_" + m.id];
25493
26108
  if (!g) continue;
25494
26109
  const name = "ix:correio:" + m.id, def = definePiece(name, { kind: "part", pivot: [0, 0, 0], ry: 0, parent: "lot" });
25495
26110
  def.inner = g;
25496
26111
  const fx = Math.sin(m.ry || 0), fz = Math.cos(m.ry || 0), ay = (m.y || 1) + (m.h || 0.3) * 0.4;
25497
- shared2.inter.items.push({ type: "mailbox", id: m.id, floor: -1, anchor: [m.x + fx * 0.2, ay, m.z + fz * 0.2], range: 2.2, angle: 0.7, pieces: [def], text: () => t(def.target > 0.5 ? "prompt.close" : "prompt.open", { what: t("what.mailbox") }), action: () => togglePiece(def), noWall: true });
26112
+ 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 });
25498
26113
  applyPiece(def);
25499
26114
  }
25500
26115
  }
25501
26116
  function placeSwitches() {
25502
- const R = shared2.ctx.r, used = /* @__PURE__ */ new Set();
26117
+ const R = house(), used = /* @__PURE__ */ new Set();
25503
26118
  for (const c of R.rooms) {
25504
- if (c.type === "void" || OPEN_AREA(c) || !shared2.inter.litRooms.has(c.id) || used.has(c.id) || shared2.ctx.iv && shared2.ctx.iv.switchRooms.has(c.id)) continue;
26119
+ if (c.type === "void" || OPEN_AREA(c) || !I().litRooms.has(c.id) || used.has(c.id) || shared2.ctx.iv && shared2.ctx.iv.switchRooms.has(c.id)) continue;
25505
26120
  const doors = R.doors.filter((p) => p.floor === c.floor && (p.a === c.id || p.b === c.id));
25506
26121
  doors.sort((p, q) => ((q.exterior ? 1 : 0) - (p.exterior ? 1 : 0)) * (c.type === "living" ? 1 : -1));
25507
26122
  for (const p of doors) if (putSwitch(c, p)) {
@@ -25511,11 +26126,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25511
26126
  }
25512
26127
  }
25513
26128
  function putSwitch(c, p) {
25514
- const R = shared2.ctx.r, f = p.floor, alongU = p.axis === "u", L = p.pos, a = p.at - p.width / 2, b = p.at + p.width / 2;
26129
+ 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;
25515
26130
  const wref = R.walls.find((w) => w.floor === f && w.axis === p.axis && Math.abs((alongU ? w.v0 : w.u0) - L) < EPS3), th = wref ? wref.thickness || 0.15 : 0.15;
25516
26131
  const inside2 = (sd2) => {
25517
26132
  const cc = roomAt(f, alongU ? p.at : L + sd2 * 0.4, alongU ? L + sd2 * 0.4 : p.at);
25518
- return cc && cc.id === c.id;
26133
+ return !!cc && cc.id === c.id;
25519
26134
  };
25520
26135
  const sd = inside2(1) ? 1 : inside2(-1) ? -1 : 0;
25521
26136
  if (!sd) return false;
@@ -25538,17 +26153,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25538
26153
  const piece2 = definePiece("ix:int:" + roomId, { kind: "light_switch", pivot: pv, ry: 0, parent: "f" + f, axis: alongU ? "x" : "z", sgn: alongU ? sd : -sd, t0: lightOn(roomId) ? 1 : 0 });
25539
26154
  piece2.t = piece2.target = lightOn(roomId) ? 1 : 0;
25540
26155
  const an = alongU ? [u, yc, face + sd * 0.12] : [face + sd * 0.12, yc, u];
25541
- shared2.inter.items.push({ type: "light_switch", id: roomId, floor: f, anchor: an, range: 1.5, angle: 0.45, pieces: [piece2], text: () => t(lightOn(roomId) ? "prompt.lightOff" : "prompt.lightOn"), action: () => toggleLight(roomId) });
26156
+ I().items.push({ type: "light_switch", id: roomId, floor: f, anchor: an, range: 1.5, angle: 0.45, pieces: [piece2], text: () => t(lightOn(roomId) ? "prompt.lightOff" : "prompt.lightOn"), action: () => toggleLight(roomId) });
25542
26157
  return true;
25543
26158
  }
25544
26159
  return false;
25545
26160
  }
25546
- Object.assign(K, { gatesInteractive, mailboxInteractive, placeSwitches, putSwitch });
26161
+ const defined = { gatesInteractive, mailboxInteractive, placeSwitches, putSwitch };
26162
+ Object.assign(K, defined);
25547
26163
  }
25548
26164
  function installInteractionDoors(K, shared2) {
25549
26165
  const { t, colliderChanged, invalidateShadow, applyPiece, hudMessage } = K;
26166
+ const leaves = () => shared2.ctx.leaves;
25550
26167
  function linkDoorLeaves() {
25551
- for (const fo of shared2.ctx.leaves) fo.handles = (fo.handleNames || []).map((n) => shared2.inter.defs.get(n)).filter(Boolean);
26168
+ const I = shared2.inter;
26169
+ for (const fo of leaves()) fo.handles = (fo.handleNames || []).map((n) => I.defs.get(n)).filter((d) => !!d);
25552
26170
  }
25553
26171
  function handleApply(fo) {
25554
26172
  for (const mc of fo.handles || []) {
@@ -25558,11 +26176,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25558
26176
  }
25559
26177
  function toggleDoor(fo) {
25560
26178
  if (fo.phase === "rattle") return;
26179
+ const col = fo.col;
25561
26180
  if (fo.phase === "handle" || fo.phase === "swing") {
25562
26181
  fo.open = !fo.open;
25563
26182
  shared2.doorState.set(fo.id, fo.open);
25564
- fo.col.off = fo.open;
25565
- colliderChanged(fo.col);
26183
+ col.off = fo.open;
26184
+ colliderChanged(col);
25566
26185
  fo.anim = true;
25567
26186
  fo.phase = "swing";
25568
26187
  return;
@@ -25576,8 +26195,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25576
26195
  }
25577
26196
  fo.open = !fo.open;
25578
26197
  shared2.doorState.set(fo.id, fo.open);
25579
- fo.col.off = fo.open;
25580
- colliderChanged(fo.col);
26198
+ col.off = fo.open;
26199
+ colliderChanged(col);
25581
26200
  fo.anim = true;
25582
26201
  shared2.ctx.animateDoorsOn = true;
25583
26202
  if (fo.handles && fo.handles.length) {
@@ -25588,7 +26207,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25588
26207
  function animateDoors(dt) {
25589
26208
  if (!shared2.ctx.animateDoorsOn) return;
25590
26209
  let active = false;
25591
- for (const fo of shared2.ctx.leaves) {
26210
+ for (const fo of leaves()) {
25592
26211
  if (!fo.phase) continue;
25593
26212
  active = true;
25594
26213
  if (fo.phase === "handle") {
@@ -25608,7 +26227,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25608
26227
  handleApply(fo);
25609
26228
  if (fo.hT <= 0) fo.phase = null;
25610
26229
  } else if (fo.phase === "rattle") {
25611
- fo.jig -= dt;
26230
+ fo.jig = (fo.jig ?? 0) - dt;
25612
26231
  fo.hT = fo.jig > 0 ? 0.55 * Math.abs(Math.sin(fo.jig * 26)) : 0;
25613
26232
  handleApply(fo);
25614
26233
  if (fo.jig <= 0) {
@@ -25622,9 +26241,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25622
26241
  invalidateShadow();
25623
26242
  }
25624
26243
  function wallBlocks(ex, ez, ax, az, floor) {
25625
- const n = shared2.ctx.wallColliders != null ? shared2.ctx.wallColliders : 0;
26244
+ const n = shared2.ctx.wallColliders != null ? shared2.ctx.wallColliders : 0, colliders = shared2.ctx.colliders;
25626
26245
  for (let i = 0; i < n; i++) {
25627
- const c = shared2.ctx.colliders[i];
26246
+ const c = colliders[i];
25628
26247
  if (c.f !== floor && !(c.f === -1 && floor === 0)) continue;
25629
26248
  let t0 = 0, t1 = 1;
25630
26249
  const dx = ax - ex, dz = az - ez;
@@ -25654,7 +26273,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25654
26273
  g.updateMatrix();
25655
26274
  }
25656
26275
  }
25657
- Object.assign(K, { linkDoorLeaves, handleApply, toggleDoor, animateDoors, wallBlocks, doorText, applyLeaf });
26276
+ const defined = { linkDoorLeaves, handleApply, toggleDoor, animateDoors, wallBlocks, doorText, applyLeaf };
26277
+ Object.assign(K, defined);
25658
26278
  }
25659
26279
  function installInteractionTarget(K, shared2) {
25660
26280
  const { doorText, toggleDoor, visibleChain, wallBlocks } = K;
@@ -25662,6 +26282,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25662
26282
  function targetOf(o, opt) {
25663
26283
  if (!o) return null;
25664
26284
  opt = opt || {};
26285
+ const I = shared2.inter;
25665
26286
  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;
25666
26287
  let best = null;
25667
26288
  const tries = (score, text, action, target) => {
@@ -25675,16 +26296,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25675
26296
  if (angle > 1.35 && d > 0.9) continue;
25676
26297
  tries(angle * 1.6 + d * 0.5 + (angle < 0.25 ? 0 : 0.6), doorText(fo), () => toggleDoor(fo), fo);
25677
26298
  }
25678
- const vis = shared2.inter.pieces.flatMap((p) => p.meshes).filter(visibleChain), hit = vis.length && opt.strike ? opt.strike(vis) : null;
26299
+ const vis = I.pieces.flatMap((p) => p.meshes).filter(visibleChain), hit = vis.length && opt.strike ? opt.strike(vis) : null;
25679
26300
  const kitA = shared2.ctx.iv ? ivTarget(shared2.ctx.iv, o, opt && opt.interactives) : null;
25680
26301
  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;
25681
26302
  const pieceHit = hit && !nearKit && hit.object.userData.piece;
25682
- for (const it of shared2.inter.items) {
26303
+ for (const it of I.items) {
25683
26304
  if (it.floor !== floor && !(it.floor === -1 && floor === 0)) continue;
25684
26305
  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);
25685
26306
  if (dh > it.range + 0.4) continue;
25686
26307
  const angle = Math.acos(Math.max(-1, Math.min(1, (dx * vx + dy * vy + dz * vz) / (d || 1))));
25687
- const byRay = pieceHit && it.pieces.includes(pieceHit) && hit.distance <= it.range + 0.5;
26308
+ const byRay = !!hit && pieceHit && it.pieces.includes(pieceHit) && hit.distance <= it.range + 0.5;
25688
26309
  if (!byRay && !(dh <= it.range && angle <= it.angle)) continue;
25689
26310
  if (!it.noWall && wallBlocks(ex, ez, ax, az, it.floor < 0 ? 0 : it.floor)) continue;
25690
26311
  tries((byRay ? 0 : angle * 2) + d * 0.3 - (byRay ? 1.5 : 0), it.text(), it.action, it);
@@ -25692,7 +26313,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25692
26313
  if (kitA) tries(kitA.score - (nearKit ? 0.5 : 0), kitA.text, kitA.action, kitA.target);
25693
26314
  return best;
25694
26315
  }
25695
- Object.assign(K, { targetOf });
26316
+ const defined = { targetOf };
26317
+ Object.assign(K, defined);
25696
26318
  }
25697
26319
  function installInteractablesBridge(K, shared2) {
25698
26320
  const { t, THREE, invalidate, invalidateShadow, cfg, DOC, LIGHT_TYPES, _Y, _q, _v3, accFor, applyLight, cursor, hashString: hashString2, hudMessage, lightBase, pieceRecord, put, rgbOf, sh, wallBlocks } = K;
@@ -25747,7 +26369,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25747
26369
  function ivBuild(h, water) {
25748
26370
  const ik = K.IVK, r = shared2.ctx.r, A = ik.A, world0 = null;
25749
26371
  void world0;
25750
- const plane2 = A.plan(r, { seed: r.seed });
26372
+ const source = r;
26373
+ const plane2 = A.plan(source, { seed: r.seed });
25751
26374
  const IV = { k: ik, plane: plane2, world: null, water, entries: /* @__PURE__ */ new Map(), roots: [], replace: /* @__PURE__ */ new Set(), roomStates: /* @__PURE__ */ new Map(), lampRoom: /* @__PURE__ */ new Map(), anim: /* @__PURE__ */ new Map(), screens: /* @__PURE__ */ new Map(), efx: null, items: null, itemsDirty: true, itemsT: 0, dirty: true, list: null, listT: 0, t: 0, circuits: [], switchRooms: /* @__PURE__ */ new Set(), warnings: [], tBuild: 0 };
25752
26375
  h.IV = IV;
25753
26376
  const t0 = performance.now();
@@ -25766,9 +26389,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25766
26389
  const wants = (roomId) => lightBase(roomId);
25767
26390
  const entById = new Map(plane2.items.map((e) => [e.id, e]));
25768
26391
  const entByItem = new Map(plane2.items.map((e) => [e.item, e]));
25769
- IV.mats = { plain: shared2.mats.plain, metal: shared2.mats.metal, wood: shared2.mats.wood, glass: shared2.mats.glass, fabric: shared2.mats.fabric, plant: shared2.mats.plant, water: shared2.mats.water, emissive: shared2.mats.emissive, atlas_picture: shared2.mats.picture, atlas_floor: shared2.mats.floor };
26392
+ const mats = shared2.mats;
26393
+ IV.mats = { plain: mats.plain, metal: shared2.mats.metal, wood: shared2.mats.wood, glass: shared2.mats.glass, fabric: shared2.mats.fabric, plant: shared2.mats.plant, water: shared2.mats.water, emissive: shared2.mats.emissive, atlas_picture: shared2.mats.picture, atlas_floor: shared2.mats.floor };
25770
26394
  const ev = (e) => ivEvent(h, e);
25771
- const world = IV.world = A.createWorld(r, { water, seed: r.seed, onEvent: ev });
26395
+ const world = IV.world = A.createWorld(source, { water, seed: r.seed, onEvent: ev });
25772
26396
  const add0 = world.add;
25773
26397
  world.add = (id, spec, tr) => {
25774
26398
  const e = entById.get(id);
@@ -25785,7 +26409,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25785
26409
  }
25786
26410
  return add0(id, spec, tr);
25787
26411
  };
25788
- const added = A.add(world, plane2, { isBlocked: A.blockedOf(r), build: (type, item) => ivDraw(IV, entByItem.get(item), type, item) });
26412
+ const added = A.add(world, plane2, { isBlocked: A.blockedOf(source), build: (type, item) => ivDraw(IV, entByItem.get(item), type, item) });
25789
26413
  world.add = add0;
25790
26414
  IV.warnings = added.warnings;
25791
26415
  IV.added = added;
@@ -25832,14 +26456,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25832
26456
  }
25833
26457
  function ivDraw(IV, ent, type, item) {
25834
26458
  const ik = IV.k, loc = Object.assign({}, item, { x: 0, z: 0, ry: 0 });
26459
+ const ix = item.x, iz = item.z, iry = item.ry;
25835
26460
  const mesh2 = ik.gfx.createMeshApi({ quality: "game", materials: IV.mats, shadows: true, mergeParts: true, swayAmplitude: 0.03 });
25836
26461
  const spec = ik.A.household.build(type, loc, mesh2.api);
25837
26462
  const out = mesh2.finish(spec);
25838
26463
  for (const l of out.lights) l.removeFromParent();
25839
26464
  const group = ivGroup(ent), g0 = cursor.group, root = new THREE.Group();
25840
26465
  root.name = "iv:" + ent.id;
25841
- root.position.set(item.x, ent.floorY, item.z);
25842
- root.rotation.y = item.ry;
26466
+ root.position.set(ix, ent.floorY, iz);
26467
+ root.rotation.y = iry;
25843
26468
  root.userData.iv = ent.id;
25844
26469
  const screen = spec.devices && spec.devices.some((d) => d.kind === "screen");
25845
26470
  let body = null;
@@ -25848,7 +26473,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25848
26473
  if (type === "gas_bottle") {
25849
26474
  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"] });
25850
26475
  for (const m of out.group.children) if (!m.name.startsWith("static:")) m.traverse((o) => {
25851
- if (o.isMesh) {
26476
+ if (isMesh(o)) {
25852
26477
  o.userData.destructionPart = cursor.pc.id;
25853
26478
  o.userData.destructionMaterial = "steel";
25854
26479
  }
@@ -25856,13 +26481,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25856
26481
  }
25857
26482
  try {
25858
26483
  for (const m of out.group.children.slice()) {
25859
- if (m.isMesh && m.name.startsWith("static:")) {
26484
+ if (isMesh(m) && m.name.startsWith("static:")) {
25860
26485
  if (screen && m.userData.material === "emissive") {
25861
26486
  body = m;
25862
26487
  root.add(m);
25863
26488
  continue;
25864
26489
  }
25865
- ivAccumulate(IV_MATERIAL[m.userData.material] || "plain", m.geometry, item.x, ent.floorY, item.z, item.ry, null);
26490
+ ivAccumulate(IV_MATERIAL[m.userData.material] || "plain", m.geometry, ix, ent.floorY, iz, iry, null);
25866
26491
  m.geometry.dispose();
25867
26492
  } else root.add(m);
25868
26493
  }
@@ -25872,7 +26497,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25872
26497
  }
25873
26498
  const base = new Set(Object.values(IV.mats));
25874
26499
  root.traverse((o) => {
25875
- if (!o.isMesh) return;
26500
+ if (!isMesh(o)) return;
25876
26501
  o.userData.iv = ent.id;
25877
26502
  if (o.castShadow) {
25878
26503
  if (!o.geometry.boundingSphere) o.geometry.computeBoundingSphere();
@@ -25883,7 +26508,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25883
26508
  roomLightMask(m);
25884
26509
  }
25885
26510
  });
25886
- 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 };
26511
+ 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 };
25887
26512
  IV.entries.set(ent.id, E);
25888
26513
  if (root.children.length) IV.roots.push(E);
25889
26514
  return spec;
@@ -25911,7 +26536,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25911
26536
  const wire = (spec.wires || []).find((x) => x.id === d.id + "_cord"), pts = (wire ? wire.points : [d.plug]).map((p) => wl(o, p));
25912
26537
  const sid = w.power.pluggedInto(E.id, d.id);
25913
26538
  if (sid) {
25914
- const cut = sid.indexOf(":"), so = w.get(sid.slice(0, cut)), sk = so && so.spec.sockets.find((s) => s.id === sid.slice(cut + 1));
26539
+ const cut = sid.indexOf(":"), so = w.get(sid.slice(0, cut)), sk = so && (so.spec.sockets || []).find((s) => s.id === sid.slice(cut + 1));
25915
26540
  if (so && sk) {
25916
26541
  const sp = wl(so, sk.pos), dir = [Math.sin(so.transform.ry), Math.cos(so.transform.ry)], last = pts[pts.length - 1];
25917
26542
  if (last[1] < 0.3 + E.pos[1]) {
@@ -25946,9 +26571,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25946
26571
  roomLightMask(sc.material);
25947
26572
  IV.screens.set(E.id, sc);
25948
26573
  }
25949
- E.screen.material = sc.material;
25950
- E.screen.castShadow = false;
25951
- E.screen.receiveShadow = false;
26574
+ const mesh2 = E.screen;
26575
+ mesh2.material = sc.material;
26576
+ mesh2.castShadow = false;
26577
+ mesh2.receiveShadow = false;
25952
26578
  }
25953
26579
  function ivEvent(h, e) {
25954
26580
  const IV = h.IV;
@@ -25984,16 +26610,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25984
26610
  IV.itemsDirty = true;
25985
26611
  break;
25986
26612
  }
25987
- if (K.IVK.onEvent) {
26613
+ const ik = K.IVK;
26614
+ if (ik.onEvent) {
25988
26615
  try {
25989
- K.IVK.onEvent(e, h.IV.pub);
26616
+ ik.onEvent(e, IV.pub);
25990
26617
  } catch (err) {
25991
26618
  console.warn("interactables.onEvent", err);
25992
26619
  }
25993
26620
  }
25994
- if (e.type === "seat" && K.IVK.onSeat && e.actor === "player") {
26621
+ if (e.type === "seat" && ik.onSeat && e.actor === "player") {
25995
26622
  try {
25996
- K.IVK.onSeat(e.seated ? ivSeat(IV) : null, e);
26623
+ ik.onSeat(e.seated ? ivSeat(IV) : null, e);
25997
26624
  } catch (err) {
25998
26625
  console.warn("interactables.onSeat", err);
25999
26626
  }
@@ -26002,7 +26629,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26002
26629
  function ivSeat(IV) {
26003
26630
  const w = IV.world, s = w.seatOf("player");
26004
26631
  if (!s) return null;
26005
- 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);
26632
+ 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);
26006
26633
  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]]);
26007
26634
  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 };
26008
26635
  }
@@ -26044,18 +26671,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26044
26671
  }
26045
26672
  }
26046
26673
  const em = w.emitters();
26047
- if (em.length && !IV.efx && K.IVK.effects) {
26674
+ const ivk = K.IVK;
26675
+ if (em.length && !IV.efx && ivk.effects) {
26048
26676
  const g = h.houseGroup;
26049
- IV.efx = ik.gfx.createEffects(g, { maxParticles: 1400, seed: 11, document: DOC, ...K.IVK.effectSink ? { effects: K.IVK.effectSink } : {} });
26677
+ IV.efx = ik.gfx.createEffects(g, { maxParticles: 1400, seed: 11, document: DOC, ...ivk.effectSink ? { effects: ivk.effectSink } : {} });
26050
26678
  }
26051
26679
  if (IV.efx) {
26052
26680
  const alive = IV.efx.stats().alive;
26053
26681
  if (em.length || alive) {
26054
- IV.efx.update(dt, em, K.IVK.camera ? typeof K.IVK.camera === "function" ? K.IVK.camera() : K.IVK.camera : void 0);
26682
+ IV.efx.update(dt, em, ivk.camera ? typeof ivk.camera === "function" ? ivk.camera() : ivk.camera : void 0);
26055
26683
  invalidate();
26056
26684
  }
26057
26685
  }
26058
- if (K.IVK.items && IV.itemsDirty && IV.t - IV.itemsT > 0.1 && !IV.anim.size) ivItems(IV, h);
26686
+ if (ivk.items && IV.itemsDirty && IV.t - IV.itemsT > 0.1 && !IV.anim.size) ivItems(IV, h);
26059
26687
  }
26060
26688
  const IV_SHAPE = {
26061
26689
  can: [["cyl", 1, 1, 1, 0, 1]],
@@ -26090,7 +26718,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26090
26718
  if (c.access && w.partT(E.id, c.access) < 0.02) continue;
26091
26719
  const st = w.contents(E.id, c.id);
26092
26720
  for (let i = 0; i < st.length; i++) {
26093
- if (st[i] && items[st[i].type]) list2.push([E, c.id, i, items[st[i].type]]);
26721
+ const stack = st[i];
26722
+ if (stack && items[stack.type]) list2.push([E, c.id, i, items[stack.type]]);
26094
26723
  }
26095
26724
  }
26096
26725
  }
@@ -26119,12 +26748,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26119
26748
  gm.setIndex(new THREE.BufferAttribute(A.i.slice(0, A.ni), 1));
26120
26749
  gm.computeBoundingSphere();
26121
26750
  if (!IV.items) {
26122
- IV.items = new THREE.Mesh(gm, shared2.mats.plain);
26123
- IV.items.name = "iv-items";
26124
- IV.items.castShadow = false;
26125
- IV.items.receiveShadow = true;
26126
- IV.items.frustumCulled = false;
26127
- h.houseGroup.add(IV.items);
26751
+ const mesh2 = new THREE.Mesh(gm, shared2.mats.plain);
26752
+ IV.items = mesh2;
26753
+ mesh2.name = "iv-items";
26754
+ mesh2.castShadow = false;
26755
+ mesh2.receiveShadow = true;
26756
+ mesh2.frustumCulled = false;
26757
+ h.houseGroup.add(mesh2);
26128
26758
  } else {
26129
26759
  IV.items.geometry.dispose();
26130
26760
  IV.items.geometry = gm;
@@ -26258,7 +26888,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26258
26888
  };
26259
26889
  return IV.pub;
26260
26890
  }
26261
- 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 });
26891
+ 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 };
26892
+ Object.assign(K, defined);
26262
26893
  }
26263
26894
  function installAnimationClotheslines(K, shared2) {
26264
26895
  const { invalidate, CLOTHES_UNIFORMS } = K;
@@ -26281,7 +26912,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26281
26912
  }
26282
26913
  invalidate();
26283
26914
  }
26284
- Object.assign(K, { WIND, animateClotheslines });
26915
+ const defined = { WIND, animateClotheslines };
26916
+ Object.assign(K, defined);
26285
26917
  }
26286
26918
  function installBuildInstance(K, shared2) {
26287
26919
  const { PROPS, THREE, DOC, cfg, HP, createInteractiveMaterials, createMaterials, typeTable } = K;
@@ -26304,7 +26936,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26304
26936
  shared2.quality = h.quality;
26305
26937
  }
26306
26938
  const tagDamage = (type) => ({ type, hp: HP[type], hpMax: HP[type] });
26307
- Object.assign(K, { props, TYPES, newState, enter, tagDamage });
26939
+ const defined = { props, TYPES, newState, enter, tagDamage };
26940
+ Object.assign(K, defined);
26308
26941
  }
26309
26942
  function installInteractablesKit(K, shared2) {
26310
26943
  const { t, THREE, DOC, cfg, Reflector } = K;
@@ -26330,15 +26963,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26330
26963
  for (const k of ["wood", "foliage", "flowers", "fruit", "spines"]) roomLightMask(m[k]);
26331
26964
  return m;
26332
26965
  })());
26333
- Object.assign(K, { IVK, VEG, vegMaterials });
26966
+ const defined = { IVK, VEG, vegMaterials };
26967
+ Object.assign(K, defined);
26334
26968
  }
26969
+ 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 });
26335
26970
  function installLightsRoomLight(K, shared2) {
26336
26971
  const { THREE, rectsOf: rectsOf2, cfg } = K;
26337
26972
  const MAX_LIGHTS = 12, EMPTY = [1e9, 1e9, -1e9, -1e9];
26338
26973
  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 } };
26339
26974
  for (let i = 0; i < MAX_LIGHTS; i++) for (const k of ["uRB0", "uRB1", "uRB2", "uREx"]) LZU[k].value.set(EMPTY, i * 4);
26340
- function roomLightMask(m) {
26341
- if (!m || m.userData && m.userData.roomLightMask || !(m.isMeshLambertMaterial || m.isMeshPhongMaterial || m.isMeshStandardMaterial || m.isMeshPhysicalMaterial)) return m;
26975
+ function roomLightMask(material) {
26976
+ const m = material;
26977
+ if (!m || m.userData && m.userData.roomLightMask || !(m.isMeshLambertMaterial || m.isMeshPhongMaterial || m.isMeshStandardMaterial || m.isMeshPhysicalMaterial)) return material;
26342
26978
  m.userData = m.userData || {};
26343
26979
  m.userData.roomLightMask = true;
26344
26980
  const prev = m.onBeforeCompile, pk = m.customProgramCacheKey;
@@ -26366,12 +27002,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26366
27002
  return (pk ? pk.call(this) : "") + "|rm1";
26367
27003
  };
26368
27004
  m.needsUpdate = true;
26369
- return m;
27005
+ return material;
26370
27006
  }
26371
- function lighting(o) {
26372
- o = o || {};
27007
+ function lighting(options) {
27008
+ const o = options || {};
26373
27009
  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;
26374
- for (const k of Object.keys(shared2.mats)) roomLightMask(shared2.mats[k]);
27010
+ const mats = shared2.mats;
27011
+ for (const k of Object.keys(mats)) roomLightMask(mats[k]);
26375
27012
  const budget = o.budget, lease = budget ? budget.lease({ owner: "floorplan.rooms", point: N, shadows: NS }) : null;
26376
27013
  if (budget && !lease) throw new Error("lighting: the LightBudget has no " + N + " free point slots (" + NS + " with shadow) for the rooms");
26377
27014
  if (budget) for (const [key2, width] of [["uRB0", 4], ["uRB1", 4], ["uRB2", 4], ["uRBY", 2], ["uREx", 4]]) {
@@ -26422,9 +27059,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26422
27059
  }
26423
27060
  for (let i = 0; i < NS; i++) PL[i].shadow.needsUpdate = true;
26424
27061
  };
26425
- A.update = function(houses, focus, op) {
26426
- op = op || {};
26427
- houses = (Array.isArray(houses) ? houses : [houses]).filter(Boolean);
27062
+ A.update = function(houseOrList, focus, options2) {
27063
+ const op = options2 || {}, houses = (Array.isArray(houseOrList) ? houseOrList : [houseOrList]).filter((h) => !!h);
26428
27064
  _f.set(focus.x, focus.y, focus.z);
26429
27065
  const rooms = [], exterior = [];
26430
27066
  for (const house of houses) {
@@ -26436,7 +27072,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26436
27072
  if (!house.lightOn(l.roomId)) continue;
26437
27073
  const k = l.type === "outdoor" ? "ext:" + (l.id || exterior.length) : l.roomId != null ? l.roomId : l.room;
26438
27074
  let g = by.get(k);
26439
- if (!g) by.set(k, g = { k, house, ls: [], exterior: l.type === "outdoor" });
27075
+ if (!g) by.set(k, g = newGroup(k, house, l.type === "outdoor"));
26440
27076
  g.ls.push(l);
26441
27077
  }
26442
27078
  for (const g of by.values()) {
@@ -26471,9 +27107,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26471
27107
  }
26472
27108
  }
26473
27109
  g.exclusion = [x0 + 0.03, z0 + 0.03, x1 - 0.03, z1 - 0.03];
26474
- g.lumens = ls[0].lumens != null ? ls[0].lumens : 3.2;
26475
- g.dist = ls[0].dist != null ? ls[0].dist : 5.5;
26476
- g.decay = ls[0].decay != null ? ls[0].decay : 2;
27110
+ const l0 = ls[0];
27111
+ g.lumens = l0.lumens != null ? l0.lumens : 3.2;
27112
+ g.dist = l0.dist != null ? l0.dist : 5.5;
27113
+ g.decay = l0.decay != null ? l0.decay : 2;
26477
27114
  } else {
26478
27115
  const c = house.r.rooms.find((q) => q.id === g.k);
26479
27116
  if (!c) continue;
@@ -26574,8 +27211,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26574
27211
  }
26575
27212
  const effectsByBudget = /* @__PURE__ */ new WeakMap();
26576
27213
  const OPENING_REACH = 2.5, OPENING_SIDE = 0.6;
26577
- function effectLights(o) {
26578
- o = o || {};
27214
+ function effectLights(options) {
27215
+ const o = options || {};
26579
27216
  const budget = o.budget;
26580
27217
  if (!budget) throw new Error("effectLights: a LightBudget is required");
26581
27218
  const known = effectsByBudget.get(budget);
@@ -26653,7 +27290,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26653
27290
  const A = {
26654
27291
  /** 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. */
26655
27292
  update(houses) {
26656
- const indoors = cfg.effectLightsIndoors !== false, list2 = (Array.isArray(houses) ? houses : [houses]).filter(Boolean), cache2 = /* @__PURE__ */ new Map();
27293
+ const indoors = cfg.effectLightsIndoors !== false, list2 = (Array.isArray(houses) ? houses : [houses]).filter((h) => !!h), cache2 = /* @__PURE__ */ new Map();
26657
27294
  for (let at2 = 0; at2 < size; at2++) {
26658
27295
  if (ours.has(at2)) continue;
26659
27296
  const light = budget.group.children[at2];
@@ -26681,7 +27318,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26681
27318
  if (!o.ours) effectsByBudget.set(budget, A);
26682
27319
  return A;
26683
27320
  }
26684
- Object.assign(K, { MAX_LIGHTS, EMPTY, LZU, roomLightMask, lighting, effectLights });
27321
+ const defined = { MAX_LIGHTS, EMPTY, LZU, roomLightMask, lighting, effectLights };
27322
+ Object.assign(K, defined);
26685
27323
  }
26686
27324
  var NONE = { panels: [], replaced: [], supports: [] };
26687
27325
  var MEMO = /* @__PURE__ */ new WeakMap();
@@ -26857,7 +27495,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26857
27495
  if (!pc || pc.unit) return sp;
26858
27496
  if (pc.role !== "wall" && pc.role !== "partition") {
26859
27497
  const def = getAssembly(pc.assembly || (pc.material === "concrete" && ["slab", "beam", "column", "stair"].includes(pc.role) ? "reinforced_concrete" : ""));
26860
- const out = def && def.reinforcement && !sp.reinforcement ? { ...sp, reinforcement: { ...def.reinforcement } } : sp;
27498
+ 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;
27499
+ const out = cage && !sp.reinforcement ? { ...sp, reinforcement: cage } : sp;
26861
27500
  if (out.reinforcement && !out.units && pc.material === "concrete" && (pc.role === "beam" || pc.role === "column") && sp.shape.kind === "box") {
26862
27501
  return { ...out, units: { size: [MEMBER_CAGE.unit, MEMBER_CAGE.unit, Math.min(...sp.shape.size)], bond: "stack", mortar: "concrete" } };
26863
27502
  }
@@ -26883,6 +27522,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26883
27522
  const a = pos.array;
26884
27523
  const u = mesh2.userData;
26885
27524
  if (!u._p0) u._p0 = a.slice();
27525
+ if (!u.plainPositions) Object.defineProperty(u, "plainPositions", { value: u._p0, enumerable: false, configurable: true, writable: true });
26886
27526
  const list2 = u.collapsedRanges ?? (u.collapsedRanges = []);
26887
27527
  if (!list2.some((r) => r[0] === v0 && r[1] === v1)) list2.push([v0, v1]);
26888
27528
  const saved = a.slice(v0 * 3, v1 * 3);
@@ -26966,10 +27606,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26966
27606
  const v = house.worldToLocal(tmp.p.set(p[0], p[1], p[2]));
26967
27607
  return [v.x, v.y, v.z];
26968
27608
  };
26969
- function cells(part, units) {
27609
+ function cells(part, units, mask) {
26970
27610
  const [u0, v0, u1, v1] = part.aabb;
26971
- const alongU = u1 - u0 >= v1 - v0;
27611
+ const alongU = mask.alongU;
26972
27612
  const len = alongU ? u1 - u0 : v1 - v0;
27613
+ const offset = (alongU ? u0 : v0) - mask.start;
26973
27614
  const [ul, uh] = units.size;
26974
27615
  const rows = Math.max(1, Math.round((part.y1 - part.y0) / uh));
26975
27616
  const rowH = (part.y1 - part.y0) / rows;
@@ -26980,7 +27621,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26980
27621
  const shift = units.bond === "running" && r & 1 ? w / 2 : 0;
26981
27622
  for (let i = 0; i < per + (shift ? 1 : 0); i++) {
26982
27623
  const a = Math.max(0, i * w - shift), b = Math.min(len, i * w - shift + w);
26983
- if (b - a > 1e-3) out.push({ a, b, y0: part.y0 + r * rowH, y1: part.y0 + (r + 1) * rowH, r, i });
27624
+ 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 });
26984
27625
  }
26985
27626
  }
26986
27627
  return out;
@@ -26994,8 +27635,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26994
27635
  for (const q of structure.parts) {
26995
27636
  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;
26996
27637
  }
27638
+ return part.role === "column" ? wallAround(part) : null;
27639
+ }
27640
+ function wallAround(part) {
27641
+ const cu = (part.aabb[0] + part.aabb[2]) / 2, cv = (part.aabb[1] + part.aabb[3]) / 2;
27642
+ for (const q of structure.parts) {
27643
+ if (q.id === part.id || q.role !== "wall" && q.role !== "partition" || !structure.meshesOf(q.id).some((it) => it.mesh)) continue;
27644
+ const inside2 = cu >= q.aabb[0] - 1e-3 && cu <= q.aabb[2] + 1e-3 && cv >= q.aabb[1] - 1e-3 && cv <= q.aabb[3] + 1e-3;
27645
+ if (inside2 && Math.min(q.y1, part.y1) - Math.max(q.y0, part.y0) > 0.5) return q.id;
27646
+ }
26997
27647
  return null;
26998
27648
  }
27649
+ const pillarSpans = (view) => structure.parts.filter((q) => q.role === "column" && wallAround(q) === view.host).map((q) => {
27650
+ 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;
27651
+ return { a, b, y0: q.y0, y1: q.y1 };
27652
+ });
26999
27653
  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);
27000
27654
  function shell(it, mask) {
27001
27655
  const g0 = it.mesh.geometry, g = new THREE.BufferGeometry();
@@ -27084,6 +27738,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27084
27738
  texture.needsUpdate = true;
27085
27739
  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) };
27086
27740
  }
27741
+ function besidePillars(c, pillars) {
27742
+ let { a, b } = c;
27743
+ for (const k of pillars) {
27744
+ if (c.y1 <= k.y0 || c.y0 >= k.y1 || b <= k.a || a >= k.b) continue;
27745
+ const centre = (a + b) / 2;
27746
+ if (centre > k.a && centre < k.b) return [];
27747
+ if (centre <= k.a) b = Math.min(b, k.a);
27748
+ else a = Math.max(a, k.b);
27749
+ }
27750
+ return b - a > 1e-3 ? [{ ...c, a, b }] : [];
27751
+ }
27087
27752
  const boxDistance = (s, y, a, b, c, d) => Math.hypot(Math.max(a - s, 0, s - b), Math.max(c - y, 0, y - d));
27088
27753
  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);
27089
27754
  function covered(c, boxes) {
@@ -27106,9 +27771,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27106
27771
  const discs = [];
27107
27772
  const flakes = [];
27108
27773
  const shown = [];
27774
+ const pillars = pillarSpans(view);
27109
27775
  for (const id of view.parts) {
27110
27776
  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);
27111
- const all = cells(part, units2);
27777
+ const own = cells(part, units2, mask);
27778
+ const all = id === view.host ? own.flatMap((c) => besidePillars(c, pillars)) : own;
27779
+ if (view.fallen.has(id)) {
27780
+ holes.push(...all);
27781
+ continue;
27782
+ }
27112
27783
  const thick = mask.alongU ? part.aabb[3] - part.aabb[1] : part.aabb[2] - part.aabb[0];
27113
27784
  const mid = mask.alongU ? (part.aabb[1] + part.aabb[3]) / 2 : (part.aabb[0] + part.aabb[2]) / 2;
27114
27785
  if (opening) discs.push({ s: along(opening.center), y: opening.center[1], r: opening.radius });
@@ -27204,52 +27875,55 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27204
27875
  }
27205
27876
  return { center: local(chip.center), along: a, up: u };
27206
27877
  }
27878
+ function newView(hostId) {
27879
+ const items = structure.meshesOf(hostId).filter((it) => it.mesh);
27880
+ if (!items.length) return null;
27881
+ const parts = [hostId, ...riders(hostId)].filter((id) => structure.byId.get(id) && specOf(id)?.units);
27882
+ const mask = maskOf(hostId, parts), core = maskOf(hostId, parts);
27883
+ return {
27884
+ host: hostId,
27885
+ parts,
27886
+ items,
27887
+ mask,
27888
+ core,
27889
+ unitMaterial: unitsMaterial(core),
27890
+ shells: [],
27891
+ saved: null,
27892
+ units: null,
27893
+ gone: 0,
27894
+ pits: 0,
27895
+ bounds: drawnBounds(items),
27896
+ chips: new Map(parts.map((id) => [id, []])),
27897
+ spalls: new Map(parts.map((id) => [id, []])),
27898
+ openings: /* @__PURE__ */ new Map(),
27899
+ flakes: 0,
27900
+ fallen: /* @__PURE__ */ new Set()
27901
+ };
27902
+ }
27903
+ function cut(view) {
27904
+ if (view.saved) return;
27905
+ view.shells = view.items.map((it) => shell(it, view.mask));
27906
+ for (const m of view.shells) m.userData.behind = () => view.units;
27907
+ view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
27908
+ }
27207
27909
  function draw(partId, change) {
27208
27910
  if (lod !== 0) return false;
27209
27911
  const hostId = hostOf(partId);
27210
27912
  if (!hostId || !specOf(partId)?.units) return false;
27211
- let view = views.get(hostId);
27212
- if (!view) {
27213
- const items = structure.meshesOf(hostId).filter((it) => it.mesh);
27214
- if (!items.length) return false;
27215
- const parts = [hostId, ...riders(hostId)].filter((id) => structure.byId.get(id) && specOf(id)?.units);
27216
- if (!parts.includes(partId)) return false;
27217
- const mask = maskOf(hostId, parts), core = maskOf(hostId, parts);
27218
- view = {
27219
- host: hostId,
27220
- parts,
27221
- items,
27222
- mask,
27223
- core,
27224
- unitMaterial: unitsMaterial(core),
27225
- shells: [],
27226
- saved: null,
27227
- units: null,
27228
- gone: 0,
27229
- pits: 0,
27230
- bounds: drawnBounds(items),
27231
- chips: new Map(parts.map((id) => [id, []])),
27232
- spalls: new Map(parts.map((id) => [id, []])),
27233
- openings: /* @__PURE__ */ new Map(),
27234
- flakes: 0
27235
- };
27236
- }
27237
- if (!view.chips.has(partId)) return false;
27913
+ const view = views.get(hostId) ?? newView(hostId);
27914
+ if (!view || !view.chips.has(partId)) return false;
27238
27915
  if (change.opening) {
27239
27916
  if (view.openings.has(partId)) return false;
27240
27917
  view.openings.set(partId, { center: local(change.opening.center), radius: change.opening.radius });
27241
27918
  }
27242
27919
  if (change.chip) view.chips.get(partId).push(chipBox(change.chip, view.mask.alongU));
27920
+ for (const chip of change.chips ?? []) view.chips.get(partId).push(chipBox(chip, view.mask.alongU));
27243
27921
  if (change.spall) {
27244
27922
  const list2 = view.spalls.get(partId);
27245
27923
  list2.push({ center: local(change.spall.center), radius: change.spall.radius });
27246
27924
  if (list2.length > MAX_FLAKES) list2.shift();
27247
27925
  }
27248
- if (!view.saved) {
27249
- view.shells = view.items.map((it) => shell(it, view.mask));
27250
- for (const m of view.shells) m.userData.behind = () => view.units;
27251
- view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
27252
- }
27926
+ cut(view);
27253
27927
  views.set(hostId, view);
27254
27928
  if (opts.deferPaint && change.spall) dirty.add(view);
27255
27929
  else {
@@ -27360,14 +28034,32 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27360
28034
  */
27361
28035
  chip(event) {
27362
28036
  if (event.torn) return false;
27363
- return draw(event.part, { chip: { center: event.center, size: event.size ?? [0, 0, 0], rotation: event.rotation ?? [0, 0, 0, 1] } });
28037
+ const rotation = event.rotation ?? [0, 0, 0, 1];
28038
+ if (event.units?.length) return draw(event.part, { chips: event.units.map((unit) => ({ center: unit.center, size: unit.size, rotation })) });
28039
+ return draw(event.part, { chip: { center: event.center, size: event.size ?? [0, 0, 0], rotation } });
27364
28040
  },
27365
28041
  /** The part broke or fell: its damage goes (the plain range stays collapsed, the renderer hides the part). */
27366
28042
  drop(partId) {
27367
- const v = views.get(partId);
27368
- if (!v) return;
28043
+ let host = views.get(partId) ?? [...views.values()].find((view) => view.parts.includes(partId));
28044
+ if (!host && lod === 0 && riders(partId).length > 0) {
28045
+ host = newView(partId);
28046
+ if (host) {
28047
+ cut(host);
28048
+ views.set(partId, host);
28049
+ }
28050
+ }
28051
+ if (!host) return;
28052
+ host.fallen.add(partId);
28053
+ if (host.parts.some((id) => !host.fallen.has(id))) {
28054
+ dirty.delete(host);
28055
+ paint(host);
28056
+ invalidate();
28057
+ invalidateShadow();
28058
+ return;
28059
+ }
28060
+ const v = host;
27369
28061
  dispose(v);
27370
- views.delete(partId);
28062
+ views.delete(v.host);
27371
28063
  if (v.saved) dropped.push(v);
27372
28064
  },
27373
28065
  /** LOD 0 draws the cut wall; LOD 1 and 2 give the wall its box back. */
@@ -27804,8 +28496,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27804
28496
  }
27805
28497
  function installBuildBuild(K, shared2) {
27806
28498
  const { THREE, cfg, rectsOf: rectsOf2, invalidateShadow, colliderChanged, VERSION: VERSION2, CARS, EPS: EPS3, 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;
27807
- function build(r0, opts) {
27808
- opts = opts || {};
28499
+ function build(r0, options) {
28500
+ const opts = options || {};
27809
28501
  const r = applyOutbuildings(r0);
27810
28502
  const t0 = performance.now();
27811
28503
  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 };
@@ -27826,7 +28518,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27826
28518
  shared2.ctx.pieces = /* @__PURE__ */ new Map();
27827
28519
  shared2.ctx.pieceObjects = /* @__PURE__ */ new Map();
27828
28520
  shared2.ctx.structureIndex = {};
27829
- for (const e of r0.structure && r0.structure.parts || []) shared2.ctx.structureIndex[e.id] = e;
28521
+ for (const e of r0.structure?.parts || []) shared2.ctx.structureIndex[e.id] = e;
27830
28522
  {
27831
28523
  const view = shared2.ctx.panelView = panelViewOf(r0.structure, !!cfg.destruction);
27832
28524
  shared2.ctx.panelsOf = /* @__PURE__ */ new Map();
@@ -27838,17 +28530,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27838
28530
  else shared2.ctx.panelsOf.set(e.slab, [e]);
27839
28531
  }
27840
28532
  }
27841
- shared2.ctx.panes = r0.roof && r0.roof.panes || [];
28533
+ shared2.ctx.panes = r0.roof?.panes || [];
27842
28534
  shared2.ctx.noPiece = false;
27843
28535
  cursor.separate = opts.pieces === "meshes";
27844
28536
  cursor.pc = null;
28537
+ shared2.ctx.showPillars = opts.pillars !== "hidden";
27845
28538
  shared2.ctx.apartment = r.template === "apartment_modern";
27846
28539
  shared2.ctx.pa = Math.max(3, Math.min(20, pr.floors != null ? pr.floors : 5));
27847
28540
  shared2.ctx.pf = Math.max(1, Math.min(shared2.ctx.pa, pr.floor != null ? pr.floor : 3));
27848
28541
  shared2.ctx.pu = Math.max(0, pr.unit != null ? pr.unit : 0);
27849
28542
  shared2.ctx.showBuilding = shared2.ctx.apartment && (pr.showIt == null ? true : !!pr.showIt);
27850
28543
  shared2.ctx.limits = { x0: -2, z0: -2, x1: r.w + 2, z1: r.d + 2 };
27851
- shared2.ctx.veg = VEG ? { G: VEG.G, S: VEG.S, mats: vegMaterials, groups: /* @__PURE__ */ new Map(), ok: /* @__PURE__ */ new Map(), opts: shared2.quality === "game" ? { quality: "game" } : { lod: 0, triangleBudget: 6e4 } } : null;
28544
+ shared2.ctx.veg = VEG ? { G: VEG.G, S: VEG.S, mats: vegMaterials, groups: /* @__PURE__ */ new Map(), ok: /* @__PURE__ */ new Map(), opts: shared2.quality === "game" ? { quality: "game" } : { quality: "high", lod: 0, triangleBudget: 6e4 } } : null;
27852
28545
  shared2.ctx.vegInfo = null;
27853
28546
  terrain();
27854
28547
  if (r.lot) {
@@ -27898,7 +28591,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27898
28591
  const g = gs[gd.name];
27899
28592
  if (!g) continue;
27900
28593
  delete gs[gd.name];
27901
- g.position.set(...gd.pos);
28594
+ g.position.fromArray(gd.pos);
27902
28595
  parent.add(g);
27903
28596
  fo.gs.push(g);
27904
28597
  }
@@ -27913,7 +28606,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27913
28606
  root.add(house);
27914
28607
  shared2.mirrors.house = house;
27915
28608
  if (shared2.ctx.apartment) {
27916
- const u = r.building.units[Math.min(shared2.ctx.pu, r.building.units.length - 1)];
28609
+ const units = r.building.units, u = units[Math.min(shared2.ctx.pu, units.length - 1)];
27917
28610
  house.position.set(u.u, shared2.ctx.showBuilding ? 0 : -r.floors[0].y0, u.v);
27918
28611
  house.rotation.y = u.ry;
27919
28612
  shared2.ctx.unitRy = u.ry;
@@ -28029,7 +28722,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28029
28722
  const wallAt = (f, axis, L) => r.walls.find((w) => w.floor === f && w.axis === axis && Math.abs((axis === "u" ? w.v0 : w.u0) - L) < EPS3);
28030
28723
  for (const j of r.windows) {
28031
28724
  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;
28032
- 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: () => {
28725
+ const jy0 = j.y0, jy1 = j.y1;
28726
+ 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: () => {
28033
28727
  }, t: 0 };
28034
28728
  }
28035
28729
  for (const E of mirrorsCopy) {
@@ -28072,7 +28766,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28072
28766
  const countDraw = () => {
28073
28767
  let n = 0, t = 0;
28074
28768
  root.traverseVisible((o) => {
28075
- if (o.isMesh) {
28769
+ if (isMesh(o)) {
28076
28770
  n++;
28077
28771
  t += (o.geometry.index ? o.geometry.index.count : o.geometry.attributes.position.count) / 3;
28078
28772
  }
@@ -28086,8 +28780,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28086
28780
  const budget = opts.drawCallBudget != null ? opts.drawCallBudget : cfg.drawCallBudget;
28087
28781
  const stats2 = { quality: h.quality, drawCalls: s0.n, drawCallsLOD1: s1.n, triangles: s0.t, trianglesLod1: s1.t, budget: budget || null, overBudget: !!budget && s0.n > budget, tBuild: performance.now() - t0 };
28088
28782
  shared2.ctx.tBuild = stats2.tBuild;
28089
- const applyLod = (n) => {
28090
- n = Math.max(0, Math.min(2, n | 0));
28783
+ const applyLod = (level) => {
28784
+ const n = Math.max(0, Math.min(2, level | 0));
28091
28785
  if (n === h.lodCurrent) return;
28092
28786
  h.lodCurrent = n;
28093
28787
  for (const o of lodObjects) o.visible = n < 1;
@@ -28164,7 +28858,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28164
28858
  lights: (() => {
28165
28859
  const by = {};
28166
28860
  for (const l of shared2.ctx.lights) {
28167
- const k = l.roomId != null ? l.roomId : l.room;
28861
+ const k = String(l.roomId != null ? l.roomId : l.room);
28168
28862
  (by[k] || (by[k] = [])).push(l);
28169
28863
  }
28170
28864
  return { list: shared2.ctx.lights, byRoom: by };
@@ -28204,9 +28898,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28204
28898
  applyLod(Math.max(n, h.lodMin));
28205
28899
  }
28206
28900
  },
28207
- show(o) {
28901
+ show(options2) {
28208
28902
  enter(h);
28209
- o = o || {};
28903
+ const o = options2 || {};
28210
28904
  const rr = shared2.ctx.r, nA = rr.floors.length, a = o.floor == null ? -1 : o.floor, sel = a >= nA ? -1 : a, cut = !!o.cut;
28211
28905
  for (const [k, g] of Object.entries(gs)) {
28212
28906
  let v = true;
@@ -28226,7 +28920,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28226
28920
  enter(h);
28227
28921
  const a = targetOf(o, opt);
28228
28922
  if (!a) return false;
28229
- 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);
28923
+ 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);
28230
28924
  },
28231
28925
  message() {
28232
28926
  return shared2.inter.msg && performance.now() < shared2.inter.msg.until ? shared2.inter.msg.text : null;
@@ -28283,13 +28977,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28283
28977
  }
28284
28978
  return null;
28285
28979
  },
28286
- partAt(p, tol) {
28287
- tol = tol || 0.05;
28980
+ partAt(p, tolerance) {
28981
+ const tol = tolerance || 0.05;
28288
28982
  let m = null;
28289
28983
  for (const k in parts) {
28290
- const a = parts[k].aabb;
28984
+ const part = parts[k], a = part.aabb;
28291
28985
  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) {
28292
- m = parts[k];
28986
+ m = part;
28293
28987
  break;
28294
28988
  }
28295
28989
  }
@@ -28300,8 +28994,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28300
28994
  destruction.deactivate();
28301
28995
  if (h.IV) ivDispose(h);
28302
28996
  root.traverse((o) => {
28303
- if (o.isMesh && o.geometry && !o.geometry.userData.shared) o.geometry.dispose();
28304
- if (o.type === "Reflector" && o.dispose) o.dispose();
28997
+ if (isMesh(o) && o.geometry && !o.geometry.userData.shared) o.geometry.dispose();
28998
+ if (o.type === "Reflector" && "dispose" in o && typeof o.dispose === "function") o.dispose();
28305
28999
  });
28306
29000
  root.removeFromParent();
28307
29001
  },
@@ -28309,7 +29003,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28309
29003
  };
28310
29004
  return res;
28311
29005
  }
28312
- Object.assign(K, { build });
29006
+ const defined = { build };
29007
+ Object.assign(K, defined);
28313
29008
  }
28314
29009
  function buildApi(K, shared2) {
28315
29010
  const { cfg, VERSION: VERSION2, ATLAS, TEX, applyPart, carGroup, carModel, props, TYPES, roomLightMask, lighting, effectLights, newState, build } = K;
@@ -28329,11 +29024,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28329
29024
  lighting,
28330
29025
  effectLights,
28331
29026
  setNight(n) {
28332
- shared2.mats.glass.emissive.set(n ? 9067040 : 0);
28333
- shared2.mats.glass.opacity = n ? 0.4 : 0.24;
29027
+ const glass = shared2.mats.glass;
29028
+ glass.emissive.set(n ? 9067040 : 0);
29029
+ glass.opacity = n ? 0.4 : 0.24;
28334
29030
  },
28335
29031
  /** 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. */
28336
29032
  deferredQueue: () => K.breachPaintQueue,
29033
+ /* the destruction side is typed with the breach */
28337
29034
  cars: { model: carModel, group: carGroup, info: (k, seed) => {
28338
29035
  const m = carModel(k, seed);
28339
29036
  return m && { parts: m.parts.length, tris: m.tris, L: m.L, W: m.W, H: m.H };
@@ -28435,10 +29132,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28435
29132
  }
28436
29133
 
28437
29134
  // ../game-floorplan-residential/dist/index.js
28438
- var __defProp2 = Object.defineProperty;
29135
+ var __defProp3 = Object.defineProperty;
28439
29136
  var __export2 = (target, all) => {
28440
29137
  for (var name in all)
28441
- __defProp2(target, name, { get: all[name], enumerable: true });
29138
+ __defProp3(target, name, { get: all[name], enumerable: true });
28442
29139
  };
28443
29140
  var residentialItems = [
28444
29141
  { type: "sofa_3seat", category: "sofa", w: 2.1, d: 0.9, h: 0.85, color: { role: "fabric_main" } },