@adatechnology/game-items-three 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -29,6 +29,7 @@ var GameItemsThree = (() => {
29
29
  ITEM_FAMILIES: () => ITEM_FAMILIES,
30
30
  ITEM_PREFIX: () => ITEM_PREFIX,
31
31
  MODEL_BUDGET_DEVIATIONS: () => MODEL_BUDGET_DEVIATIONS,
32
+ OPENING_NAME: () => OPENING_NAME,
32
33
  ROW_LIMIT: () => ROW_LIMIT,
33
34
  RULER_HEIGHT: () => RULER_HEIGHT,
34
35
  RULER_ID: () => RULER_ID,
@@ -42,6 +43,7 @@ var GameItemsThree = (() => {
42
43
  WEAR_AMOUNT: () => WEAR_AMOUNT,
43
44
  WEAR_TAGS: () => WEAR_TAGS,
44
45
  WEAR_TARGET: () => WEAR_TARGET,
46
+ asLid: () => asLid,
45
47
  buildItem: () => buildItem,
46
48
  buildItemLod: () => buildItemLod,
47
49
  canonicalFrame: () => canonicalFrame,
@@ -60,14 +62,18 @@ var GameItemsThree = (() => {
60
62
  itemFamily: () => itemFamily,
61
63
  itemModelBuilder: () => itemModelBuilder,
62
64
  itemModelEntry: () => itemModelEntry,
65
+ itemOpening: () => itemOpening,
63
66
  itemThumbnail: () => itemThumbnail,
64
67
  itemThumbnailSvg: () => itemThumbnailSvg,
65
68
  listItemModels: () => listItemModels,
66
69
  mergeItem: () => mergeItem,
70
+ openItem: () => openItem,
67
71
  registerItemModel: () => registerItemModel,
68
72
  renderItemThumbnail: () => renderItemThumbnail,
73
+ setOpeningContents: () => setOpeningContents,
69
74
  setWear: () => setWear,
70
75
  shade: () => shade,
76
+ shapeDestruction: () => shapeDestruction,
71
77
  shapeOf: () => shapeOf,
72
78
  shapeThumbnailSvg: () => shapeThumbnailSvg,
73
79
  shelvesLayout: () => shelvesLayout,
@@ -75,6 +81,7 @@ var GameItemsThree = (() => {
75
81
  tagForDestruction: () => tagForDestruction,
76
82
  thumbnailPatch: () => thumbnailPatch,
77
83
  triangleBudgetOf: () => triangleBudgetOf,
84
+ turnItem: () => turnItem,
78
85
  unregisterItemModel: () => unregisterItemModel,
79
86
  wearableMaterials: () => wearableMaterials
80
87
  });
@@ -1724,6 +1731,90 @@ var GameItemsThree = (() => {
1724
1731
  return mesh2;
1725
1732
  });
1726
1733
  }
1734
+ var isTexture = (v) => !!v && typeof v === "object" && v.isTexture === true;
1735
+ function texturesOf(material, out) {
1736
+ for (const value of Object.values(material)) if (isTexture(value)) out.add(value);
1737
+ const uniforms = material.uniforms;
1738
+ if (uniforms) {
1739
+ for (const u of Object.values(uniforms)) if (isTexture(u?.value)) out.add(u.value);
1740
+ }
1741
+ }
1742
+ function collect(roots) {
1743
+ const geometries = /* @__PURE__ */ new Set();
1744
+ const materials = /* @__PURE__ */ new Set();
1745
+ const textures = /* @__PURE__ */ new Set();
1746
+ const skeletons = /* @__PURE__ */ new Set();
1747
+ for (const root of roots) {
1748
+ root.traverse((object2) => {
1749
+ const o = object2;
1750
+ if (o.geometry && typeof o.geometry.dispose === "function") geometries.add(o.geometry);
1751
+ if (o.skeleton && typeof o.skeleton.dispose === "function") skeletons.add(o.skeleton);
1752
+ const list2 = Array.isArray(o.material) ? o.material : o.material ? [o.material] : [];
1753
+ for (const m of list2) {
1754
+ if (!m || typeof m.dispose !== "function") continue;
1755
+ materials.add(m);
1756
+ texturesOf(m, textures);
1757
+ }
1758
+ });
1759
+ }
1760
+ return { geometries, materials, textures, skeletons };
1761
+ }
1762
+ var marked = /* @__PURE__ */ new WeakSet();
1763
+ var shared = (r) => r.userData?.shared === true || marked.has(r);
1764
+ function releaseObject3D(roots, options = {}) {
1765
+ const list2 = Array.isArray(roots) ? roots : [roots];
1766
+ const report = { geometries: 0, materials: 0, textures: 0 };
1767
+ if (list2.length === 0) return report;
1768
+ const found = collect(list2);
1769
+ const keepRoots = options.keep === void 0 ? [] : Array.isArray(options.keep) ? options.keep : [options.keep];
1770
+ const releasing = new Set(list2);
1771
+ for (const keep of keepRoots) {
1772
+ const walk = (o) => {
1773
+ if (releasing.has(o)) return;
1774
+ const owner = o;
1775
+ if (owner.geometry) found.geometries.delete(owner.geometry);
1776
+ if (owner.skeleton) found.skeletons.delete(owner.skeleton);
1777
+ const mats = Array.isArray(owner.material) ? owner.material : owner.material ? [owner.material] : [];
1778
+ for (const m of mats) {
1779
+ if (!m) continue;
1780
+ found.materials.delete(m);
1781
+ const t = /* @__PURE__ */ new Set();
1782
+ texturesOf(m, t);
1783
+ for (const x of t) found.textures.delete(x);
1784
+ }
1785
+ for (const c of o.children) walk(c);
1786
+ };
1787
+ walk(keep);
1788
+ }
1789
+ for (const g of found.geometries) {
1790
+ if (shared(g)) continue;
1791
+ g.dispose();
1792
+ report.geometries++;
1793
+ }
1794
+ for (const m of found.materials) {
1795
+ if (shared(m)) continue;
1796
+ m.dispose();
1797
+ report.materials++;
1798
+ }
1799
+ for (const t of found.textures) {
1800
+ if (shared(t)) continue;
1801
+ t.dispose();
1802
+ report.textures++;
1803
+ }
1804
+ for (const s of found.skeletons) s.dispose();
1805
+ return report;
1806
+ }
1807
+ function discardObject3D(objects, options = {}) {
1808
+ const list2 = Array.isArray(objects) ? objects : [objects];
1809
+ const keep = options.keep === void 0 ? [] : Array.isArray(options.keep) ? [...options.keep] : [options.keep];
1810
+ for (const object2 of list2) {
1811
+ let top = object2;
1812
+ while (top.parent) top = top.parent;
1813
+ object2.removeFromParent();
1814
+ if (top !== object2 && !keep.includes(top)) keep.push(top);
1815
+ }
1816
+ return releaseObject3D(list2, { keep });
1817
+ }
1727
1818
 
1728
1819
  // src/kit.ts
1729
1820
  var WEAR_TAGS = ["metal", "wood", "cloth", "plastic", "paper", "food", "glass"];
@@ -2958,6 +3049,12 @@ var GameItemsThree = (() => {
2958
3049
  liquid: "honey",
2959
3050
  fill: 0.9
2960
3051
  }
3052
+ },
3053
+ shapes: {
3054
+ box: {
3055
+ hollow: true,
3056
+ welded: true
3057
+ }
2961
3058
  }
2962
3059
  };
2963
3060
 
@@ -2973,6 +3070,8 @@ var GameItemsThree = (() => {
2973
3070
  };
2974
3071
  var FAMILIES = destruction_default.families;
2975
3072
  var CONTENTS = destruction_default.contents;
3073
+ var SHAPES2 = destruction_default.shapes;
3074
+ var shapeDestruction = (shapeId) => SHAPES2[shapeId];
2976
3075
  var FAMILY_OF_MODEL = new Map(Object.entries(FAMILIES).flatMap(([family, entry2]) => entry2.models.map((model) => [model, family])));
2977
3076
  var itemFamily = (modelId) => FAMILY_OF_MODEL.get(modelId);
2978
3077
  var itemDestruction = (modelId) => {
@@ -3088,9 +3187,9 @@ var GameItemsThree = (() => {
3088
3187
  root.userData.tessellationTriangles = added;
3089
3188
  }
3090
3189
  function tagForDestruction(root, options = {}) {
3091
- const { modelId, weight, size, three } = options;
3190
+ const { modelId, shapeId, weight, size, powder, three } = options;
3092
3191
  if (weight !== void 0 && weight > 0) root.userData.destructionMass = weight;
3093
- const rule = modelId === void 0 ? void 0 : itemDestruction(modelId);
3192
+ const rule = modelId !== void 0 ? itemDestruction(modelId) : shapeId !== void 0 ? shapeDestruction(shapeId) : void 0;
3094
3193
  if (rule?.tessellate) tessellateShapes(root, rule.tessellate, three);
3095
3194
  const solid = [];
3096
3195
  root.traverse((object2) => {
@@ -3105,6 +3204,7 @@ var GameItemsThree = (() => {
3105
3204
  return;
3106
3205
  }
3107
3206
  if (rule?.hollow) mesh2.userData.hollow = true;
3207
+ if (powder) mesh2.userData.destructionPowder = { color: powder.color };
3108
3208
  solid.push(mesh2);
3109
3209
  });
3110
3210
  if (!rule?.welded || solid.length < 2) return;
@@ -5587,8 +5687,168 @@ var GameItemsThree = (() => {
5587
5687
  return G(mesh2(cyl(0.32, 0.32, 0.52), m), mesh2(cyl(0.326, 0.326, 0.34, 14), food(10172964)), mesh2(cyl(0.33, 0.33, 0.06), paper2(14861162), [0, 0.02, 0]), mesh2(torus2(0.31, 0.025), m, [0, 0.26, 0], [Math.PI / 2, 0, 0]), mesh2(torus2(0.31, 0.025), m, [0, -0.26, 0], [Math.PI / 2, 0, 0]));
5588
5688
  };
5589
5689
 
5690
+ // src/data/opening.json
5691
+ var opening_default = {
5692
+ families: {
5693
+ drink_can: { style: "pull_tab" },
5694
+ food_tin: { style: "cut_lid" }
5695
+ },
5696
+ models: {
5697
+ empty_can: { style: "none" },
5698
+ canned_beans: { food: "#7a2e1c" },
5699
+ canned_corn_and_peas: { food: "#c7b03c" },
5700
+ canned_sausages: { food: "#c98d5c" },
5701
+ canned_sardines: { style: "peel_lid", food: "#8e979c" },
5702
+ condensed_milk: { food: "#e3cf9c" },
5703
+ energy_drink: { style: "pull_tab" },
5704
+ honey_jar: { style: "screw_cap", food: "#d99a1c" },
5705
+ home_preserves: { style: "screw_cap", food: "#8e1f3a" },
5706
+ cooking_oil: { style: "screw_cap", food: "#e3b830" },
5707
+ water_bottle: { style: "screw_cap" },
5708
+ water_jug_5l: { style: "screw_cap" },
5709
+ dirty_water: { style: "screw_cap" },
5710
+ sports_drink: { style: "screw_cap" },
5711
+ coconut_water: { style: "screw_cap" },
5712
+ cachaca: { style: "screw_cap" },
5713
+ communion_wine: { style: "screw_cap" }
5714
+ }
5715
+ };
5716
+
5717
+ // src/opening.ts
5718
+ var FAMILIES2 = opening_default.families;
5719
+ var MODELS = opening_default.models;
5720
+ var itemOpening = (modelId) => {
5721
+ const family = itemFamily(modelId);
5722
+ const row = { ...family === void 0 ? {} : FAMILIES2[family], ...MODELS[modelId] };
5723
+ if (row.style === void 0 || row.style === "none") return void 0;
5724
+ return { style: row.style, ...row.food === void 0 ? {} : { food: row.food } };
5725
+ };
5726
+ var OPENING_NAME = "opening";
5727
+ var INSIDE = 1315086;
5728
+ var CUT_EDGE = 14278114;
5729
+ var LID = 12172996;
5730
+ var isLid = (o) => o.userData.itemLid === true;
5731
+ var asLid = (mesh2) => {
5732
+ mesh2.userData.itemLid = true;
5733
+ return mesh2;
5734
+ };
5735
+ var localBox = (T2, root, only) => {
5736
+ root.updateMatrixWorld(true);
5737
+ const toRoot = new T2.Matrix4().copy(root.matrixWorld).invert();
5738
+ const box4 = new T2.Box3();
5739
+ const part = new T2.Box3();
5740
+ const m = new T2.Matrix4();
5741
+ root.traverse((o) => {
5742
+ const mesh2 = o;
5743
+ if (!mesh2.isMesh || mesh2.userData.destructionDebris || mesh2.name === OPENING_NAME || mesh2.parent?.name === OPENING_NAME) return;
5744
+ if (only && !only(mesh2)) return;
5745
+ if (!mesh2.geometry.boundingBox) mesh2.geometry.computeBoundingBox();
5746
+ part.copy(mesh2.geometry.boundingBox).applyMatrix4(m.multiplyMatrices(toRoot, mesh2.matrixWorld));
5747
+ box4.union(part);
5748
+ });
5749
+ return box4;
5750
+ };
5751
+ function openItem(T2, root, modelId) {
5752
+ const look = itemOpening(modelId);
5753
+ if (!look) return false;
5754
+ if (root.userData.itemOpened) return true;
5755
+ const box4 = look.style === "screw_cap" ? localBox(T2, root, isLid) : localBox(T2, root);
5756
+ if (box4.isEmpty()) return false;
5757
+ const size = box4.getSize(new T2.Vector3());
5758
+ const centre = box4.getCenter(new T2.Vector3());
5759
+ const top = look.style === "screw_cap" ? box4.min.y : box4.max.y;
5760
+ const lift = size.y * 3e-3;
5761
+ const sheet = Math.max(size.y * 6e-3, 1e-4);
5762
+ const group = new T2.Group();
5763
+ group.name = OPENING_NAME;
5764
+ group.position.set(centre.x, top, centre.z);
5765
+ const material = (color2, metal = 0) => new T2.MeshStandardMaterial({ color: color2, metalness: metal, roughness: metal ? 0.45 : 0.85, polygonOffset: true, polygonOffsetFactor: -2, polygonOffsetUnits: -2 });
5766
+ const add = (geometry, mat, y, parent = group) => {
5767
+ const mesh2 = new T2.Mesh(geometry, mat);
5768
+ mesh2.position.y = y;
5769
+ mesh2.renderOrder = 2;
5770
+ mesh2.userData.destructionDebris = true;
5771
+ mesh2.userData.itemOpening = true;
5772
+ parent.add(mesh2);
5773
+ return mesh2;
5774
+ };
5775
+ const flat = (geometry) => geometry.rotateX(-Math.PI / 2);
5776
+ const food = look.food ?? INSIDE;
5777
+ if (look.style === "screw_cap") {
5778
+ const r = Math.min(size.x, size.z) / 2;
5779
+ root.traverse((o) => isLid(o) && (o.visible = false));
5780
+ add(flat(new T2.CircleGeometry(r * 0.85, 24)), material(INSIDE), lift);
5781
+ if (look.food !== void 0) add(flat(new T2.CircleGeometry(r * 0.7, 24)), material(look.food), lift * 2).userData.itemFood = true;
5782
+ } else if (look.style === "pull_tab") {
5783
+ const r = Math.min(size.x, size.z) / 2;
5784
+ const mouth = add(flat(new T2.CircleGeometry(r * 0.2, 24)), material(INSIDE), lift);
5785
+ mouth.scale.set(1.15, 1, 0.85);
5786
+ mouth.position.z = r * 0.52;
5787
+ } else if (look.style === "cut_lid") {
5788
+ const r = Math.min(size.x, size.z) / 2;
5789
+ add(flat(new T2.CircleGeometry(r * 0.88, 40)), material(INSIDE), lift);
5790
+ add(flat(new T2.CircleGeometry(r * 0.76, 40)), material(food), lift * 2).userData.itemFood = true;
5791
+ add(flat(new T2.RingGeometry(r * 0.86, r * 0.9, 40)), material(CUT_EDGE, 0.9), lift * 3);
5792
+ const hinge = new T2.Group();
5793
+ hinge.position.set(0, lift, -r * 0.86);
5794
+ hinge.rotation.x = -1.95;
5795
+ group.add(hinge);
5796
+ const lid = add(new T2.CylinderGeometry(r * 0.86, r * 0.86, sheet, 40), material(LID, 0.4), 0, hinge);
5797
+ lid.position.z = r * 0.86;
5798
+ } else {
5799
+ const long = size.x >= size.z ? "x" : "z";
5800
+ const length = Math.max(size.x, size.z);
5801
+ const width = Math.min(size.x, size.z);
5802
+ const plane2 = (a, b) => flat(long === "x" ? new T2.PlaneGeometry(a, b) : new T2.PlaneGeometry(b, a));
5803
+ add(plane2(length * 0.92, width * 0.86), material(INSIDE), lift);
5804
+ add(plane2(length * 0.84, width * 0.76), material(food), lift * 2).userData.itemFood = true;
5805
+ const hinge = new T2.Group();
5806
+ const end = length * 0.46;
5807
+ if (long === "x") {
5808
+ hinge.position.set(end, lift, 0);
5809
+ hinge.rotation.z = -1.7;
5810
+ } else {
5811
+ hinge.position.set(0, lift, end);
5812
+ hinge.rotation.x = 1.7;
5813
+ }
5814
+ group.add(hinge);
5815
+ const lid = add(long === "x" ? new T2.BoxGeometry(length * 0.9, sheet, width * 0.84) : new T2.BoxGeometry(width * 0.84, sheet, length * 0.9), material(LID, 0.4), 0, hinge);
5816
+ if (long === "x") lid.position.x = -length * 0.45;
5817
+ else lid.position.z = -length * 0.45;
5818
+ }
5819
+ root.add(group);
5820
+ root.userData.itemOpened = true;
5821
+ return true;
5822
+ }
5823
+ var CAP_OFF = 1.6;
5824
+ function turnItem(root, modelId, state) {
5825
+ if (itemOpening(modelId)?.style !== "screw_cap") return false;
5826
+ root.traverse((o) => {
5827
+ var _a;
5828
+ if (!isLid(o)) return;
5829
+ const mesh2 = o;
5830
+ const base = (_a = mesh2.userData).lidBase ?? (_a.lidBase = { y: mesh2.position.y, turn: mesh2.rotation.y });
5831
+ if (!mesh2.geometry.boundingBox) mesh2.geometry.computeBoundingBox();
5832
+ const height = (mesh2.geometry.boundingBox.max.y - mesh2.geometry.boundingBox.min.y) * mesh2.scale.y;
5833
+ mesh2.rotation.y = base.turn + state.turned;
5834
+ mesh2.position.y = base.y + Math.min(1, Math.max(0, state.lift)) * height * CAP_OFF;
5835
+ });
5836
+ return true;
5837
+ }
5838
+ function setOpeningContents(root, share) {
5839
+ const opening = root.getObjectByName(OPENING_NAME);
5840
+ if (!opening) return;
5841
+ const left = Math.max(0, Math.min(1, share));
5842
+ opening.traverse((o) => {
5843
+ if (!o.userData.itemFood) return;
5844
+ o.visible = left > 0.02;
5845
+ const k = 0.35 + 0.65 * left;
5846
+ o.scale.set(k, 1, k);
5847
+ });
5848
+ }
5849
+
5590
5850
  // src/models/water-bottle.ts
5591
- var waterBottle = ({ mesh: mesh2, cyl, lathe: lathe2, G, plastic, paper: paper2, glass }) => G(mesh2(lathe2([[0, -0.6], [0.2, -0.6], [0.22, -0.5], [0.22, 0.2], [0.19, 0.32], [0.09, 0.45], [0.08, 0.55], [0, 0.55]]), glass(9421788, 0.55)), mesh2(cyl(0.085, 0.085, 0.1, 12), plastic(2907530), [0, 0.6, 0]), mesh2(cyl(0.225, 0.225, 0.22, 16), paper2(15330543), [0, -0.15, 0]), mesh2(cyl(0.226, 0.226, 0.05, 16), plastic(3831976), [0, -0.12, 0]));
5851
+ var waterBottle = ({ mesh: mesh2, cyl, lathe: lathe2, G, plastic, paper: paper2, glass }) => G(mesh2(lathe2([[0, -0.6], [0.2, -0.6], [0.22, -0.5], [0.22, 0.2], [0.19, 0.32], [0.09, 0.45], [0.08, 0.55], [0, 0.55]]), glass(9421788, 0.55)), asLid(mesh2(cyl(0.085, 0.085, 0.1, 12), plastic(2907530), [0, 0.6, 0])), mesh2(cyl(0.225, 0.225, 0.22, 16), paper2(15330543), [0, -0.15, 0]), mesh2(cyl(0.226, 0.226, 0.05, 16), plastic(3831976), [0, -0.12, 0]));
5592
5852
 
5593
5853
  // src/models/rice.ts
5594
5854
  var rice = ({ mesh: mesh2, bx, G, paper: paper2, food }) => G(mesh2(bx(0.7, 0.95, 0.28), paper2(15129792)), mesh2(bx(0.72, 0.12, 0.1), paper2(14010792), [0, 0.52, 0]), mesh2(bx(0.5, 0.3, 0.02), food(11883039), [0, 0.05, 0.15]), mesh2(bx(0.3, 0.1, 0.02), paper2(4160069), [0, -0.25, 0.15]));
@@ -5597,7 +5857,7 @@ var GameItemsThree = (() => {
5597
5857
  var militaryRation = ({ mesh: mesh2, bx, G, plastic, paper: paper2 }) => G(mesh2(bx(0.75, 1, 0.22), plastic(5923142)), mesh2(bx(0.77, 0.1, 0.23), plastic(4672823), [0, 0.48, 0]), mesh2(bx(0.5, 0.14, 0.01), paper2(2237727), [0, 0.18, 0.115]), mesh2(bx(0.36, 0.06, 0.01), paper2(2237727), [0, -0.02, 0.115]));
5598
5858
 
5599
5859
  // src/models/cachaca.ts
5600
- var cachaca = ({ mesh: mesh2, cyl, lathe: lathe2, G, wood, paper: paper2, food, glass }) => G(mesh2(lathe2([[0, -0.6], [0.25, -0.6], [0.27, -0.52], [0.27, 0.1], [0.2, 0.25], [0.09, 0.35], [0.09, 0.58], [0, 0.58]]), glass(12749354, 0.78)), mesh2(cyl(0.08, 0.07, 0.14, 10), wood(9071172), [0, 0.64, 0]), mesh2(cyl(0.275, 0.275, 0.34, 16), paper2(15327692), [0, -0.25, 0]), mesh2(cyl(0.276, 0.276, 0.06, 16), food(8007455), [0, -0.15, 0]));
5860
+ var cachaca = ({ mesh: mesh2, cyl, lathe: lathe2, G, wood, paper: paper2, food, glass }) => G(mesh2(lathe2([[0, -0.6], [0.25, -0.6], [0.27, -0.52], [0.27, 0.1], [0.2, 0.25], [0.09, 0.35], [0.09, 0.58], [0, 0.58]]), glass(12749354, 0.78)), asLid(mesh2(cyl(0.08, 0.07, 0.14, 10), wood(9071172), [0, 0.64, 0])), mesh2(cyl(0.275, 0.275, 0.34, 16), paper2(15327692), [0, -0.25, 0]), mesh2(cyl(0.276, 0.276, 0.06, 16), food(8007455), [0, -0.15, 0]));
5601
5861
 
5602
5862
  // src/models/first-aid-kit.ts
5603
5863
  var firstAidKit = ({ mesh: mesh2, bx, torus: torus2, G, plastic }) => {
@@ -5813,7 +6073,7 @@ var GameItemsThree = (() => {
5813
6073
  mesh2(cyl(0.41, 0.41, 0.86, 12), food(9314106), [0, -0.2, 0]),
5814
6074
  mesh2(cyl(0.34, 0.445, 0.12, 12), glass(13625070, 0.5), [0, 0.39, 0]),
5815
6075
  mesh2(cyl(0.34, 0.34, 0.05, 12), glass(13625070, 0.5), [0, 0.475, 0]),
5816
- mesh2(cyl(0.38, 0.38, 0.15, 12), metal(12163644), [0, 0.575, 0]),
6076
+ asLid(mesh2(cyl(0.38, 0.38, 0.15, 12), metal(12163644), [0, 0.575, 0])),
5817
6077
  mesh2(cyl(0.45, 0.45, 0.4, 12), paper2(15327172), [0, -0.2, 0]),
5818
6078
  mesh2(cyl(0.452, 0.452, 0.08, 12), cloth2(10172986), [0, -0.2, 0])
5819
6079
  );
@@ -6018,7 +6278,7 @@ var GameItemsThree = (() => {
6018
6278
  mesh2(cyl(0.395, 0.395, 0.68, 12), glass(14925936, 0.55), [0, -0.16, 0]),
6019
6279
  mesh2(cyl(0.37, 0.37, 0.6, 12), food(14260764), [0, -0.2, 0]),
6020
6280
  mesh2(cyl(0.3, 0.395, 0.14, 12), glass(14925936, 0.55), [0, 0.25, 0]),
6021
- mesh2(cyl(0.3, 0.3, 0.18, 12), metal(7031324), [0, 0.41, 0]),
6281
+ asLid(mesh2(cyl(0.3, 0.3, 0.18, 12), metal(7031324), [0, 0.41, 0])),
6022
6282
  mesh2(cyl(0.4, 0.4, 0.34, 12), paper2(15853512), [0, -0.2, 0]),
6023
6283
  mesh2(cyl(0.402, 0.402, 0.05, 12), paper2(9067028), [0, -0.1, 0]),
6024
6284
  mesh2(cyl(0.402, 0.402, 0.05, 12), paper2(9067028), [0, -0.3, 0])
@@ -6122,7 +6382,7 @@ var GameItemsThree = (() => {
6122
6382
  mesh2(cyl(0.345, 0.345, 1.7, 12), glass(14923824, 0.65), [0, -0.45, 0]),
6123
6383
  mesh2(cyl(0.12, 0.345, 0.5, 12), glass(14923824, 0.65), [0, 0.65, 0]),
6124
6384
  mesh2(cyl(0.12, 0.12, 0.25, 12), glass(14923824, 0.65), [0, 1.025, 0]),
6125
- mesh2(cyl(0.14, 0.14, 0.15, 12), plastic(4160042), [0, 1.225, 0]),
6385
+ asLid(mesh2(cyl(0.14, 0.14, 0.15, 12), plastic(4160042), [0, 1.225, 0])),
6126
6386
  mesh2(cyl(0.35, 0.35, 0.8, 12), paper2(15853512), [0, -0.5, 0]),
6127
6387
  mesh2(cyl(0.352, 0.352, 0.2, 12), paper2(4160042), [0, -0.5, 0])
6128
6388
  );
@@ -6160,7 +6420,7 @@ var GameItemsThree = (() => {
6160
6420
  const body = mesh2(bx(1.5, 2.3, 1.5), glass(10473710, 0.75), [0, -0.5, 0]);
6161
6421
  const shoulder = mesh2(bx(1.2, 0.45, 1.2), glass(10473710, 0.75), [0, 0.875, 0]);
6162
6422
  const neck = mesh2(cyl(0.34, 0.34, 0.3, 12), dark, [0, 1.25, 0]);
6163
- const cap = mesh2(cyl(0.4, 0.4, 0.25, 12), dark, [0, 1.525, 0]);
6423
+ const cap = asLid(mesh2(cyl(0.4, 0.4, 0.25, 12), dark, [0, 1.525, 0]));
6164
6424
  const grip = mesh2(bx(0.16, 0.9, 0.3), dark, [1.07, 0.6, 0]);
6165
6425
  const upperBar = mesh2(bx(0.45, 0.16, 0.3), dark, [0.925, 0.97, 0]);
6166
6426
  const lowerBar = mesh2(bx(0.45, 0.16, 0.3), dark, [0.925, 0.23, 0]);
@@ -6175,7 +6435,7 @@ var GameItemsThree = (() => {
6175
6435
  const label = mesh2(cyl(0.332, 0.332, 0.7, 12), paper2(1448738), [0, -0.12, 0]);
6176
6436
  const stripe = mesh2(cyl(0.332, 0.332, 0.1, 12), paper2(15753232), [0, 0.28, 0]);
6177
6437
  const collar = mesh2(cyl(0.2, 0.2, 0.04, 12), plastic(15263976), [0, 0.705, 0]);
6178
- const cap = mesh2(cyl(0.19, 0.19, 0.2, 12), plastic(15753232), [0, 0.815, 0]);
6438
+ const cap = asLid(mesh2(cyl(0.19, 0.19, 0.2, 12), plastic(15753232), [0, 0.815, 0]));
6179
6439
  return G(bottle2, label, stripe, collar, cap);
6180
6440
  };
6181
6441
 
@@ -6222,7 +6482,7 @@ var GameItemsThree = (() => {
6222
6482
  const goldBand = mesh2(cyl(0.382, 0.382, 0.05, 12), metal(11896880), [0, 0.075, 0]);
6223
6483
  const crossUpright = mesh2(bx(0.06, 0.26, 0.02), paper2(8003371), [0, -0.35, 0.375]);
6224
6484
  const crossArm = mesh2(bx(0.18, 0.06, 0.02), paper2(8003371), [0, -0.3, 0.375]);
6225
- const foil = mesh2(cyl(0.15, 0.15, 0.46, 12), metal(11896880), [0, 1.27, 0]);
6485
+ const foil = asLid(mesh2(cyl(0.15, 0.15, 0.46, 12), metal(11896880), [0, 1.27, 0]));
6226
6486
  return G(bottle2, label, goldBand, crossUpright, crossArm, foil);
6227
6487
  };
6228
6488
 
@@ -6233,7 +6493,7 @@ var GameItemsThree = (() => {
6233
6493
  const nut = mesh2(cyl(0.11, 0.11, 0.03, 10), paper2(7031339), [0, -0.12, 0.285], [Math.PI / 2, 0, 0]);
6234
6494
  const leafLeft = mesh2(bx(0.2, 0.05, 0.01), paper2(15135448), [-0.12, 0.08, 0.292], [0, 0, 0.5]);
6235
6495
  const leafRight = mesh2(bx(0.2, 0.05, 0.01), paper2(15135448), [0.12, 0.08, 0.292], [0, 0, -0.5]);
6236
- const cap = mesh2(cyl(0.14, 0.14, 0.2, 12), plastic(4165450), [0, 0.75, 0]);
6496
+ const cap = asLid(mesh2(cyl(0.14, 0.14, 0.2, 12), plastic(4165450), [0, 0.75, 0]));
6237
6497
  return G(bottle2, label, nut, leafLeft, leafRight, cap);
6238
6498
  };
6239
6499
 
@@ -6243,7 +6503,7 @@ var GameItemsThree = (() => {
6243
6503
  const murk = mesh2(lathe2([[0, -0.89], [0.27, -0.89], [0.315, -0.84], [0.315, 0.1], [0, 0.1]], 12), food(7035444));
6244
6504
  const sediment = mesh2(cyl(0.31, 0.27, 0.12, 8), food(4865314), [0, -0.82, 0]);
6245
6505
  const label = mesh2(cyl(0.332, 0.332, 0.22, 12), paper2(13617588), [0, 0.38, 0]);
6246
- const cap = mesh2(cyl(0.19, 0.19, 0.2, 8), plastic(5922920), [0, 0.815, 0]);
6506
+ const cap = asLid(mesh2(cyl(0.19, 0.19, 0.2, 8), plastic(5922920), [0, 0.815, 0]));
6247
6507
  return G(bottle2, murk, sediment, label, cap);
6248
6508
  };
6249
6509
 
@@ -9232,7 +9492,7 @@ var GameItemsThree = (() => {
9232
9492
  const materials = kit.materials.slice(first);
9233
9493
  if (options.wear) setWear(materials, options.wear);
9234
9494
  root.userData.wear = options.wear ?? 0;
9235
- if (options.destructible) tagForDestruction(root, { ...kind === "model" && item.model !== void 0 ? { modelId: item.model } : {}, ...item.weight === void 0 ? {} : { weight: item.weight }, size: item.size, three: T2 });
9495
+ if (options.destructible) tagForDestruction(root, { ...kind === "model" && item.model !== void 0 ? { modelId: item.model } : {}, ...shape === void 0 ? {} : { shapeId: shape }, ...item.weight === void 0 ? {} : { weight: item.weight }, size: item.size, ...item.powder ? { powder: item.powder } : {}, three: T2 });
9236
9496
  markKitOrigin(root, { owner: "game-items-three", kind: "item", id: item.id, ...kind === "shape" ? { standIn: true } : {} });
9237
9497
  return { root, kind, ...shape ? { shape } : {}, size: item.size, materials };
9238
9498
  }
@@ -15147,6 +15407,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
15147
15407
  var FLAMMABLE_FLUIDS = ["gas", "fuel"];
15148
15408
  var VENT_DIAMETER = 8e-3;
15149
15409
  var FLAME_LIGHTS_LEAK_C = 470;
15410
+ var RESTING_HOLD_COS = Math.cos(Math.PI / 6);
15150
15411
  var BREACH_RADIUS = 0.55;
15151
15412
  var BREACH_BLAST_FACTOR = 6;
15152
15413
  var BREACH_AREA = 0.25;
@@ -15162,6 +15423,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
15162
15423
  var BREACH_GRID_CAP = 4096;
15163
15424
  var CHIP_ENERGY = 200;
15164
15425
  var CHIP_SPLASH = 0.5;
15426
+ var CRATER_SPENT = 0.6;
15427
+ var EDGE_REACH = 1.5;
15165
15428
  var BAR_BOW = 0.08;
15166
15429
  var BULLET_JOINT_SPAN = 0.3;
15167
15430
  var CUT_SLICE = 1;
@@ -15182,12 +15445,22 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
15182
15445
  const cells = p.st.chipped;
15183
15446
  if (!cells?.length) return 0;
15184
15447
  const [u, v] = planeAxes(p.thin);
15185
- const along = p.dims[u] >= p.dims[v] ? u : v;
15448
+ const role = p.spec.structure?.role;
15449
+ const up = rotateVec(p.q, [0, 0, 0].map((_, k) => k === v ? 1 : 0));
15450
+ const upright = Math.abs(up[1]) > 0.7 ? v : Math.abs(rotateVec(p.q, [0, 0, 0].map((_, k) => k === u ? 1 : 0))[1]) > 0.7 ? u : -1;
15451
+ const along = (role === "wall" || role === "partition" || role === "column") && upright >= 0 ? upright : p.dims[u] >= p.dims[v] ? u : v;
15186
15452
  const across2 = along === u ? v : u;
15187
15453
  let worst = 0;
15188
15454
  for (const c of cells) {
15189
- let gone = 0;
15190
- for (const d of cells) if (Math.abs(d.center[along] - c.center[along]) < d.size[along] / 2 + 1e-6) gone += d.size[across2];
15455
+ const spans = [];
15456
+ for (const d of cells) if (Math.abs(d.center[along] - c.center[along]) < d.size[along] / 2 + 1e-6) spans.push([d.center[across2] - d.size[across2] / 2, d.center[across2] + d.size[across2] / 2]);
15457
+ spans.sort((a, b) => a[0] - b[0]);
15458
+ let gone = 0, end = -Infinity;
15459
+ for (const [a, b] of spans) {
15460
+ if (b <= end) continue;
15461
+ gone += b - Math.max(a, end);
15462
+ end = b;
15463
+ }
15191
15464
  worst = Math.max(worst, gone / Math.max(p.dims[across2], 1e-6));
15192
15465
  }
15193
15466
  return Math.min(1, worst);
@@ -15483,7 +15756,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
15483
15756
  if (k < 0 || j.spec.kind !== "tie") return k;
15484
15757
  return partXf(o, o.parts[k]).c[1] > partXf(o, o.parts[r]).c[1] + 1e-6 ? k : -1;
15485
15758
  };
15759
+ let poseVersion = 0;
15760
+ const contactMemo = /* @__PURE__ */ new WeakMap();
15486
15761
  const contactBox = (p, support) => {
15762
+ let byTouching = contactMemo.get(p);
15763
+ if (!byTouching) contactMemo.set(p, byTouching = /* @__PURE__ */ new Map());
15764
+ const known = byTouching.get(support);
15765
+ if (known && known.version === poseVersion) return known.box;
15766
+ const box4 = measureContact(p, support);
15767
+ byTouching.set(support, { version: poseVersion, box: box4 });
15768
+ return box4;
15769
+ };
15770
+ const measureContact = (p, support) => {
15487
15771
  const A = aabbOf(p.spec.shape, p.pos, p.q), B = aabbOf(support.spec.shape, support.pos, support.q);
15488
15772
  const lo = [0, 0, 0], hi = [0, 0, 0];
15489
15773
  for (let k = 0; k < 3; k++) {
@@ -16278,7 +16562,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16278
16562
  p.st.holes.push(hole);
16279
16563
  if (p.st.holes.length > maxHoles) p.st.holes.shift();
16280
16564
  markDamaged(p);
16281
- emit({ ...base(o, src), type: "hole", part: p.spec.id, hole, worldPoint: wp, ...exit ? { exitPoint: exit } : {} });
16565
+ emit({ ...base(o, src), type: "hole", part: p.spec.id, hole, worldPoint: wp, ...exit ? { exitPoint: exit } : {}, ...p.spec.powder ? { powder: { ...p.spec.powder } } : {} });
16282
16566
  setStage(o, p, 1, {}, src);
16283
16567
  return hole;
16284
16568
  };
@@ -16295,6 +16579,22 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16295
16579
  const detachEvents = (o, opened, by, src) => {
16296
16580
  for (const j of opened) emit({ ...base(o, src), type: "detach", joint: j.spec.id, parts: [j.spec.a, j.spec.b], by, groups: o.st.groups.map((g) => [...g]) });
16297
16581
  };
16582
+ const slideOffResting = (o, rotation) => {
16583
+ const upY = 1 - 2 * (rotation[0] * rotation[0] + rotation[2] * rotation[2]);
16584
+ if (upY >= RESTING_HOLD_COS) return;
16585
+ const opened = o.joints.filter((j) => j.spec.kind === "resting" && !j.st.open);
16586
+ if (opened.length === 0) return;
16587
+ run(() => {
16588
+ for (const j of opened) {
16589
+ j.st.open = true;
16590
+ j.st.openedBy = "break";
16591
+ }
16592
+ solveStructure(o);
16593
+ recomputeGroups(o);
16594
+ detachEvents(o, opened, "break");
16595
+ collapseCheck(o);
16596
+ });
16597
+ };
16298
16598
  const checkDestroyed = (o, src) => {
16299
16599
  if (!o.st.destroyed && o.parts.length > 0 && o.parts.every(isLost)) {
16300
16600
  o.st.destroyed = true;
@@ -16395,7 +16695,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16395
16695
  const localHolesOf = (p) => p.st.holes.map((h) => ({ point: toLocal(p.pos, p.q, h.point), normal: rotateVec(quat.conjugate(p.q), h.normal), diameter: h.diameter }));
16396
16696
  const unitsOf2 = (p) => p.spec.units ?? { size: [p.mat.fragmentSize?.[1] ?? 0.2, p.mat.fragmentSize?.[1] ?? 0.2, p.thickness], bond: "stack" };
16397
16697
  const FRAGMENT_SHAPE = { shatter: "shard", splinter: "splinter", tear: "scrap" };
16398
- const cellFragments = (o, p, cells, hitW, dir, speed, mass, tag) => {
16698
+ const cellFragments = (o, p, cells, hitW, dir, speed, mass, tag, inner = false) => {
16399
16699
  const { c, q } = partXf(o, p);
16400
16700
  const holes = p.st.holes.length > 0 ? localHolesOf(p) : [];
16401
16701
  const [u, v] = planeAxes(p.thin);
@@ -16419,7 +16719,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16419
16719
  velocity: [dv[0] * k, dv[1] * k + 0.5 * rnd(), dv[2] * k],
16420
16720
  angularVelocity: [(rnd() - 0.5) * 8, (rnd() - 0.5) * 8, (rnd() - 0.5) * 8],
16421
16721
  mass: mass * faceArea(cell) / total,
16422
- ...marks.length > 0 ? { marks } : {}
16722
+ ...marks.length > 0 ? { marks } : {},
16723
+ ...inner ? { inner } : {}
16423
16724
  };
16424
16725
  });
16425
16726
  };
@@ -16460,7 +16761,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16460
16761
  return cells.some((c) => Math.abs(lp[u] - c.center[u]) <= c.size[u] / 2 && Math.abs(lp[v] - c.center[v]) <= c.size[v] / 2);
16461
16762
  };
16462
16763
  const chipUnits = (o, p, kind, wp, hitEnergy, dir, radius, src) => {
16463
- var _a, _b;
16764
+ var _a, _b, _c;
16464
16765
  if (!p.spec.units || !p.staged || chipEnergy <= 0 || p.st.stripped || isLost(p) || (p.st.stage ?? 0) >= 2) return;
16465
16766
  const rule = p.mat.hits?.[kind];
16466
16767
  const perKg = rule?.unitJoules ?? chipEnergy;
@@ -16470,7 +16771,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16470
16771
  const lp = toLocal(p.pos, p.q, objLocal(o, wp));
16471
16772
  const grid = gridOf(p);
16472
16773
  const worn = (_a = p.rt).chips ?? (_a.chips = {});
16774
+ const cut = (_b = p.rt).craters ?? (_b.craters = {});
16473
16775
  const out = [];
16776
+ const shot = kind === "ballistic";
16474
16777
  for (let i = 0; i < grid.length; i++) {
16475
16778
  const cell = grid[i];
16476
16779
  if (worn[i] === -1) continue;
@@ -16483,18 +16786,42 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16483
16786
  worn[i] = total;
16484
16787
  continue;
16485
16788
  }
16486
- worn[i] = -1;
16487
- out.push(cell);
16789
+ if (!shot) {
16790
+ worn[i] = -1;
16791
+ out.push(cell);
16792
+ continue;
16793
+ }
16794
+ const size = [cell.size[0], cell.size[1], cell.size[2]];
16795
+ const center = [cell.center[0], cell.center[1], cell.center[2]];
16796
+ for (const a of [u, v]) {
16797
+ const w = Math.min(cell.size[a], craterAcross(hitEnergy) * (0.85 + 0.3 * rnd()));
16798
+ const lo = cell.center[a] - cell.size[a] / 2 + w / 2, hi = cell.center[a] + cell.size[a] / 2 - w / 2;
16799
+ size[a] = w;
16800
+ center[a] = clamp2(lp[a], lo, hi);
16801
+ const [from, to] = tornToEdge({ p, cell, a, b: a === u ? v : u, at: lp[a], crater: [center[a] - w / 2, center[a] + w / 2], reach: w * EDGE_REACH, gone: (k) => worn[k] === -1 });
16802
+ size[a] = to - from;
16803
+ center[a] = (from + to) / 2;
16804
+ }
16805
+ const taken2 = (cut[i] ?? 0) + size[u] * size[v];
16806
+ if (taken2 >= cell.size[u] * cell.size[v] * CRATER_SPENT) {
16807
+ worn[i] = -1;
16808
+ out.push({ ...cell, crater: true });
16809
+ continue;
16810
+ }
16811
+ worn[i] = 0;
16812
+ cut[i] = taken2;
16813
+ out.push({ center, size, crater: true });
16488
16814
  }
16489
16815
  if (out.length === 0) return;
16490
16816
  const { c, q } = partXf(o, p);
16491
- const chipped = (_b = p.st).chipped ?? (_b.chipped = []);
16817
+ const chipped = (_c = p.st).chipped ?? (_c.chipped = []);
16492
16818
  const holes = localHolesOf(p);
16493
16819
  for (const cell of out) {
16494
16820
  const mass = Math.min(p.st.mass, p.mat.density * cell.size[0] * cell.size[1] * cell.size[2]);
16495
16821
  const center = toWorld(c, q, cell.center);
16496
16822
  const speed = clamp2(Math.sqrt(2 * energy * 0.05 / Math.max(mass, 0.05)), 0.5, 6);
16497
- const fragments = cellFragments(o, p, [cell], wp, dir, speed, mass, `c${chipped.length}_`);
16823
+ const tag = `c${chipped.length}_`;
16824
+ const fragments = cell.crater ? craterFragments(o, p, cell, dir, speed, mass, tag) : cellFragments(o, p, [cell], wp, dir, speed, mass, tag, true);
16498
16825
  p.st.holes = p.st.holes.filter((_, k) => marksInBox(cell.center, cell.size, void 0, [holes[k]]).length === 0);
16499
16826
  chipped.push({ center: [cell.center[0], cell.center[1], cell.center[2]], size: [cell.size[0], cell.size[1], cell.size[2]] });
16500
16827
  p.st.mass = Math.max(0, p.st.mass - mass);
@@ -16511,6 +16838,57 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16511
16838
  collapseCheck(o, src);
16512
16839
  }
16513
16840
  };
16841
+ const tornToEdge = (o) => {
16842
+ const { p, cell, a, b, at, crater: crater2, reach, gone } = o;
16843
+ const half = p.dims[a] / 2;
16844
+ const lo = cell.center[a] - cell.size[a] / 2, hi = cell.center[a] + cell.size[a] / 2;
16845
+ const free = (side, sign2) => {
16846
+ if (sign2 > 0 ? side >= half - 1e-6 : side <= -half + 1e-6) return sign2 > 0 || a !== planeAxes(p.thin)[1];
16847
+ const probe = side + sign2 * 1e-3;
16848
+ return gridOf(p).some((c, k) => gone(k) && Math.abs(probe - c.center[a]) <= c.size[a] / 2 && Math.abs(cell.center[b] - c.center[b]) <= c.size[b] / 2);
16849
+ };
16850
+ if (at - lo <= reach && free(lo, -1)) return [lo, Math.max(crater2[1], lo)];
16851
+ if (hi - at <= reach && free(hi, 1)) return [Math.min(crater2[0], hi), hi];
16852
+ return crater2;
16853
+ };
16854
+ const craterAcross = (energy) => clamp2(0.03 + 12e-4 * Math.sqrt(Math.max(0, energy)), 0.03, 0.14);
16855
+ const craterFragments = (o, p, cell, dir, speed, mass, tag) => {
16856
+ const { c, q } = partXf(o, p);
16857
+ const [u, v] = planeAxes(p.thin);
16858
+ const d = dir ?? rotateVec(q, [p.thin === 0 ? 1 : 0, p.thin === 1 ? 1 : 0, p.thin === 2 ? 1 : 0]);
16859
+ const exitSign = Math.sign(rotateVec(quat.conjugate(q), d)[p.thin]) || 1;
16860
+ const bit = Math.max(0.01, Math.min(cell.size[u], cell.size[v]) / 3);
16861
+ const n = clamp2(Math.round(cell.size[u] * cell.size[v] / (bit * bit * 3)), 4, 10) + Math.floor(rnd() * 3);
16862
+ const out = [];
16863
+ for (let i = 0; i < n; i++) {
16864
+ const back = i % 3 === 2;
16865
+ const lc = [cell.center[0], cell.center[1], cell.center[2]];
16866
+ lc[u] += (rnd() - 0.5) * cell.size[u] * 0.7;
16867
+ lc[v] += (rnd() - 0.5) * cell.size[v] * 0.7;
16868
+ lc[p.thin] += (back ? -exitSign : exitSign) * (p.thickness / 2 + 0.01);
16869
+ const size = [0, 0, 0];
16870
+ size[u] = bit * (0.6 + 0.8 * rnd());
16871
+ size[v] = bit * (0.5 + 0.7 * rnd());
16872
+ size[p.thin] = bit * (0.4 + 0.6 * rnd());
16873
+ const spread3 = [(rnd() - 0.5) * 0.9, (rnd() - 0.3) * 0.9, (rnd() - 0.5) * 0.9];
16874
+ const k = speed * (back ? 0.4 + 0.4 * rnd() : 0.7 + 0.8 * rnd());
16875
+ const vdir = vec.normalize(vec.add(back ? vec.scale(d, -1) : d, spread3));
16876
+ out.push({
16877
+ id: `${p.spec.id}#${tag}${i}`,
16878
+ part: p.spec.id,
16879
+ material: p.spec.material,
16880
+ shape: "chunk",
16881
+ center: toWorld(c, q, lc),
16882
+ size,
16883
+ rotation: q,
16884
+ velocity: [vdir[0] * k, vdir[1] * k + 0.5 * rnd(), vdir[2] * k],
16885
+ angularVelocity: [(rnd() - 0.5) * 20, (rnd() - 0.5) * 20, (rnd() - 0.5) * 20],
16886
+ mass: mass / n,
16887
+ inner: true
16888
+ });
16889
+ }
16890
+ return out;
16891
+ };
16514
16892
  const exposeRebar = (o, p, src) => {
16515
16893
  const r = p.spec.reinforcement;
16516
16894
  if (!r) return;
@@ -16798,7 +17176,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16798
17176
  });
16799
17177
  }
16800
17178
  const patch = [scale * 4, scale * 4, scale * 4];
16801
- emit({ ...base(o, src), type: "chip", part: p.spec.id, center: exit ?? entry2, size: patch, rotation: q, fragments });
17179
+ emit({ ...base(o, src), type: "chip", part: p.spec.id, center: exit ?? entry2, size: patch, rotation: q, fragments, torn: true });
16802
17180
  };
16803
17181
  const ballistic = (o, p, entry2, n, d, E, caliber, pathLen, src, round3 = {}) => {
16804
17182
  const mat = p.mat;
@@ -16857,12 +17235,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16857
17235
  } else if (mat.ductility >= 0.5) {
16858
17236
  addDent(o, p, entry2, n, Math.max(caliber * 3 / 1e3, 0.012), clamp2(Math.min(Math.max(p.thickness * 3, 3e-3), ratio * 0.01), 1e-3, 0.05), src);
16859
17237
  } else if (brittle) {
16860
- addCrack(o, p, entry2, n, crackLen, src);
17238
+ if (!p.spec.units) addCrack(o, p, entry2, n, crackLen, src);
16861
17239
  if (mat.fracture !== "shatter") addHole(o, p, entry2, n, caliber / 1e3, false, void 0, src);
16862
17240
  } else addHole(o, p, entry2, n, caliber / 1e3, false, void 0, src);
16863
17241
  debris(o, p, mat.hitDebris, entry2, n, clamp2(Math.round(E / 60) + 2, 2, 14), clamp2(Math.sqrt(E) / 6, 1, 8), src);
16864
17242
  wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true, BULLET_JOINT_SPAN);
16865
- const absorbed = penetrated && mat.ductility >= 0.5 && mat.fracture !== "tear" ? Math.min(E, thr) : E;
17243
+ const hollowTear = mat.fracture === "tear" && p.spec.fill !== void 0 && p.spec.fill < 0.5;
17244
+ const absorbed = penetrated && (mat.ductility >= 0.5 && mat.fracture !== "tear" || hollowTear) ? Math.min(E, thr) : E;
16866
17245
  const dmg = applyDamage(o, p, absorbed * DMG_PER_J * scale, "ballistic", entry2, d, absorbed * 0.1, 12, src);
16867
17246
  if (!isLost(p)) tearAt(o, p, "ballistic", entry2, penetrated ? exitPoint : void 0, d, E, caliber / 1e3, src);
16868
17247
  chipUnits(o, p, "ballistic", entry2, penetrated ? Math.min(E, Math.max(thr, E * 0.5)) : E, d, Math.max(0.05, caliber / 1e3 * 8), src);
@@ -16947,10 +17326,25 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
16947
17326
  if (dist <= BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3)) addBreach(o, p, wp, breachAreaOf(p, dealt, true), Ein, null, src);
16948
17327
  return reach;
16949
17328
  };
17329
+ const blastProbe = { partsTested: 0, partsNear: 0 };
17330
+ const blastCandidates = (o, point, radius) => {
17331
+ const local = toLocal(o.st.position, o.st.rotation, point);
17332
+ const near = [];
17333
+ for (const p of o.parts) {
17334
+ const reach = radius + p.bound;
17335
+ const dx = local[0] - p.pos[0];
17336
+ const dy = local[1] - p.pos[1];
17337
+ const dz = local[2] - p.pos[2];
17338
+ if (dx * dx + dy * dy + dz * dz < reach * reach) near.push(p);
17339
+ }
17340
+ blastProbe.partsTested += o.parts.length;
17341
+ blastProbe.partsNear += near.length;
17342
+ return near;
17343
+ };
16950
17344
  const blastObject = (o, point, energy, radius, src) => {
16951
17345
  const start = cur.length;
16952
17346
  const res = { object: o.id, damage: 0, penetrated: false, exitEnergy: 0, events: [] };
16953
- for (const p of o.parts) blastPart(o, p, point, energy, radius, src, res);
17347
+ for (const p of blastCandidates(o, point, radius)) blastPart(o, p, point, energy, radius, src, res);
16954
17348
  res.events = cur.slice(start);
16955
17349
  return res;
16956
17350
  };
@@ -17074,7 +17468,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
17074
17468
  let order = 0;
17075
17469
  for (const o of inRange) {
17076
17470
  if (only && only !== o) continue;
17077
- for (const p of o.parts) {
17471
+ for (const p of blastCandidates(o, point, radius)) {
17078
17472
  if (isLost(p)) continue;
17079
17473
  const dist = distToPart(o, p, point);
17080
17474
  if (dist < radius) items.push({ dist, order: order++, o, p });
@@ -17621,6 +18015,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
17621
18015
  const p = getPart(o, partId);
17622
18016
  p.pos = [position[0], position[1], position[2]];
17623
18017
  p.q = q;
18018
+ poseVersion++;
17624
18019
  updateBound(o);
17625
18020
  },
17626
18021
  remove(id) {
@@ -17639,6 +18034,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
17639
18034
  const o = getObj(id);
17640
18035
  o.base = { pos: [position[0], position[1], position[2]], rot: [rotation[0], rotation[1], rotation[2], rotation[3]] };
17641
18036
  applySoilPose(o);
18037
+ slideOffResting(o, rotation);
17642
18038
  },
17643
18039
  splitGroup(id, group, newId) {
17644
18040
  if (impls.has(id)) throw new Error(`object "${id}" is a registered DestructibleImpl and cannot be split; its module owns its pieces`);
@@ -17662,7 +18058,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
17662
18058
  if (o.spec.name !== void 0) s.name = o.spec.name;
17663
18059
  if (o.spec.tags) s.tags = [...o.spec.tags];
17664
18060
  if (o.spec.soil !== void 0) s.soil = o.spec.soil;
17665
- return clone(s);
18061
+ return s;
17666
18062
  };
17667
18063
  const inNew = (pid) => moved.has(pid);
17668
18064
  const inOld = (pid) => !moved.has(pid);
@@ -17689,7 +18085,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
17689
18085
  const p = getPart(o, partId);
17690
18086
  return whole(() => doHit(o, h, p));
17691
18087
  },
18088
+ blastProbe() {
18089
+ return { ...blastProbe };
18090
+ },
17692
18091
  explode(point, energy, radius, source, blast) {
18092
+ blastProbe.partsTested = 0;
18093
+ blastProbe.partsNear = 0;
17693
18094
  return withCollapses(run(() => blastWorld(point, energy, radius, source, blast)));
17694
18095
  },
17695
18096
  raycast(origin, direction, maxDistance = Infinity) {
@@ -17699,7 +18100,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
17699
18100
  sweepBox(box4, direction, distance2, options2 = {}) {
17700
18101
  const d = vec.normalize(direction);
17701
18102
  const ignored = options2.ignore === void 0 ? void 0 : objects.get(options2.ignore);
17702
- const ignore = ignored ? new Set(ignored.parts.map((p) => `${ignored.id}\0${p.spec.id}`)) : void 0;
18103
+ const hosted = options2.ignore === void 0 || ignored ? void 0 : impls.get(options2.ignore);
18104
+ const ignore = ignored ? new Set(ignored.parts.map((p) => `${ignored.id}\0${p.spec.id}`)) : hosted ? new Set(hosted.impl.describe().parts.map((p) => `${hosted.impl.id}\0${p.id}`)) : void 0;
17703
18105
  let best = null;
17704
18106
  for (const origin of sweepOrigins(box4, d, options2.spacing ?? 0.2)) {
17705
18107
  const r = raycastInternal(origin, d, distance2 + SWEEP_BACK, ignore);
@@ -21142,9 +21544,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21142
21544
  var SHARED_ROOMS = { west: { type: "laundry", label: "laundry_room" }, east: { type: "storage", label: "storage_room" } };
21143
21545
  var apartments = (plan) => (strip, { floor, plate, ceiling }) => {
21144
21546
  if (strip.length < plan.apartmentMin) {
21145
- const shared = SHARED_ROOMS[strip.id] ?? SHARED_ROOMS.east;
21146
- const id = `${shared.label}_${floor}_${strip.id}`;
21147
- return { rooms: [{ id, type: shared.type, label: shared.label, rect: [...strip.rect] }], doors: [stripDoor(id, strip, floor, 0.9)], windows: exteriorWindows(id, strip.rect, plate, ceiling, { ...plan.window, width: 1.2 }) };
21547
+ const shared2 = SHARED_ROOMS[strip.id] ?? SHARED_ROOMS.east;
21548
+ const id = `${shared2.label}_${floor}_${strip.id}`;
21549
+ return { rooms: [{ id, type: shared2.type, label: shared2.label, rect: [...strip.rect] }], doors: [stripDoor(id, strip, floor, 0.9)], windows: exteriorWindows(id, strip.rect, plate, ceiling, { ...plan.window, width: 1.2 }) };
21148
21550
  }
21149
21551
  const count = Math.max(1, Math.round(strip.length / plan.apartment)), wide = strip.length / count;
21150
21552
  const parts = Array.from({ length: count }, (_, k) => apartment(strip, floor, k, r22(k * wide), r22((k + 1) * wide), plate, ceiling, plan.window));
@@ -21258,7 +21660,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21258
21660
  var OPEN_ROOM_TYPES2 = /* @__PURE__ */ new Set(["balcony", "terrace", "veranda", "balcony_gourmet"]);
21259
21661
  var rectsOf = (c) => c.parts && c.parts.length ? c.parts : [[c.u0, c.v0, c.u1, c.v1]];
21260
21662
  var isOpenArea = (c) => OPEN_ROOM_TYPES2.has(c.type) || c.outdoor === true;
21261
- function installKernelGeometry(K, shared) {
21663
+ function installKernelGeometry(K, shared2) {
21262
21664
  const { THREE } = K;
21263
21665
  const GEO = {};
21264
21666
  {
@@ -21317,9 +21719,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21317
21719
  const cursor = { group: "lot", accs: /* @__PURE__ */ new Map(), rot: [], org: [0, 0, 0], ry: 0 };
21318
21720
  const PARTS = [];
21319
21721
  const MIRRORS = [];
21320
- shared.partCount = 0;
21722
+ shared2.partCount = 0;
21321
21723
  function part(type, pos, fn, meta = {}, parent, ry = 0) {
21322
- const gA = cursor.group, oA = cursor.org, rA = cursor.ry, pieceA = cursor.pc, name = "part:" + (meta.id || type) + ":" + shared.partCount++;
21724
+ const gA = cursor.group, oA = cursor.org, rA = cursor.ry, pieceA = cursor.pc, name = "part:" + (meta.id || type) + ":" + shared2.partCount++;
21323
21725
  PARTS.push({ name, parent: parent || gA, pos: pos.slice(), type, meta, ry });
21324
21726
  cursor.group = name;
21325
21727
  cursor.org = pos;
@@ -21354,7 +21756,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21354
21756
  }
21355
21757
  const _Y = new THREE.Vector3(0, 1, 0), _qa = new THREE.Quaternion(), _qb = new THREE.Quaternion();
21356
21758
  function pieceRecord(id, mat, role, extra) {
21357
- const M = shared.ctx.pieces;
21759
+ const M = shared2.ctx.pieces;
21358
21760
  let p = M.get(id);
21359
21761
  if (!p) {
21360
21762
  p = Object.assign({ id, mat, role: role || null }, extra);
@@ -21363,7 +21765,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21363
21765
  return p;
21364
21766
  }
21365
21767
  const structurePiece = (id) => {
21366
- const e = shared.ctx.structureIndex && shared.ctx.structureIndex[id];
21768
+ const e = shared2.ctx.structureIndex && shared2.ctx.structureIndex[id];
21367
21769
  return e ? pieceRecord(id, e.material, e.role, { floor: e.floor }) : null;
21368
21770
  };
21369
21771
  function accFor(mat) {
@@ -21812,7 +22214,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21812
22214
  const NO_SHADOW = /* @__PURE__ */ new Set(["dirt", "glass", "water", "screen", "building", "picture", "floor", "emissive"]);
21813
22215
  Object.assign(K, { createMaterials, antiTile, dirtMaterial, CLOTHES_UNIFORMS, clothesMaterial, ORDER, NO_SHADOW });
21814
22216
  }
21815
- function installKernelCloseScene(K, shared) {
22217
+ function installKernelCloseScene(K, shared2) {
21816
22218
  const { THREE, NO_SHADOW, ORDER, PARTS, applyPart, cursor } = K;
21817
22219
  const assembleCars = (...a) => K.assembleCars(...a);
21818
22220
  const assembleMirrors = (...a) => K.assembleMirrors(...a);
@@ -21827,7 +22229,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21827
22229
  if (!fx.length) return;
21828
22230
  const u = m.userData, ids = [...new Set(fx.map((f) => f.id))], weight = {};
21829
22231
  for (const f of fx) {
21830
- const mt = shared.ctx.pieces.get(f.id).mat;
22232
+ const mt = shared2.ctx.pieces.get(f.id).mat;
21831
22233
  weight[mt] = (weight[mt] || 0) + f.v1 - f.v0;
21832
22234
  }
21833
22235
  u.ranges = fx;
@@ -21835,7 +22237,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21835
22237
  u.destructionMaterial = Object.keys(weight).sort((a, b) => weight[b] - weight[a])[0];
21836
22238
  if (ids.length === 1) {
21837
22239
  u.destructionPart = ids[0];
21838
- const pc = shared.ctx.pieces.get(ids[0]);
22240
+ const pc = shared2.ctx.pieces.get(ids[0]);
21839
22241
  if (pc.role) u.structuralRole = pc.role;
21840
22242
  }
21841
22243
  }
@@ -21878,7 +22280,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21878
22280
  if (P.meta.t0) applyPart(g, P.meta.t0);
21879
22281
  }
21880
22282
  (groups[P.parent] || (groups[P.parent] = new THREE.Group())).add(g);
21881
- if (P.meta.id) (shared.ctx.parts || (shared.ctx.parts = {}))[P.meta.id] = g;
22283
+ if (P.meta.id) (shared2.ctx.parts || (shared2.ctx.parts = {}))[P.meta.id] = g;
21882
22284
  }
21883
22285
  PARTS.length = 0;
21884
22286
  assembleMirrors(groups);
@@ -21888,20 +22290,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21888
22290
  }
21889
22291
  Object.assign(K, { markMesh, closeScene });
21890
22292
  }
21891
- function installHouseHelpers(K, shared) {
21892
- shared.ctx = {};
22293
+ function installHouseHelpers(K, shared2) {
22294
+ shared2.ctx = {};
21893
22295
  const OPEN_ROOM_TYPES22 = /* @__PURE__ */ new Set(["balcony", "terrace", "veranda", "balcony_gourmet"]);
21894
22296
  const NO_CEILING = OPEN_ROOM_TYPES22;
21895
22297
  const OPEN_AREA = (c) => OPEN_ROOM_TYPES22.has(c.type) || c.outdoor === true;
21896
22298
  const EPS3 = 1e-3;
21897
22299
  const Y0 = (f) => {
21898
- const A = shared.ctx.r.floors;
22300
+ const A = shared2.ctx.r.floors;
21899
22301
  return A[Math.max(0, Math.min(A.length - 1, f))].y0;
21900
22302
  };
21901
- const colorOf = (v) => typeof v === "number" ? v : typeof v === "string" && shared.ctx.colors[v] != null ? shared.ctx.colors[v] : null;
22303
+ const colorOf = (v) => typeof v === "number" ? v : typeof v === "string" && shared2.ctx.colors[v] != null ? shared2.ctx.colors[v] : null;
21902
22304
  const rectsOf2 = (c) => c.parts && c.parts.length ? c.parts : [[c.u0, c.v0, c.u1, c.v1]];
21903
22305
  function roomAt(f, u, v) {
21904
- for (const c of shared.ctx.r.rooms) if (c.floor === f) {
22306
+ for (const c of shared2.ctx.r.rooms) if (c.floor === f) {
21905
22307
  for (const [a, b, c2, d] of rectsOf2(c)) if (u > a + EPS3 && u < c2 - EPS3 && v > b + EPS3 && v < d - EPS3) return c;
21906
22308
  }
21907
22309
  return null;
@@ -21929,14 +22331,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21929
22331
  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]))];
21930
22332
  }
21931
22333
  function effectiveHeight(f, h) {
21932
- const A = shared.ctx.r.floors;
22334
+ const A = shared2.ctx.r.floors;
21933
22335
  if (f + 1 >= A.length) return h;
21934
22336
  const pitch = A[f + 1].y0 - A[f].y0;
21935
22337
  return h > pitch && h - pitch <= 0.45 ? pitch : h;
21936
22338
  }
21937
22339
  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 });
21938
22340
  }
21939
- function installHouseWalls(K, shared) {
22341
+ function installHouseWalls(K, shared2) {
21940
22342
  const { EPS: EPS3, Y0, boxC, bx, cursor, effectiveHeight, pieceRecord, structurePiece, wallColor } = K;
21941
22343
  function wallBox(alongU, L, a, b, ya, yb, th, cL, cH, mL, mH) {
21942
22344
  if (yb - ya < 1e-4 || b - a < 1e-4) return;
@@ -21949,10 +22351,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21949
22351
  }
21950
22352
  }
21951
22353
  function sideOf(id, frontLine) {
21952
- const R = shared.ctx.r, F = R.facade;
21953
- if (id === "outside" || !shared.ctx.roomById[id]) {
22354
+ const R = shared2.ctx.r, F = R.facade;
22355
+ if (id === "outside" || !shared2.ctx.roomById[id]) {
21954
22356
  const ac = F.finish;
21955
- let mat = "plaster", color2 = shared.ctx.colors.facade;
22357
+ let mat = "plaster", color2 = shared2.ctx.colors.facade;
21956
22358
  if (ac === "roughcast") mat = "roughcast";
21957
22359
  else if (ac === "exposed_block") {
21958
22360
  mat = "block";
@@ -21963,12 +22365,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21963
22365
  }
21964
22366
  return { color: color2, mat, exterior: true };
21965
22367
  }
21966
- return { color: wallColor(shared.ctx.roomById[id]), mat: "plaster", exterior: false };
22368
+ return { color: wallColor(shared2.ctx.roomById[id]), mat: "plaster", exterior: false };
21967
22369
  }
21968
22370
  const pieceOf = (w) => !w.id ? null : structurePiece(w.id) || pieceRecord(w.id, w.material || "brick", w.role || "partition", { floor: w.floor });
21969
22371
  function nearestWall(f, axis, L, c) {
21970
22372
  let m = null, md = 1e9;
21971
- for (const w of shared.ctx.r.walls) {
22373
+ for (const w of shared2.ctx.r.walls) {
21972
22374
  if (w.floor !== f || w.axis !== axis || w.type !== "wall" || Math.abs((axis === "u" ? w.v0 : w.u0) - L) > EPS3) continue;
21973
22375
  const a = Math.min(axis === "u" ? w.u0 : w.v0, axis === "u" ? w.u1 : w.v1), b = Math.max(axis === "u" ? w.u0 : w.v0, axis === "u" ? w.u1 : w.v1), d = c < a ? a - c : c > b ? c - b : 0;
21974
22376
  if (d < md) {
@@ -21979,7 +22381,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21979
22381
  return m;
21980
22382
  }
21981
22383
  function walls() {
21982
- const R = shared.ctx.r, cut = shared.ctx.cut, nA = R.floors.length, vMin = Math.min(...R.walls.map((w) => w.axis === "u" ? w.v0 : Math.min(w.v0, w.v1)));
22384
+ 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)));
21983
22385
  const corners = /* @__PURE__ */ new Map();
21984
22386
  for (const w of R.walls) {
21985
22387
  const f = w.floor;
@@ -21990,9 +22392,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
21990
22392
  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);
21991
22393
  const front = alongU && Math.abs(L - vMin) < 0.05;
21992
22394
  const sideL = sideOf(w.sides[0], front), sideH = sideOf(w.sides[1], front);
21993
- shared.ctx.colliders.push({ type: "wall", piece: w.id, f, x0: alongU ? s0 : L - th / 2, z0: alongU ? L - th / 2 : s0, x1: alongU ? s1 : L + th / 2, z1: alongU ? L + th / 2 : s1 });
22395
+ 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 });
21994
22396
  if (w.type === "railing") {
21995
- const c0 = shared.ctx.colors.metal != null ? shared.ctx.colors.metal : 9080466;
22397
+ const c0 = shared2.ctx.colors.metal != null ? shared2.ctx.colors.metal : 9080466;
21996
22398
  const sx = alongU ? 1 : 0, sz = alongU ? 0 : 1, len = s1 - s0, n = Math.max(1, Math.round(len / 1.4));
21997
22399
  const cx_ = alongU ? (s0 + s1) / 2 : L, cz_ = alongU ? L : (s0 + s1) / 2;
21998
22400
  boxC("glass", cx_, y0 + 0.55, cz_, alongU ? len : 0.02, 0.85, alongU ? 0.02 : len, 16777215);
@@ -22039,7 +22441,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22039
22441
  }
22040
22442
  Object.assign(K, { wallBox, sideOf, pieceOf, nearestWall, walls });
22041
22443
  }
22042
- function installHouseDoors(K, shared) {
22444
+ function installHouseDoors(K, shared2) {
22043
22445
  const seedKey = (id) => K.seedKey(id);
22044
22446
  const { EPS: EPS3, Y0, boxC, bx, cursor, effectiveHeight, nearestWall, part, pieceOf, pieceRecord, roomAt, sideOf, wallBox } = K;
22045
22447
  const SEED = (...a) => K.SEED(...a);
@@ -22047,15 +22449,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22047
22449
  const rngString = (...a) => K.rngString(...a);
22048
22450
  const sh = (...a) => K.sh(...a);
22049
22451
  function doorLineSides(p) {
22050
- const R = shared.ctx.r, alongU = p.axis === "u", a = p.at - p.width / 2, b = p.at + p.width / 2;
22452
+ const R = shared2.ctx.r, alongU = p.axis === "u", a = p.at - p.width / 2, b = p.at + p.width / 2;
22051
22453
  const w = R.walls.find((w2) => w2.floor === p.floor && w2.axis === p.axis && Math.abs((alongU ? w2.v0 : w2.u0) - p.pos) < EPS3 && w2.type === "wall" && (Math.abs((alongU ? w2.u1 : w2.v1) - a) < 0.02 || Math.abs((alongU ? w2.u0 : w2.v0) - b) < 0.02));
22052
22454
  const sides = w ? w.sides : [p.a, p.b];
22053
22455
  return [sideOf(sides[0], false), sideOf(sides[1], false)];
22054
22456
  }
22055
- shared.doorState = /* @__PURE__ */ new Map();
22457
+ shared2.doorState = /* @__PURE__ */ new Map();
22056
22458
  function doors() {
22057
- shared.ctx.leaves = [];
22058
- const R = shared.ctx.r, cut = shared.ctx.cut, C = shared.ctx.colors, wood = C.wood != null ? C.wood : 8016948, frame2 = sh(wood, 0.55);
22459
+ shared2.ctx.leaves = [];
22460
+ 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);
22059
22461
  for (const p of R.doors) {
22060
22462
  const f = p.floor;
22061
22463
  cursor.group = "f" + f;
@@ -22085,12 +22487,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22085
22487
  }
22086
22488
  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);
22087
22489
  const extC = wood;
22088
- const open0 = p.blocked ? false : shared.doorState.has(p.id) ? shared.doorState.get(p.id) : !!p.open;
22089
- shared.doorState.set(p.id, open0);
22490
+ const open0 = p.blocked ? false : shared2.doorState.has(p.id) ? shared2.doorState.get(p.id) : !!p.open;
22491
+ shared2.doorState.set(p.id, open0);
22090
22492
  const dc = alongU ? [p.at, L] : [L, p.at];
22091
22493
  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 };
22092
22494
  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 };
22093
- shared.ctx.colliders.push(colR);
22495
+ shared2.ctx.colliders.push(colR);
22094
22496
  fo.col = colR;
22095
22497
  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);
22096
22498
  const newGroup = (k, hu, topY) => {
@@ -22150,7 +22552,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22150
22552
  fo.rot = Math.atan2(n[0] * A[1] - n[1] * A[0], A[0] * n[0] + A[1] * n[1]);
22151
22553
  }
22152
22554
  }
22153
- shared.ctx.leaves.push(fo);
22555
+ shared2.ctx.leaves.push(fo);
22154
22556
  cursor.group = "f" + f;
22155
22557
  if (p.blocked) {
22156
22558
  part("window_boards", [0, 0, 0], () => {
@@ -22178,18 +22580,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22178
22580
  }
22179
22581
  }
22180
22582
  }, { id: "boards:" + p.id }, "f" + f);
22181
- shared.ctx.colliders.push({ type: "board", f, x0: alongU ? a : L - th / 2, z0: alongU ? L - th / 2 : a, x1: alongU ? b : L + th / 2, z1: alongU ? L + th / 2 : b });
22583
+ 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 });
22182
22584
  }
22183
22585
  }
22184
22586
  }
22185
22587
  Object.assign(K, { doorLineSides, doors });
22186
22588
  }
22187
- function installHouseWindows(K, shared) {
22589
+ function installHouseWindows(K, shared2) {
22188
22590
  const { EPS: EPS3, Y0, boxC, bx, cursor, pieceRecord, roomAt } = K;
22189
22591
  const FRAME_COLORS = { budget: 15856110, mid: 12830924, high: 2829875, commercial: 11844287 };
22190
22592
  const SILL_COLORS = { budget: 15131870, mid: 14277076, high: 3816770, commercial: 13225166 };
22191
22593
  function windows() {
22192
- const R = shared.ctx.r, cut = shared.ctx.cut, C = shared.ctx.colors, structure = R.style, fr = FRAME_COLORS[structure] || FRAME_COLORS.budget, pe_ = SILL_COLORS[structure] || SILL_COLORS.budget;
22594
+ const R = shared2.ctx.r, cut = shared2.ctx.cut, C = shared2.ctx.colors, structure = R.style, fr = FRAME_COLORS[structure] || FRAME_COLORS.budget, pe_ = SILL_COLORS[structure] || SILL_COLORS.budget;
22193
22595
  const boardItems = new Set(R.stateItems.filter((e) => e.type === "window_boards" && e.window).map((e) => e.window));
22194
22596
  for (const j of R.windows) {
22195
22597
  const f = j.floor;
@@ -22242,11 +22644,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22242
22644
  }
22243
22645
  Object.assign(K, { FRAME_COLORS, SILL_COLORS, windows });
22244
22646
  }
22245
- function installHouseFloors(K, shared) {
22647
+ function installHouseFloors(K, shared2) {
22246
22648
  const { rectsOf: rectsOf2, EPS: EPS3, OPEN_AREA, Y0, bx, cursor, floorColor, stairFootprint, structurePiece, subRects } = K;
22247
22649
  function flights() {
22248
- if (shared.ctx._flights && shared.ctx._flights.r === shared.ctx.r) return shared.ctx._flights.l;
22249
- const R = shared.ctx.r, mp = /* @__PURE__ */ new Map();
22650
+ if (shared2.ctx._flights && shared2.ctx._flights.r === shared2.ctx.r) return shared2.ctx._flights.l;
22651
+ const R = shared2.ctx.r, mp = /* @__PURE__ */ new Map();
22250
22652
  for (const m of R.items) {
22251
22653
  if (m.type !== "stairs" || !m.link) continue;
22252
22654
  const k = [m.link.from, m.link.to, m.x.toFixed(2), m.z.toFixed(2), (m.ry || 0).toFixed(2)].join("|");
@@ -22262,12 +22664,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22262
22664
  v.LP = LP;
22263
22665
  v.top = stairFootprint({ x: m.x + lz * Math.sin(m.ry), z: m.z + lz * Math.cos(m.ry), ry: m.ry, w: m.w, d: LP });
22264
22666
  }
22265
- shared.ctx._flights = { r: R, l };
22667
+ shared2.ctx._flights = { r: R, l };
22266
22668
  return l;
22267
22669
  }
22268
22670
  const panelRects = (p) => p.footprint && p.footprint.length ? p.footprint : [p.aabb];
22269
22671
  function tilesOf(parent, rc) {
22270
- const ps = parent && shared.ctx.panelsOf && shared.ctx.panelsOf.get(parent);
22672
+ const ps = parent && shared2.ctx.panelsOf && shared2.ctx.panelsOf.get(parent);
22271
22673
  if (!ps) return [[parent ? structurePiece(parent) : null, rc]];
22272
22674
  const out = [], taken = [];
22273
22675
  for (const p of ps) for (const q of panelRects(p)) {
@@ -22281,14 +22683,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22281
22683
  return out;
22282
22684
  }
22283
22685
  function panelAt(parent, x, z) {
22284
- const ps = shared.ctx.panelsOf && shared.ctx.panelsOf.get(parent);
22686
+ const ps = shared2.ctx.panelsOf && shared2.ctx.panelsOf.get(parent);
22285
22687
  if (!ps) return structurePiece(parent);
22286
22688
  for (const p of ps) for (const q of panelRects(p)) if (x >= q[0] - EPS3 && x <= q[2] + EPS3 && z >= q[1] - EPS3 && z <= q[3] + EPS3) return structurePiece(p.id);
22287
22689
  return null;
22288
22690
  }
22289
- const hasSlab = (id) => !!(shared.ctx.structureIndex[id] || shared.ctx.panelsOf && shared.ctx.panelsOf.has(id));
22691
+ const hasSlab = (id) => !!(shared2.ctx.structureIndex[id] || shared2.ctx.panelsOf && shared2.ctx.panelsOf.has(id));
22290
22692
  function floorsAndSlabs() {
22291
- const R = shared.ctx.r, nA = R.floors.length, C = shared.ctx.colors;
22693
+ const R = shared2.ctx.r, nA = R.floors.length, C = shared2.ctx.colors;
22292
22694
  const V = flights(), holes = (f) => V.filter((v) => v.to === f).flatMap((v) => {
22293
22695
  let rs = [v.rect];
22294
22696
  if (v.top) rs = subRects(rs, [v.top]);
@@ -22325,18 +22727,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22325
22727
  }
22326
22728
  Object.assign(K, { flights, floorsAndSlabs, tilesOf, panelAt });
22327
22729
  }
22328
- function installHouseStairs(K, shared) {
22730
+ function installHouseStairs(K, shared2) {
22329
22731
  const { rectsOf: rectsOf2, Y0, boxC, bx, cursor, flights, stairFootprint, structurePiece } = K;
22330
22732
  const sh = (...a) => K.sh(...a);
22331
22733
  function buildStairs() {
22332
- const R = shared.ctx.r;
22333
- shared.ctx.stairs = [];
22734
+ const R = shared2.ctx.r;
22735
+ shared2.ctx.stairs = [];
22334
22736
  for (const vo of flights()) {
22335
22737
  const m = vo.m, f = vo.from, Dr = m.d - (vo.LP || 0);
22336
22738
  cursor.group = "f" + f;
22337
22739
  cursor.pc = structurePiece("stairs_" + vo.from + "_" + vo.to);
22338
22740
  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);
22339
- const wood = shared.ctx.colors.wood != null ? shared.ctx.colors.wood : 9071176, under = sh(wood, 0.7);
22741
+ const wood = shared2.ctx.colors.wood != null ? shared2.ctx.colors.wood : 9071176, under = sh(wood, 0.7);
22340
22742
  const P = (lx, lz) => [m.x + lx * c + lz * s, m.z - lx * s + lz * c];
22341
22743
  const boxL = (mat, lx, y, lz, w, h, d, color2, rx = 0) => {
22342
22744
  const [px, pz] = P(lx, lz);
@@ -22358,16 +22760,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22358
22760
  }
22359
22761
  }
22360
22762
  cursor.pc = null;
22361
- shared.ctx.stairs.push({ m, f, to: vo.to, y0, H, rect: stairFootprint(m), landingPoint: (vo.LP || 0) / m.d });
22763
+ shared2.ctx.stairs.push({ m, f, to: vo.to, y0, H, rect: stairFootprint(m), landingPoint: (vo.LP || 0) / m.d });
22362
22764
  }
22363
22765
  }
22364
22766
  function elevator() {
22365
- const R = shared.ctx.r;
22767
+ const R = shared2.ctx.r;
22366
22768
  for (const c of R.rooms.filter((c2) => c2.type === "elevator" && c2.floor === 0)) {
22367
22769
  cursor.group = "f0";
22368
22770
  const [u0, v0, u1, v1] = rectsOf2(c)[0], y0 = Y0(0);
22369
22771
  bx("metal", u0 + 0.15, y0 + 0.05, v0 + 0.15, u1 - 0.15, y0 + 2.3, v1 - 0.15, 10133670);
22370
- bx("emissive", u0 + 0.3, y0 + 2.28, v0 + 0.3, u1 - 0.3, y0 + 2.3, v1 - 0.3, shared.ctx.night ? 16773320 : 13619924);
22772
+ bx("emissive", u0 + 0.3, y0 + 2.28, v0 + 0.3, u1 - 0.3, y0 + 2.3, v1 - 0.3, shared2.ctx.night ? 16773320 : 13619924);
22371
22773
  for (const f of R.floors) {
22372
22774
  const yy = Y0(f.index);
22373
22775
  cursor.group = "f" + f.index;
@@ -22377,7 +22779,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22377
22779
  }
22378
22780
  Object.assign(K, { buildStairs, elevator });
22379
22781
  }
22380
- function installLightsFixtures(K, shared) {
22782
+ function installLightsFixtures(K, shared2) {
22381
22783
  const seedKey = (id) => K.seedKey(id);
22382
22784
  const { cursor, part, polyFace } = K;
22383
22785
  const makeApi = (...a) => K.makeApi(...a);
@@ -22395,9 +22797,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22395
22797
  return ((t ^ t >>> 14) >>> 0) / 4294967296;
22396
22798
  };
22397
22799
  }
22398
- const SEED = () => shared.ctx.r && shared.ctx.r.seed || 0;
22399
- const STYLE = () => shared.ctx.r && shared.ctx.r.style || "budget";
22400
- shared.api0 = null;
22800
+ const SEED = () => shared2.ctx.r && shared2.ctx.r.seed || 0;
22801
+ const STYLE = () => shared2.ctx.r && shared2.ctx.r.style || "budget";
22802
+ shared2.api0 = null;
22401
22803
  function kit2(M, A, y0 = M.y || 0) {
22402
22804
  const c = Math.cos(M.ry), s = Math.sin(M.ry);
22403
22805
  let api = A;
@@ -22429,7 +22831,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22429
22831
  return null;
22430
22832
  }
22431
22833
  const a0 = api;
22432
- api = shared.api0 || (shared.api0 = makeApi());
22834
+ api = shared2.api0 || (shared2.api0 = makeApi());
22433
22835
  try {
22434
22836
  return part(type, W(lx, ly, lz), fn, meta || {}, void 0, M.ry);
22435
22837
  } finally {
@@ -22523,7 +22925,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22523
22925
  yLight = yc - 0.3;
22524
22926
  range2 = 6.5;
22525
22927
  } else if (type === "chandelier") {
22526
- const yc = t - 0.5, gold = shared.ctx.colors && shared.ctx.colors.metal != null ? shared.ctx.colors.metal : 9075290, N = 6;
22928
+ const yc = t - 0.5, gold = shared2.ctx.colors && shared2.ctx.colors.metal != null ? shared2.ctx.colors.metal : 9075290, N = 6;
22527
22929
  K2.c("metal", 0, yc, 0, 0.012, 0.5, gold);
22528
22930
  K2.e("metal", 0, yc - 0.03, 0, 0.055, 0.08, gold);
22529
22931
  K2.c("metal", 0, yc - 0.06, 0, 0.14, 0.015, gold);
@@ -22601,24 +23003,24 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22601
23003
  }
22602
23004
  Object.assign(K, { hashString: hashString2, rngString, SEED, STYLE, kit2, arcPoints, TEMP_WARM, TEMP_NEUTRAL, TEMP_COOL, colorTemperature, lightStyle, ceilingLamp, tableLamp, floorLamp, sconce, outdoorLamp, lightSwitch });
22603
23005
  }
22604
- function installLightsDecor(K, shared) {
23006
+ function installLightsDecor(K, shared2) {
22605
23007
  const { EPS: EPS3, OPEN_AREA, SEED, Y0, cursor, rngString, roomAt, stairFootprint } = K;
22606
23008
  const lightItem = (...a) => K.lightItem(...a);
22607
23009
  function decorLights(api) {
22608
- const R = shared.ctx.r, T2 = shared.ctx.types, structure = R.style, chance = structure === "budget" ? 0.35 : structure === "mid" ? 0.75 : 1, rnd = rngString(SEED() + "|decorluz");
23010
+ const R = shared2.ctx.r, T2 = shared2.ctx.types, structure = R.style, chance = structure === "budget" ? 0.35 : structure === "mid" ? 0.75 : 1, rnd = rngString(SEED() + "|decorluz");
22609
23011
  const itemsF = (f) => R.items.filter((m) => (m.outdoor ? -1 : m.floor) === f && m.type !== "stairs");
22610
23012
  const rectsF = (f) => itemsF(f).filter((m) => (m.h || 0) > 0.3 && !/rug|floor|concrete|dirt|lawn|ceiling_light|curtain|blinds|picture|mirror|pendant|chandelier|spot/.test(m.type)).map((m) => stairFootprint(m));
22611
23013
  const free = (f, x, z, margin) => {
22612
23014
  if (!roomAt(f, x, z)) return false;
22613
- for (const c of shared.ctx.colliders) if (c.f === f && x > c.x0 - margin && x < c.x1 + margin && z > c.z0 - margin && z < c.z1 + margin) return false;
23015
+ for (const c of shared2.ctx.colliders) if (c.f === f && x > c.x0 - margin && x < c.x1 + margin && z > c.z0 - margin && z < c.z1 + margin) return false;
22614
23016
  for (const r of rectsF(f)) if (x > r[0] - margin && x < r[2] + margin && z > r[1] - margin && z < r[3] + margin) return false;
22615
23017
  return true;
22616
23018
  };
22617
23019
  const puts = (f, type, m0, extra) => {
22618
23020
  const ent = T2[type];
22619
23021
  if (!ent) return;
22620
- const com = shared.ctx.roomById[m0.room], g = "f" + f, base = Y0(f);
22621
- const M = Object.assign({ x: m0.x, z: m0.z, ry: m0.ry || 0, w: m0.w || 0.3, d: m0.d || 0.3, h: m0.h || 0.3, y: 0, base, floor: f, colors: shared.ctx.colors, seed: m0.id, room: m0.room, typeWith: com ? com.type : null, ceiling: com ? com.ceiling : 2.8, on: shared.ctx.night, light: shared.ctx.night, lit: shared.ctx.night }, extra || {});
23022
+ const com = shared2.ctx.roomById[m0.room], g = "f" + f, base = Y0(f);
23023
+ const M = Object.assign({ x: m0.x, z: m0.z, ry: m0.ry || 0, w: m0.w || 0.3, d: m0.d || 0.3, h: m0.h || 0.3, y: 0, base, floor: f, colors: shared2.ctx.colors, seed: m0.id, room: m0.room, typeWith: com ? com.type : null, ceiling: com ? com.ceiling : 2.8, on: shared2.ctx.night, light: shared2.ctx.night, lit: shared2.ctx.night }, extra || {});
22622
23024
  cursor.group = g;
22623
23025
  lightItem({ id: m0.id, room: m0.room }, M, ent, api, g);
22624
23026
  };
@@ -22666,18 +23068,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22666
23068
  }
22667
23069
  Object.assign(K, { decorLights });
22668
23070
  }
22669
- function installLotTerrain(K, shared) {
23071
+ function installLotTerrain(K, shared2) {
22670
23072
  const { rectsOf: rectsOf2, MIRRORS, PARTS, bx, cursor } = K;
22671
23073
  function terrain() {
22672
23074
  PARTS.length = 0;
22673
23075
  MIRRORS.length = 0;
22674
23076
  K.CARS.length = 0;
22675
- shared.partCount = 0;
22676
- shared.ctx.parts = {};
22677
- shared.tapCount = 0;
22678
- shared.ctx.clotheslines = [];
22679
- if (shared.ctx.noTerrain) return;
22680
- const R = shared.ctx.r, lt = R.lot, C = shared.ctx.colors;
23077
+ shared2.partCount = 0;
23078
+ shared2.ctx.parts = {};
23079
+ shared2.tapCount = 0;
23080
+ shared2.ctx.clotheslines = [];
23081
+ if (shared2.ctx.noTerrain) return;
23082
+ const R = shared2.ctx.r, lt = R.lot, C = shared2.ctx.colors;
22681
23083
  cursor.group = "floor";
22682
23084
  const light = (c, f) => {
22683
23085
  const m = (k) => Math.round((c >> k & 255) * (1 - f) + 255 * f);
@@ -22691,13 +23093,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22691
23093
  bx("sidewalk", u0 - 40, -0.06, v0 - 1.8, u1 + 40, 0.02, v0, 14999766);
22692
23094
  for (let x = u0 - 38; x < u1 + 40; x += 6) bx("plaster", x, 0, v0 - 5.6, x + 2.6, 5e-3, v0 - 5.4, 15262904);
22693
23095
  } else {
22694
- const b = shared.ctx.limits;
23096
+ const b = shared2.ctx.limits;
22695
23097
  bx("sidewalk", b.x0 - 6, -0.09, b.z0 - 6, b.x1 + 6, -0.03, b.z1 + 6, 14605010);
22696
23098
  }
22697
23099
  }
22698
23100
  function freeSpans(alongU, L, a, b) {
22699
23101
  const blocks = [];
22700
- for (const c of shared.ctx.r.rooms) {
23102
+ for (const c of shared2.ctx.r.rooms) {
22701
23103
  if (c.type === "void" || c.floor < 0) continue;
22702
23104
  for (const [u0, v0, u1, v1] of rectsOf2(c)) {
22703
23105
  const c0 = alongU ? v0 : u0, c1 = alongU ? v1 : u1, lo = alongU ? u0 : v0, hi = alongU ? u1 : v1;
@@ -22717,12 +23119,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22717
23119
  }
22718
23120
  Object.assign(K, { terrain, freeSpans });
22719
23121
  }
22720
- function installLotPerimeter(K, shared) {
23122
+ function installLotPerimeter(K, shared2) {
22721
23123
  const { EPS: EPS3, boxC, bx, colorOf, cursor, freeSpans, pieceRecord } = K;
22722
23124
  const makeApi = (...a) => K.makeApi(...a);
22723
23125
  const sh = (...a) => K.sh(...a);
22724
23126
  function perimeter() {
22725
- const R = shared.ctx.r, lt = R.lot, C = shared.ctx.colors;
23127
+ const R = shared2.ctx.r, lt = R.lot, C = shared2.ctx.colors;
22726
23128
  if (!lt) return;
22727
23129
  cursor.group = "lot";
22728
23130
  const rnd = /* @__PURE__ */ (() => {
@@ -22736,7 +23138,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22736
23138
  const th = s.thickness || 0.15, h = s.height, color2 = colorOf(s.color) != null ? colorOf(s.color) : C.wall || 12104874, len = b - a;
22737
23139
  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);
22738
23140
  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 };
22739
- shared.ctx.colliders.push(col);
23141
+ shared2.ctx.colliders.push(col);
22740
23142
  if (s.type === "wall") {
22741
23143
  B("plaster", a, 0, b, h, th, color2);
22742
23144
  B("plaster", a, h, b, h + 0.05, th + 0.06, sh(color2, 1.15));
@@ -22775,7 +23177,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22775
23177
  const w2 = x1 - x0, cm = (x0 + x1) / 2;
22776
23178
  const M = top === "razor_wire" ? { x: alongU ? cm : L, z: alongU ? L : cm, ry: alongU ? 0 : K.PE, w: w2, d: 0.4, h: 0.4, y: ym, base: 0, floor: -1, colors: C, seed: s.id } : { x: alongU ? cm : L, z: alongU ? L : cm, ry: alongU ? 0 : K.PE, w: w2, d: 0.1, h: 0.3, y: 0, base: ym, floor: -1, colors: C, seed: s.id };
22777
23179
  try {
22778
- shared.ctx.mv.builders[top](M, api);
23180
+ shared2.ctx.mv.builders[top](M, api);
22779
23181
  } catch (e) {
22780
23182
  console.warn(e);
22781
23183
  }
@@ -22796,7 +23198,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22796
23198
  }
22797
23199
  }
22798
23200
  function paths() {
22799
- const lt = shared.ctx.r.lot;
23201
+ const lt = shared2.ctx.r.lot;
22800
23202
  if (!lt || !lt.paths) return;
22801
23203
  cursor.group = "lot";
22802
23204
  for (const c of lt.paths) {
@@ -22809,14 +23211,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22809
23211
  }
22810
23212
  Object.assign(K, { perimeter, paths });
22811
23213
  }
22812
- function installLotGates(K, shared) {
23214
+ function installLotGates(K, shared2) {
22813
23215
  const { bx, colorOf, cursor, cylBase } = K;
22814
23216
  const sh = (...a) => K.sh(...a);
22815
23217
  function slideDirection(g, lt) {
22816
23218
  return g.u + g.width / 2 + g.width + 1.2 <= lt.rect[2] ? 1 : -1;
22817
23219
  }
22818
23220
  function gates() {
22819
- const R = shared.ctx.r, lt = R.lot, C = shared.ctx.colors;
23221
+ const R = shared2.ctx.r, lt = R.lot, C = shared2.ctx.colors;
22820
23222
  if (!lt) return;
22821
23223
  cursor.group = "lot";
22822
23224
  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;
@@ -22890,12 +23292,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22890
23292
  bx("emissive", mx + 0.1, 0.28, zc + sd * 0.452, mx + 0.14, 0.31, zc + sd * 0.455, 6479994);
22891
23293
  }
22892
23294
  }
22893
- if (!g.open || ped) shared.ctx.colliders.push({ type: "gate", f: -1, x0: a, z0: v - 0.1, x1: b, z1: v + 0.1 });
23295
+ if (!g.open || ped) shared2.ctx.colliders.push({ type: "gate", f: -1, x0: a, z0: v - 0.1, x1: b, z1: v + 0.1 });
22894
23296
  }
22895
23297
  }
22896
23298
  Object.assign(K, { slideDirection, gates });
22897
23299
  }
22898
- function installRoofRoofs(K, shared) {
23300
+ function installRoofRoofs(K, shared2) {
22899
23301
  const { rectsOf: rectsOf2, EPS: EPS3, OPEN_AREA, Y0, bx, cursor } = K;
22900
23302
  const gutter = (...a) => K.gutter(...a);
22901
23303
  const gutterConfig = (...a) => K.gutterConfig(...a);
@@ -22903,14 +23305,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22903
23305
  const sh = (...a) => K.sh(...a);
22904
23306
  const slabs = (...a) => K.slabs(...a);
22905
23307
  function roofs() {
22906
- const R = shared.ctx.r, F = R.facade, C = shared.ctx.colors, nA = R.floors.length, type = F.roof;
23308
+ const R = shared2.ctx.r, F = R.facade, C = shared2.ctx.colors, nA = R.floors.length, type = F.roof;
22907
23309
  cursor.group = "roof";
22908
- shared.ctx.roofRects = [];
22909
- shared.ctx.gutter = gutterConfig();
22910
- shared.ctx.gutter.ncond = 0;
22911
- shared.ctx.gutter.nbuz = 0;
22912
- shared.ctx.gutter.bz = /* @__PURE__ */ new Set();
22913
- shared.ctx.gutterInfo = { gutters: [], downpipes: [], drains: [] };
23310
+ shared2.ctx.roofRects = [];
23311
+ shared2.ctx.gutter = gutterConfig();
23312
+ shared2.ctx.gutter.ncond = 0;
23313
+ shared2.ctx.gutter.nbuz = 0;
23314
+ shared2.ctx.gutter.bz = /* @__PURE__ */ new Set();
23315
+ shared2.ctx.gutterInfo = { gutters: [], downpipes: [], drains: [] };
22914
23316
  const roofColor = C.roof != null ? C.roof : 11031610, gable = (R.seed | 0) % 2 === 0;
22915
23317
  for (let f = 0; f < nA; f++) {
22916
23318
  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);
@@ -22933,7 +23335,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22933
23335
  return Y0(f) + Math.max(...cs.map((c) => c.ceiling)) + 0.2;
22934
23336
  };
22935
23337
  if (type === "slab") {
22936
- for (let j = 0; j < nz; j++) for (let i = 0; i < nx; i++) if (O(j, i)) shared.ctx.roofRects.push({ f, r: [xs[i], zs[j], xs[i + 1], zs[j + 1]], slab: true, yb: pe(xs[i], zs[j], xs[i + 1], zs[j + 1]) + 0.03 });
23338
+ 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 });
22937
23339
  slabs(f, xs, zs, O, U, nx, nz, full, pe, C);
22938
23340
  cursor.pc = null;
22939
23341
  continue;
@@ -22956,36 +23358,36 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22956
23358
  if (U(q.j0 - 1, i)) touchesU[1] = 1;
22957
23359
  if (U(q.j1 + 1, i)) touchesU[3] = 1;
22958
23360
  }
22959
- shared.ctx.roofRects.push({ f, r: [x0, z0, x1, z1], touchesU });
23361
+ shared2.ctx.roofRects.push({ f, r: [x0, z0, x1, z1], touchesU });
22960
23362
  const ybq = pe(x0, z0, x1, z1);
22961
23363
  roofRect(type, x0, z0, x1, z1, ybq, roofColor, gable && single, F, touchesU);
22962
23364
  cursor.pc = null;
22963
- if (shared.ctx.gutter.on) gutter(type, f, x0, z0, x1, z1, ybq, touchesU);
23365
+ if (shared2.ctx.gutter.on) gutter(type, f, x0, z0, x1, z1, ybq, touchesU);
22964
23366
  }
22965
23367
  }
22966
- for (const e of shared.ctx.outbuildingList || []) {
23368
+ for (const e of shared2.ctx.outbuildingList || []) {
22967
23369
  const [x0, z0, x1, z1] = e.aabb, yb = Y0(0) + (e.ceiling || 2.6) + 0.2;
22968
- shared.ctx.roofRects.push({ f: 0, r: [x0, z0, x1, z1], outbuilding: e.id });
23370
+ shared2.ctx.roofRects.push({ f: 0, r: [x0, z0, x1, z1], outbuilding: e.id });
22969
23371
  if (type === "slab") {
22970
23372
  const c = C.facade != null ? C.facade : 14209216;
22971
23373
  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));
22972
23374
  for (const [a, b, c2, d] of [[x0 - 0.08, z0 - 0.08, x1 + 0.08, z0 - 0.04], [x0 - 0.08, z1 + 0.04, x1 + 0.08, z1 + 0.08], [x0 - 0.08, z0 - 0.08, x0 - 0.04, z1 + 0.08], [x1 + 0.04, z0 - 0.08, x1 + 0.08, z1 + 0.08]]) bx("plaster", a, yb, b, c2, yb + 0.4, d, c);
22973
23375
  continue;
22974
23376
  }
22975
- shared.ctx.noPiece = true;
23377
+ shared2.ctx.noPiece = true;
22976
23378
  roofRect(type, x0, z0, x1, z1, yb, roofColor, true, F, [0, 0, 0, 0]);
22977
23379
  cursor.pc = null;
22978
- shared.ctx.noPiece = false;
22979
- if (shared.ctx.gutter.on) gutter(type, 0, x0, z0, x1, z1, yb, [0, 0, 0, 0]);
23380
+ shared2.ctx.noPiece = false;
23381
+ if (shared2.ctx.gutter.on) gutter(type, 0, x0, z0, x1, z1, yb, [0, 0, 0, 0]);
22980
23382
  }
22981
23383
  }
22982
23384
  Object.assign(K, { roofs });
22983
23385
  }
22984
- function installRoofGutters(K, shared) {
23386
+ function installRoofGutters(K, shared2) {
22985
23387
  const { boxC, bx, cursor, roomAt } = K;
22986
23388
  const sh = (...a) => K.sh(...a);
22987
23389
  function gutterConfig() {
22988
- const R = shared.ctx.r, structure = R.style, high = structure === "high" || structure === "luxury", p = high || structure === "mid" ? 0.6 : 0.3;
23390
+ const R = shared2.ctx.r, structure = R.style, high = structure === "high" || structure === "luxury", p = high || structure === "mid" ? 0.6 : 0.3;
22989
23391
  let h = 2166136261;
22990
23392
  for (const ch of String(R.seed) + "|" + K.seedKey(R.template) + "|calha") h = Math.imul(h ^ ch.charCodeAt(0), 16777619);
22991
23393
  const rnd = () => {
@@ -22997,10 +23399,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
22997
23399
  const draw2 = rnd() < p, light = rnd() < 0.6;
22998
23400
  void draw2;
22999
23401
  const on = true;
23000
- return { on, rnd, color: high ? 3816770 : light ? 15527921 : 10857392, bad: (shared.ctx.colors.meta && shared.ctx.colors.meta.state) === "abandoned" || R.state === "abandoned", fallback: false };
23402
+ 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 };
23001
23403
  }
23002
23404
  function gutter(type, f, X0, Z0, X1, Z1, yb, touchesU) {
23003
- const G = shared.ctx.gutter, o = type === "fiber_cement" ? 0.3 : 0.45, x0 = X0 - (touchesU[0] ? 0 : o), x1 = X1 + (touchesU[2] ? 0 : o), z0 = Z0 - (touchesU[1] ? 0 : o), z1 = Z1 + (touchesU[3] ? 0 : o), c = G.color, y = yb - 0.05;
23405
+ 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;
23004
23406
  const run = (ax, a, b, p, outside, breaks) => {
23005
23407
  const seg2 = (u0, u1, tilt) => {
23006
23408
  const L = u1 - u0, m = (u0 + u1) / 2, dy = tilt ? -Math.abs(tilt) * L * 0.5 : 0;
@@ -23024,7 +23426,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23024
23426
  sides.forEach((l, i) => {
23025
23427
  if (l[0]) run(l[1], l[2], l[3], l[4], l[5], G.bad && !G.fallback && i === larger && (G.fallback = true));
23026
23428
  });
23027
- const INF = shared.ctx.gutterInfo || (shared.ctx.gutterInfo = { gutters: [], downpipes: [], drains: [] });
23429
+ const INF = shared2.ctx.gutterInfo || (shared2.ctx.gutterInfo = { gutters: [], downpipes: [], drains: [] });
23028
23430
  sides.forEach((l, i) => {
23029
23431
  if (l[0]) INF.gutters.push({ f, side: ["z0", "z1", "x0", "x1"][i], axis: l[1], a: l[2], b: l[3], p: l[4], y });
23030
23432
  });
@@ -23086,7 +23488,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23086
23488
  }
23087
23489
  Object.assign(K, { gutterConfig, gutter, drain });
23088
23490
  }
23089
- function installRoofSlabs(K, shared) {
23491
+ function installRoofSlabs(K, shared2) {
23090
23492
  const { boxC, bx, cursor, drain, roomAt, structurePiece } = K;
23091
23493
  const sh = (...a) => K.sh(...a);
23092
23494
  function slabs(f, xs, zs, O, U, nx, nz, full, pe, C) {
@@ -23116,15 +23518,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23116
23518
  side(free(j, i + 1), x1 + o - t, z0 - ez0, x1 + o, z1 + ez1);
23117
23519
  side(free(j - 1, i), x0 - ex0, z0 - o, x1 + ex1, z0 - o + t);
23118
23520
  side(free(j + 1, i), x0 - ex0, z1 + o - t, x1 + ex1, z1 + o);
23119
- if (shared.ctx.gutter && shared.ctx.gutter.on) for (const [ok, dx, dz] of [[free(j - 1, i), 0, -1], [free(j + 1, i), 0, 1], [free(j, i - 1), -1, 0], [free(j, i + 1), 1, 0]]) {
23521
+ 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]]) {
23120
23522
  const kd = f + ":" + dx + ":" + dz;
23121
- if (!ok || shared.ctx.gutter.bz.has(kd)) continue;
23122
- shared.ctx.gutter.bz.add(kd);
23123
- shared.ctx.gutter.nbuz++;
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 = shared.ctx.gutter.color;
23523
+ if (!ok || shared2.ctx.gutter.bz.has(kd)) continue;
23524
+ shared2.ctx.gutter.bz.add(kd);
23525
+ shared2.ctx.gutter.nbuz++;
23526
+ 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;
23125
23527
  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);
23126
23528
  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));
23127
- if (shared.ctx.gutter.bad) boxC("plain", ex + dx * 0.05, yb + 0.5 * 0, ez + dz * 0.05, dx ? 0.06 : 0.3, 0.02, dz ? 0.06 : 0.3, 4868674);
23529
+ 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);
23128
23530
  {
23129
23531
  const tx = ex + dx * 0.38, tz = ez + dz * 0.38;
23130
23532
  let lv = true;
@@ -23137,8 +23539,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23137
23539
  boxC("plain", tx, 0.9, tz, 0.12, 0.04, 0.12, sh(cc, 0.8));
23138
23540
  const rx = tx + dx * 0.24, rz = tz + dz * 0.24;
23139
23541
  drain(rx, rz, tx, tz, cc);
23140
- (shared.ctx.gutterInfo || (shared.ctx.gutterInfo = { gutters: [], downpipes: [], drains: [] })).downpipes.push({ f, x: tx, z: tz, y0: 0.045, y1: yb + 0.04, drain: [rx, rz], hornBox: true });
23141
- shared.ctx.gutterInfo.drains.push({ x: rx, z: rz });
23542
+ (shared2.ctx.gutterInfo || (shared2.ctx.gutterInfo = { gutters: [], downpipes: [], drains: [] })).downpipes.push({ f, x: tx, z: tz, y0: 0.045, y1: yb + 0.04, drain: [rx, rz], hornBox: true });
23543
+ shared2.ctx.gutterInfo.drains.push({ x: rx, z: rz });
23142
23544
  }
23143
23545
  }
23144
23546
  }
@@ -23146,10 +23548,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23146
23548
  }
23147
23549
  Object.assign(K, { slabs });
23148
23550
  }
23149
- function installRoofTiles(K, shared) {
23551
+ function installRoofTiles(K, shared2) {
23150
23552
  const { UV_SCALE, _Y, _h2, _q, accFor, cursor, put, rgbOf, structurePiece } = K;
23151
23553
  const sh = (...a) => K.sh(...a);
23152
- const R_STYLE = () => shared.ctx.r && shared.ctx.r.style || "budget";
23554
+ const R_STYLE = () => shared2.ctx.r && shared2.ctx.r.style || "budget";
23153
23555
  function tileRelief(mat, pts, color2, type) {
23154
23556
  const n = pts.length;
23155
23557
  if (n < 3) return;
@@ -23190,7 +23592,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23190
23592
  S.push(rx * ex + ry * ey + rz * ez);
23191
23593
  T2.push(rx * dx + ry * dy + rz * dz);
23192
23594
  }
23193
- const colonial = type !== "fiber_cement", P = colonial ? 0.2 : 0.177, A = colonial ? 0.032 : 0.0255, seg2 = shared.quality === "game" ? colonial ? 4 : 4 : colonial ? 8 : 6, h = P / seg2;
23595
+ const colonial = type !== "fiber_cement", P = colonial ? 0.2 : 0.177, A = colonial ? 0.032 : 0.0255, seg2 = shared2.quality === "game" ? colonial ? 4 : 4 : colonial ? 8 : 6, h = P / seg2;
23194
23596
  const smin = Math.min(...S), smax = Math.max(...S);
23195
23597
  if (smax - smin < 1e-4) return;
23196
23598
  const xs = new Set(S.map((v) => +v.toFixed(5)));
@@ -23262,9 +23664,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23262
23664
  }
23263
23665
  }
23264
23666
  function pieceOfPane(x, z) {
23265
- if (shared.ctx.noPiece || !shared.ctx.panes.length) return null;
23667
+ if (shared2.ctx.noPiece || !shared2.ctx.panes.length) return null;
23266
23668
  let m = null, md = 1e9;
23267
- for (const a of shared.ctx.panes) {
23669
+ for (const a of shared2.ctx.panes) {
23268
23670
  const b = a.aabb;
23269
23671
  if (!b) continue;
23270
23672
  const dx = x < b[0] ? b[0] - x : x > b[2] ? x - b[2] : 0, dz = z < b[1] ? b[1] - z : z > b[3] ? z - b[3] : 0, d = Math.hypot(dx, dz) * 1e3 + (b[2] - b[0]) * (b[3] - b[1]) * 1e-3;
@@ -23277,11 +23679,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23277
23679
  }
23278
23680
  Object.assign(K, { R_STYLE, tileRelief, ridge, pieceOfPane });
23279
23681
  }
23280
- function installRoofRect(K, shared) {
23682
+ function installRoofRect(K, shared2) {
23281
23683
  const { R_STYLE, bx, cursor, pieceOfPane, polyFace, ridge, tileRelief } = K;
23282
23684
  const sh = (...a) => K.sh(...a);
23283
23685
  function roofRect(type, X0, Z0, X1, Z1, yb, roofColor, gable, F, touchesU = [0, 0, 0, 0]) {
23284
- const C = shared.ctx.colors, 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), dx = x1 - x0, dz = z1 - z0, xm = (x0 + x1) / 2, zm = (z0 + z1) / 2;
23686
+ const C = shared2.ctx.colors, 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), dx = x1 - x0, dz = z1 - z0, xm = (x0 + x1) / 2, zm = (z0 + z1) / 2;
23285
23687
  const mat = type === "fiber_cement" ? "fiber_cement" : "tile", tp = type === "fiber_cement" ? 0.2 : 0.5, alongX = dx >= dz, up = [0, 1, 0];
23286
23688
  const Q = (pts) => {
23287
23689
  let cx = 0, cz = 0;
@@ -23319,7 +23721,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23319
23721
  }
23320
23722
  const rm = alongX ? dz / 2 : dx / 2;
23321
23723
  {
23322
- const rr = shared.ctx.roofRects[shared.ctx.roofRects.length - 1];
23724
+ const rr = shared2.ctx.roofRects[shared2.ctx.roofRects.length - 1];
23323
23725
  if (rr && !rr.yb) Object.assign(rr, { yb, tp, gable: !!gable, alongX, exterior: [x0, z0, x1, z1], rm });
23324
23726
  }
23325
23727
  if (gable) {
@@ -23358,12 +23760,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23358
23760
  }
23359
23761
  Object.assign(K, { roofRect });
23360
23762
  }
23361
- function installMirrors(K, shared) {
23763
+ function installMirrors(K, shared2) {
23362
23764
  const { DOC, THREE, Reflector, MIRRORS, Y0, _Y, roomAt } = K;
23363
- shared.mirrorEnv = null;
23364
- shared.mirrorMat = null;
23765
+ shared2.mirrorEnv = null;
23766
+ shared2.mirrorMat = null;
23365
23767
  function mirrorEnv() {
23366
- if (shared.mirrorEnv) return shared.mirrorEnv;
23768
+ if (shared2.mirrorEnv) return shared2.mirrorEnv;
23367
23769
  const mk = (f) => {
23368
23770
  const c = DOC.createElement("canvas");
23369
23771
  c.width = c.height = 64;
@@ -23399,18 +23801,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23399
23801
  const t = new THREE.CubeTexture(faces);
23400
23802
  t.colorSpace = THREE.SRGBColorSpace;
23401
23803
  t.needsUpdate = true;
23402
- shared.mirrorEnv = t;
23403
- shared.mirrorMat = new THREE.MeshStandardMaterial({ color: 16054008, metalness: 1, roughness: 0.06, envMap: t, envMapIntensity: 1 });
23804
+ shared2.mirrorEnv = t;
23805
+ shared2.mirrorMat = new THREE.MeshStandardMaterial({ color: 16054008, metalness: 1, roughness: 0.06, envMap: t, envMapIntensity: 1 });
23404
23806
  return t;
23405
23807
  }
23406
23808
  const newMirrorState = () => ({ list: [], active: null, tmp: new THREE.Vector3(), house: null });
23407
- shared.mirrors = newMirrorState();
23809
+ shared2.mirrors = newMirrorState();
23408
23810
  function assembleMirrors(groups) {
23409
- shared.mirrors.list.length = 0;
23410
- shared.mirrors.active = null;
23811
+ shared2.mirrors.list.length = 0;
23812
+ shared2.mirrors.active = null;
23411
23813
  if (!MIRRORS.length) return;
23412
23814
  mirrorEnv();
23413
- if (shared.quality === "game" || !Reflector) {
23815
+ if (shared2.quality === "game" || !Reflector) {
23414
23816
  const by = /* @__PURE__ */ new Map(), m4 = new THREE.Matrix4(), qy = new THREE.Quaternion(), um = new THREE.Vector3(1, 1, 1), ps = new THREE.Vector3(), nm = new THREE.Matrix3(), v = new THREE.Vector3();
23415
23817
  for (const E of MIRRORS) {
23416
23818
  const geo = new THREE.PlaneGeometry(E.w, E.h);
@@ -23437,7 +23839,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23437
23839
  g.setAttribute("uv", new THREE.Float32BufferAttribute(B.U, 2));
23438
23840
  g.setIndex(B.I);
23439
23841
  g.computeBoundingSphere();
23440
- const m = new THREE.Mesh(g, shared.mirrorMat);
23842
+ const m = new THREE.Mesh(g, shared2.mirrorMat);
23441
23843
  m.name = "mirror/environment";
23442
23844
  m.userData.part = "mirror";
23443
23845
  (groups[parent] || (groups[parent] = new THREE.Group())).add(m);
@@ -23452,7 +23854,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23452
23854
  g.userData.part = "mirror";
23453
23855
  g.userData.room = E.room;
23454
23856
  const geo = new THREE.PlaneGeometry(E.w, E.h);
23455
- const fake = new THREE.Mesh(geo, shared.mirrorMat);
23857
+ const fake = new THREE.Mesh(geo, shared2.mirrorMat);
23456
23858
  fake.userData.part = "mirror";
23457
23859
  fake.name = "mirror/environment";
23458
23860
  g.add(fake);
@@ -23468,27 +23870,27 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23468
23870
  console.warn("mirror real", e);
23469
23871
  }
23470
23872
  (groups[E.parent] || (groups[E.parent] = new THREE.Group())).add(g);
23471
- shared.mirrors.list.push({ E, g, fake, real });
23873
+ shared2.mirrors.list.push({ E, g, fake, real });
23472
23874
  }
23473
23875
  }
23474
23876
  function floorAtY(y) {
23475
- const A = shared.ctx.r.floors;
23877
+ const A = shared2.ctx.r.floors;
23476
23878
  let f = 0;
23477
23879
  for (let i = 0; i < A.length; i++) if (y >= A[i].y0 - 0.2) f = i;
23478
23880
  return f;
23479
23881
  }
23480
23882
  function chooseMirror(camera) {
23481
- if (!shared.mirrors.list.length) return;
23883
+ if (!shared2.mirrors.list.length) return;
23482
23884
  let target = null;
23483
- if (shared.mirrors.house && shared.ctx.r) {
23484
- shared.mirrors.tmp.copy(camera.position);
23485
- shared.mirrors.house.worldToLocal(shared.mirrors.tmp);
23486
- const f = floorAtY(shared.mirrors.tmp.y), c = roomAt(f, shared.mirrors.tmp.x, shared.mirrors.tmp.z);
23487
- if (c && shared.mirrors.tmp.y > Y0(f) && shared.mirrors.tmp.y < Y0(f) + 4) {
23885
+ if (shared2.mirrors.house && shared2.ctx.r) {
23886
+ shared2.mirrors.tmp.copy(camera.position);
23887
+ shared2.mirrors.house.worldToLocal(shared2.mirrors.tmp);
23888
+ const f = floorAtY(shared2.mirrors.tmp.y), c = roomAt(f, shared2.mirrors.tmp.x, shared2.mirrors.tmp.z);
23889
+ if (c && shared2.mirrors.tmp.y > Y0(f) && shared2.mirrors.tmp.y < Y0(f) + 4) {
23488
23890
  let best = 1e9;
23489
- for (const m of shared.mirrors.list) {
23891
+ for (const m of shared2.mirrors.list) {
23490
23892
  if (m.E.room !== c.id || m.E.floor !== f || !m.g.parent || !m.g.parent.visible) continue;
23491
- const d = Math.hypot(m.E.x - shared.mirrors.tmp.x, m.E.z - shared.mirrors.tmp.z);
23893
+ const d = Math.hypot(m.E.x - shared2.mirrors.tmp.x, m.E.z - shared2.mirrors.tmp.z);
23492
23894
  if (d < best) {
23493
23895
  best = d;
23494
23896
  target = m;
@@ -23496,9 +23898,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23496
23898
  }
23497
23899
  }
23498
23900
  }
23499
- if (target === shared.mirrors.active) return;
23500
- shared.mirrors.active = target;
23501
- for (const m of shared.mirrors.list) {
23901
+ if (target === shared2.mirrors.active) return;
23902
+ shared2.mirrors.active = target;
23903
+ for (const m of shared2.mirrors.list) {
23502
23904
  const on = m === target && !!m.real;
23503
23905
  if (m.real) m.real.visible = on;
23504
23906
  m.fake.visible = !on;
@@ -23506,7 +23908,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23506
23908
  }
23507
23909
  Object.assign(K, { mirrorEnv, newMirrorState, assembleMirrors, floorAtY, chooseMirror });
23508
23910
  }
23509
- function installCars(K, shared) {
23911
+ function installCars(K, shared2) {
23510
23912
  const { THREE, FLEET, _Y } = K;
23511
23913
  const CARS = [];
23512
23914
  const CAR_BY_STYLE = Object.assign({
@@ -23532,12 +23934,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23532
23934
  return b;
23533
23935
  }
23534
23936
  function carModel(k, seed) {
23535
- const kc = k + "|" + shared.quality + "|" + (seed || 0);
23937
+ const kc = k + "|" + shared2.quality + "|" + (seed || 0);
23536
23938
  if (CAR_CACHE.has(kc)) return CAR_CACHE.get(kc);
23537
23939
  if (!FLEET) return null;
23538
23940
  let res = null;
23539
23941
  try {
23540
- const v0 = FLEET.build(k, { quality: shared.quality, seed: seed || 0 }), c = { root: v0.group, g: v0.group };
23942
+ const v0 = FLEET.build(k, { quality: shared2.quality, seed: seed || 0 }), c = { root: v0.group, g: v0.group };
23541
23943
  c.root.updateMatrixWorld(true);
23542
23944
  const inv = new THREE.Matrix4();
23543
23945
  const byMaterial = /* @__PURE__ */ new Map(), tmp = new THREE.Matrix4(), v = new THREE.Vector3(), nm = new THREE.Matrix3(), bb = new THREE.Box3();
@@ -23657,7 +24059,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23657
24059
  return g;
23658
24060
  }
23659
24061
  function assembleCars(groups) {
23660
- if (shared.quality === "game") return assembleMergedCars(groups);
24062
+ if (shared2.quality === "game") return assembleMergedCars(groups);
23661
24063
  for (const C of CARS) {
23662
24064
  const g = carGroup(C.k, C.w, C.d, C.seed);
23663
24065
  if (!g) continue;
@@ -23710,10 +24112,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23710
24112
  }
23711
24113
  Object.assign(K, { CARS, CAR_BY_STYLE, CAR_CACHE, materialSignature, BUCKETS, bucketMaterial, carModel, carGroup, assembleCars, assembleMergedCars });
23712
24114
  }
23713
- function installHouseBuilding(K, shared) {
24115
+ function installHouseBuilding(K, shared2) {
23714
24116
  const { bx, cursor } = K;
23715
24117
  function building() {
23716
- const R = shared.ctx.r, P = R.building, C = shared.ctx.colors, N = shared.ctx.pa, uf = shared.ctx.pf, pe = P.ceilingHeight, fa = C.facade != null ? C.facade : 14209216;
24118
+ const R = shared2.ctx.r, P = R.building, C = shared2.ctx.colors, N = shared2.ctx.pa, uf = shared2.ctx.pf, pe = P.ceilingHeight, fa = C.facade != null ? C.facade : 14209216;
23717
24119
  cursor.group = "building";
23718
24120
  const uw = P.unit.w, ud = P.unit.d, un = P.units;
23719
24121
  const unitBox = (u) => {
@@ -23721,7 +24123,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23721
24123
  return [x[0], z[0], x[1], z[1]];
23722
24124
  };
23723
24125
  const un0 = unitBox(un[0]), color2 = P.corridor, hall = P.hall, el = P.elevator.rect, es = P.stairs.rect;
23724
- const sel = un[shared.ctx.pu] || un[0], selR = unitBox(sel);
24126
+ const sel = un[shared2.ctx.pu] || un[0], selR = unitBox(sel);
23725
24127
  const shell = (rc, y0, y1, thickness = 0.15) => {
23726
24128
  const [a, b, c, d] = rc;
23727
24129
  bx("building", a, y0, b, c, y1, b + thickness, fa);
@@ -23760,11 +24162,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23760
24162
  }
23761
24163
  const ytop = N * pe - 0.2;
23762
24164
  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);
23763
- shared.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) };
24165
+ 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) };
23764
24166
  }
23765
24167
  Object.assign(K, { building });
23766
24168
  }
23767
- function installUtilitiesWater(K, shared) {
24169
+ function installUtilitiesWater(K, shared2) {
23768
24170
  const { THREE, _Y, _q, cursor, cylBase, part, pieceRecord, put } = K;
23769
24171
  function createWater(r, state) {
23770
24172
  const H = r.utilities.plumbing, cap = H ? +H.capacityL || 0 : 0, ls = { dry: [], full: [] }, points = {}, itemPoint = {};
@@ -23856,14 +24258,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23856
24258
  }
23857
24259
  const _v3 = new THREE.Vector3();
23858
24260
  function waterPipes() {
23859
- const H = shared.ctx.r.utilities.plumbing;
24261
+ const H = shared2.ctx.r.utilities.plumbing;
23860
24262
  if (!H || !H.visibleRuns) return;
23861
- const nA = shared.ctx.r.floors.length;
24263
+ const nA = shared2.ctx.r.floors.length;
23862
24264
  const groupOf = (c) => c && c.floor >= 0 ? "f" + Math.min(c.floor, nA - 1) : "lot", xyz = (p) => [p[0], p[2], p[1]];
23863
24265
  for (const tr of H.visibleRuns) {
23864
24266
  const pts = tr.points.map(xyz), d = tr.diameter || 0.025;
23865
24267
  if (tr.exposed === "wall") {
23866
- const pt = H.points.find((p) => p.run === tr.id), com = shared.ctx.roomById[tr.to], g2 = groupOf(com || pt && { floor: pt.floor });
24268
+ const pt = H.points.find((p) => p.run === tr.id), com = shared2.ctx.roomById[tr.to], g2 = groupOf(com || pt && { floor: pt.floor });
23867
24269
  part("wall_pipe", [0, 0, 0], () => {
23868
24270
  for (let i = 0; i + 1 < pts.length; i++) pipe(pts[i], pts[i + 1], d, PIPE_COLOR);
23869
24271
  for (const p of pts) cylBase("plain", p[0], p[1] - d, p[2], d * 0.7, d * 2, PIPE_COLOR);
@@ -23871,7 +24273,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23871
24273
  continue;
23872
24274
  }
23873
24275
  let g;
23874
- if (tr.exposed === "tank_outlet") g = shared.ctx.waterTankPos && shared.ctx.waterTankPos.group || "f0";
24276
+ if (tr.exposed === "tank_outlet") g = shared2.ctx.waterTankPos && shared2.ctx.waterTankPos.group || "f0";
23875
24277
  else {
23876
24278
  const pt = H.points.find((p) => p.id === tr.to);
23877
24279
  g = groupOf(pt);
@@ -23887,15 +24289,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23887
24289
  }
23888
24290
  Object.assign(K, { createWater, PIPE_COLOR, pipe, _v3, waterPipes });
23889
24291
  }
23890
- function installUtilitiesElectrical(K, shared) {
24292
+ function installUtilitiesElectrical(K, shared2) {
23891
24293
  const { _Y, _q, _v3, bx, cursor, cylBase, pieceRecord, put } = K;
23892
24294
  const sh = (...a) => K.sh(...a);
23893
24295
  function electricalStructure() {
23894
- const E = shared.ctx.r.utilities.electrical;
23895
- shared.ctx.electricalInfo = null;
24296
+ const E = shared2.ctx.r.utilities.electrical;
24297
+ shared2.ctx.electricalInfo = null;
23896
24298
  if (!E) return;
23897
- const R = shared.ctx.r, nA = R.floors.length, lotGroup = R.lot ? "lot" : "f0", concreteColor = 11973547, iron = 4869200, wireRun = 1842206, info = { pole: null, meter: null, panel: null, conduits: [], outlets: [], switches: [], circuits: E.circuits || [], exposed: !!E.exposed };
23898
- const en22 = E.serviceEntrance, KV = shared.ctx.iv ? shared.ctx.iv.plane : null;
24299
+ 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 };
24300
+ const en22 = E.serviceEntrance, KV = shared2.ctx.iv ? shared2.ctx.iv.plane : null;
23899
24301
  const wireL = (a, b, r_ = 8e-3) => {
23900
24302
  const L = Math.hypot(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
23901
24303
  if (L < 1e-3) return;
@@ -23973,7 +24375,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23973
24375
  info.conduits.push(t.id);
23974
24376
  continue;
23975
24377
  }
23976
- const c = circ[t.circuit], com = c && shared.ctx.roomById[c.room];
24378
+ const c = circ[t.circuit], com = c && shared2.ctx.roomById[c.room];
23977
24379
  cursor.group = "f" + Math.max(0, Math.min(nA - 1, com ? com.floor : 0));
23978
24380
  const d = t.diameter || 0.02, P = t.points.map((p) => [p[0], p[2], p[1]]), seg2 = [];
23979
24381
  for (let i = 0; i + 1 < P.length; i++) {
@@ -23991,7 +24393,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
23991
24393
  }
23992
24394
  for (const t of E.outlets || []) info.outlets.push({ id: t.id, pos: [t.u, t.y, t.v], normal: [t.frontU || 0, 0, t.frontV || 0], room: t.room, floor: t.floor, type: t.type, voltage: t.voltage });
23993
24395
  for (const t of E.switches || []) info.switches.push({ id: t.id, pos: [t.u, t.y, t.v], normal: [t.frontU || 0, 0, t.frontV || 0], room: t.room, floor: t.floor, controls: t.controls });
23994
- shared.ctx.electricalInfo = info;
24396
+ shared2.ctx.electricalInfo = info;
23995
24397
  }
23996
24398
  function pipe2(a, b, diameter, color2) {
23997
24399
  const dx = b[0] - a[0], dy = b[1] - a[1], dz = b[2] - a[2], L = Math.hypot(dx, dy, dz);
@@ -24001,11 +24403,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24001
24403
  }
24002
24404
  Object.assign(K, { electricalStructure, pipe2 });
24003
24405
  }
24004
- function installHouseBaseboard(K, shared) {
24406
+ function installHouseBaseboard(K, shared2) {
24005
24407
  const { Y0, bx, cursor, sideOf } = K;
24006
24408
  const sh = (...a) => K.sh(...a);
24007
24409
  function baseboardAndSidewalk() {
24008
- const R = shared.ctx.r, W = 0.6, t = 0.012, ht = 0.35, color2 = sh(shared.ctx.colors.facade != null ? shared.ctx.colors.facade : 14209216, 0.62), y0 = Y0(0), cal = 13947078;
24410
+ const R = shared2.ctx.r, W = 0.6, t = 0.012, ht = 0.35, color2 = sh(shared2.ctx.colors.facade != null ? shared2.ctx.colors.facade : 14209216, 0.62), y0 = Y0(0), cal = 13947078;
24009
24411
  const ws = R.walls.filter((w) => w.floor === 0 && w.type === "wall").map((w) => {
24010
24412
  const au = w.axis === "u";
24011
24413
  return { w, au, L: au ? w.v0 : w.u0, a: Math.min(au ? w.u0 : w.v0, au ? w.u1 : w.v1), b: Math.max(au ? w.u0 : w.v0, au ? w.u1 : w.v1), th: w.thickness || 0.15 };
@@ -24037,11 +24439,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24037
24439
  }
24038
24440
  Object.assign(K, { baseboardAndSidewalk });
24039
24441
  }
24040
- function installUtilitiesSolar(K, shared) {
24442
+ function installUtilitiesSolar(K, shared2) {
24041
24443
  const { Y0, boxC, bx, cursor, cylBase } = K;
24042
24444
  function roofHeightAt(u, v, f) {
24043
24445
  let y = null;
24044
- for (const rr of shared.ctx.roofRects || []) {
24446
+ for (const rr of shared2.ctx.roofRects || []) {
24045
24447
  if (rr.yb == null || f != null && rr.f !== f) continue;
24046
24448
  if (rr.slab) {
24047
24449
  const [a, b, c, d] = rr.r;
@@ -24056,8 +24458,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24056
24458
  return y;
24057
24459
  }
24058
24460
  function solar() {
24059
- const R = shared.ctx.r, S = R.utilities.solar;
24060
- shared.ctx.solarInfo = null;
24461
+ const R = shared2.ctx.r, S = R.utilities.solar;
24462
+ shared2.ctx.solarInfo = null;
24061
24463
  if (!S || !S.panels || !S.panels.length) return;
24062
24464
  cursor.group = "roof";
24063
24465
  const silver = 13225426, blue = 1780302, line = 9279142, sv = S.north === "front" ? -1 : 1, info = { type: S.type, panels: [], inverter: null }, onRack = S.type === "slab_rack";
@@ -24099,15 +24501,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24099
24501
  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);
24100
24502
  bx("emissive", iv.u - 0.03, y0 - 0.12, iv.v + fa0, iv.u + 0.03, y0 - 0.09, iv.v + fa1, 6479994);
24101
24503
  }
24102
- const top = Math.max(...(shared.ctx.roofRects || []).filter((t2) => t2.yb != null).map((t2) => t2.yb), Y0(fa) + 2.8);
24504
+ const top = Math.max(...(shared2.ctx.roofRects || []).filter((t2) => t2.yb != null).map((t2) => t2.yb), Y0(fa) + 2.8);
24103
24505
  cylBase("plain", iv.u, y0 + h / 2, iv.v, 0.016, Math.max(0.2, top - 0.2 - (y0 + h / 2)), 15262936);
24104
24506
  info.inverter = { id: iv.id, pos: [iv.u, y0, iv.v], side: iv.side, link: iv.link };
24105
24507
  }
24106
- shared.ctx.solarInfo = info;
24508
+ shared2.ctx.solarInfo = info;
24107
24509
  }
24108
24510
  Object.assign(K, { roofHeightAt, solar });
24109
24511
  }
24110
- function installHouseOutbuildings(K, shared) {
24512
+ function installHouseOutbuildings(K, shared2) {
24111
24513
  const { t, bx, cursor, floorColor } = K;
24112
24514
  const sh = (...a) => K.sh(...a);
24113
24515
  const OUTBUILDING_USE = { guest_room: ["bedroom", "bedroom", t("outbuilding.guest_room")], office: ["office", "office", t("outbuilding.office")], storage: ["stockroom", "stockroom", t("outbuilding.storage")], gourmet: ["living", "gourmet", t("outbuilding.gourmet")] };
@@ -24139,17 +24541,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24139
24541
  return Object.assign({}, r, { rooms, walls, doors, windows, items });
24140
24542
  }
24141
24543
  function outbuildings() {
24142
- const E = (shared.ctx.r.outbuildings || []).filter((e) => shared.ctx.roomById[e.id] && shared.ctx.roomById[e.id].outbuilding);
24143
- shared.ctx.outbuildingList = E;
24544
+ const E = (shared2.ctx.r.outbuildings || []).filter((e) => shared2.ctx.roomById[e.id] && shared2.ctx.roomById[e.id].outbuilding);
24545
+ shared2.ctx.outbuildingList = E;
24144
24546
  if (!E.length) return;
24145
24547
  cursor.group = "f0";
24146
24548
  for (const e of E) {
24147
- const c = shared.ctx.roomById[e.id], col = floorColor(c);
24549
+ const c = shared2.ctx.roomById[e.id], col = floorColor(c);
24148
24550
  for (const [a, b, c2, d] of e.interior) bx("plaster", a - 0.075, 0, b - 0.075, c2 + 0.075, 0.04, d + 0.075, col);
24149
24551
  for (const p of e.doors || []) {
24150
24552
  const alongU = p.axis === "u", th = e.thickness || 0.15;
24151
- if (alongU) bx("plaster", p.at - p.width / 2, 0, p.pos - th / 2 - 0.12, p.at + p.width / 2, 0.03, p.pos + th / 2 + 0.12, sh(shared.ctx.colors.facade || 14209216, 0.8));
24152
- else bx("plaster", p.pos - th / 2 - 0.12, 0, p.at - p.width / 2, p.pos + th / 2 + 0.12, 0.03, p.at + p.width / 2, sh(shared.ctx.colors.facade || 14209216, 0.8));
24553
+ if (alongU) bx("plaster", p.at - p.width / 2, 0, p.pos - th / 2 - 0.12, p.at + p.width / 2, 0.03, p.pos + th / 2 + 0.12, sh(shared2.ctx.colors.facade || 14209216, 0.8));
24554
+ else bx("plaster", p.pos - th / 2 - 0.12, 0, p.at - p.width / 2, p.pos + th / 2 + 0.12, 0.03, p.at + p.width / 2, sh(shared2.ctx.colors.facade || 14209216, 0.8));
24153
24555
  }
24154
24556
  }
24155
24557
  }
@@ -24883,10 +25285,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24883
25285
  }
24884
25286
  Object.assign(K, { typeTable });
24885
25287
  }
24886
- function installFurnitureTaps(K, shared) {
24887
- shared.tapCount = 0;
25288
+ function installFurnitureTaps(K, shared2) {
25289
+ shared2.tapCount = 0;
24888
25290
  function counterTap(K2, x, y, z, reach, back, meta = {}) {
24889
- const cr = 12896460, id = "tap_" + (K2.M.seed || "") + "_" + shared.tapCount++;
25291
+ const cr = 12896460, id = "tap_" + (K2.M.seed || "") + "_" + shared2.tapCount++;
24890
25292
  K2.c("metal", x, y, z, 0.028, 0.012, cr);
24891
25293
  K2.c("metal", x, y + 0.012, z, 0.014, 0.12, cr);
24892
25294
  const pts = [];
@@ -24917,7 +25319,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
24917
25319
  return id;
24918
25320
  }
24919
25321
  function wallTap(K2, x, y, zw, direction, back, meta = {}) {
24920
- const cr = 12896460, id = "tap_" + (K2.M.seed || "") + "_" + shared.tapCount++, s = direction || 1;
25322
+ const cr = 12896460, id = "tap_" + (K2.M.seed || "") + "_" + shared2.tapCount++, s = direction || 1;
24921
25323
  K2.t("metal", [x, y, zw], [x, y, zw + s * 0.025], 0.03, cr);
24922
25324
  K2.t("metal", [x, y, zw + s * 0.02], [x, y, zw + s * 0.1], 0.016, cr);
24923
25325
  K2.e("metal", x, y, zw + s * 0.105, 0.019, 0.04, cr);
@@ -25167,7 +25569,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25167
25569
  }
25168
25570
  Object.assign(K, { GREENS: GREENS2, FLOWERS, blobs, potModel, arcLeaf, tuft, palm_tree, treeModel, shrubModel, potPlant, tablePot, planterModel });
25169
25571
  }
25170
- function installFurnitureYard(K, shared) {
25572
+ function installFurnitureYard(K, shared2) {
25171
25573
  const seedKey = (id) => K.seedKey(id);
25172
25574
  const { FURNITURE, SEED, STYLE, kit2, rngString, sh, wallTap } = K;
25173
25575
  FURNITURE.laundry_tub = function(M, A) {
@@ -25257,7 +25659,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25257
25659
  }
25258
25660
  }
25259
25661
  }, { id: "laundry_" + M.seed, swing: true, room: "yard" });
25260
- (shared.ctx.clotheslines || (shared.ctx.clotheslines = [])).push(M.seed);
25662
+ (shared2.ctx.clotheslines || (shared2.ctx.clotheslines = [])).push(M.seed);
25261
25663
  };
25262
25664
  FURNITURE.water_tank = function(M, A) {
25263
25665
  const K2 = kit2(M, A), w = M.w || 1, d = M.d || 1, onGround = !M.onSlab && (M.y || 0) < 0.5, color2 = M.palette && M.palette.tank_water != null ? M.palette.tank_water : 3107496, r = Math.min(w, d) * 0.46, rc = 11841700;
@@ -25399,13 +25801,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25399
25801
  }
25400
25802
  Object.assign(K, { extraTypes });
25401
25803
  }
25402
- function installFurniturePlaceItems(K, shared) {
25804
+ function installFurniturePlaceItems(K, shared2) {
25403
25805
  const { THREE, Y0, _col, boxC, colorOf, cursor, decorLights, makeApi, structurePiece } = K;
25404
25806
  const buildItem2 = (...a) => K.buildItem(...a);
25405
25807
  const registerCollision = (...a) => K.registerCollision(...a);
25406
25808
  const vegItem = (...a) => K.vegItem(...a);
25407
25809
  function houseItems() {
25408
- const R = shared.ctx.r, T2 = shared.ctx.types, api = makeApi(), noModel = /* @__PURE__ */ new Map();
25810
+ const R = shared2.ctx.r, T2 = shared2.ctx.types, api = makeApi(), noModel = /* @__PURE__ */ new Map();
25409
25811
  const list2 = R.items.concat(R.stateItems.filter((e) => e.w != null && e.d != null && e.type !== "razor_wire" && e.type !== "barbed_wire"));
25410
25812
  const rect = (poly) => {
25411
25813
  let a = 0;
@@ -25417,8 +25819,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25417
25819
  if (m.type === "stairs") continue;
25418
25820
  const exterior = m.outdoor || m.floor < 0, f = exterior ? -1 : Math.min(m.floor, R.floors.length - 1);
25419
25821
  cursor.group = exterior ? "lot" : "f" + f;
25420
- const com = shared.ctx.roomById[m.room], base = exterior ? 0 : Y0(f);
25421
- const M = { x: m.x, z: m.z, ry: m.ry || 0, w: m.w, d: m.d, h: m.h, y: m.y || 0, base, floor: exterior ? -1 : f, palette: shared.ctx.colors, color: m.category === "ground_cover" ? void 0 : colorOf(m.color) != null ? colorOf(m.color) : void 0, seed: m.id, room: m.room, typeWith: com ? com.type : null, ceiling: com ? com.ceiling : 2.9, on: shared.ctx.night, light: shared.ctx.night, lit: shared.ctx.night, open: !!m.doorOpen, overhead: m.overhead, assembly: m.assembly, hose: m.hose };
25822
+ const com = shared2.ctx.roomById[m.room], base = exterior ? 0 : Y0(f);
25823
+ 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 };
25422
25824
  if (m.category === "ground_cover" && m.polygon) {
25423
25825
  const xs = m.polygon.map((p) => p[0]), zs = m.polygon.map((p) => p[1]);
25424
25826
  M.x = (Math.min(...xs) + Math.max(...xs)) / 2;
@@ -25428,8 +25830,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25428
25830
  M.ry = 0;
25429
25831
  if (!rect(m.polygon)) M.poly = m.polygon.map((p) => [p[0] - M.x, p[1] - M.z]);
25430
25832
  }
25431
- if (shared.ctx.veg && vegItem(m, M, exterior ? "lot" : "f" + f)) continue;
25432
- if (shared.ctx.iv && shared.ctx.iv.replace.has(m.id)) {
25833
+ if (shared2.ctx.veg && vegItem(m, M, exterior ? "lot" : "f" + f)) continue;
25834
+ if (shared2.ctx.iv && shared2.ctx.iv.replace.has(m.id)) {
25433
25835
  registerCollision(m, M);
25434
25836
  continue;
25435
25837
  }
@@ -25461,13 +25863,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25461
25863
  return noModel;
25462
25864
  }
25463
25865
  function waterTankOfHouse(api) {
25464
- const cd = shared.ctx.r.waterTank;
25465
- if (!cd || !shared.ctx.types.water_tank) return;
25466
- const lc = cd.place === "raised_slab" && cd.platform, slab = cd.place === "slab" || !!lc, nA = shared.ctx.r.floors.length, f = Math.max(0, Math.min(nA - 1, cd.floor));
25467
- const base = lc ? cd.platform.topY : cd.y + (shared.ctx.r.rooms.some((c) => c.id === cd.room && c.type === "terrace") ? 0 : 0.2 + (slab ? 0.03 : 0));
25866
+ const cd = shared2.ctx.r.waterTank;
25867
+ if (!cd || !shared2.ctx.types.water_tank) return;
25868
+ const lc = cd.place === "raised_slab" && cd.platform, slab = cd.place === "slab" || !!lc, nA = shared2.ctx.r.floors.length, f = Math.max(0, Math.min(nA - 1, cd.floor));
25869
+ const base = lc ? cd.platform.topY : cd.y + (shared2.ctx.r.rooms.some((c) => c.id === cd.room && c.type === "terrace") ? 0 : 0.2 + (slab ? 0.03 : 0));
25468
25870
  cursor.group = slab ? "f" + f : "attic_tank";
25469
25871
  if (lc) {
25470
- const P = cd.platform, [x0, z0, x1, z1] = P.aabb, e = P.thickness, color2 = shared.ctx.colors.slab != null ? shared.ctx.colors.slab : 12170668;
25872
+ const P = cd.platform, [x0, z0, x1, z1] = P.aabb, e = P.thickness, color2 = shared2.ctx.colors.slab != null ? shared2.ctx.colors.slab : 12170668;
25471
25873
  cursor.pc = structurePiece("tank_slab");
25472
25874
  boxC("plain", (x0 + x1) / 2, P.topY - e / 2, (z0 + z1) / 2, x1 - x0, e, z1 - z0, color2, 0, 0, 0);
25473
25875
  P.pillars.forEach((p, k) => {
@@ -25477,13 +25879,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25477
25879
  cursor.pc = null;
25478
25880
  }
25479
25881
  if (!slab) {
25480
- const color2 = shared.ctx.colors.slab != null ? shared.ctx.colors.slab : 12170668, yp = Y0(f), hw = cd.w / 2 + 0.1, hd = cd.d / 2 + 0.1;
25882
+ const color2 = shared2.ctx.colors.slab != null ? shared2.ctx.colors.slab : 12170668, yp = Y0(f), hw = cd.w / 2 + 0.1, hd = cd.d / 2 + 0.1;
25481
25883
  boxC("plain", cd.u, base - 0.06, cd.v, hw * 2, 0.12, hd * 2, color2);
25482
25884
  for (const sx of [-1, 1]) for (const sz of [-1, 1]) boxC("plain", cd.u + sx * (hw - 0.07), (yp + base - 0.12) / 2, cd.v + sz * (hd - 0.07), 0.1, base - 0.12 - yp, 0.1, color2);
25483
25885
  }
25484
- const M = { x: cd.u, z: cd.v, ry: 0, w: cd.w, d: cd.d, h: cd.h + 0.12, y: 0, base, floor: f, colors: shared.ctx.colors, seed: "water_tank", room: cd.room, onSlab: true, ceiling: 2.9 };
25485
- shared.ctx.waterTankPos = { x: cd.u, z: cd.v, y: base, group: cursor.group };
25486
- shared.ctx.types.water_tank.f(M, api);
25886
+ const M = { x: cd.u, z: cd.v, ry: 0, w: cd.w, d: cd.d, h: cd.h + 0.12, y: 0, base, floor: f, colors: shared2.ctx.colors, seed: "water_tank", room: cd.room, onSlab: true, ceiling: 2.9 };
25887
+ shared2.ctx.waterTankPos = { x: cd.u, z: cd.v, y: base, group: cursor.group };
25888
+ shared2.ctx.types.water_tank.f(M, api);
25487
25889
  }
25488
25890
  function hashColor(s) {
25489
25891
  let h = 7;
@@ -25493,11 +25895,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25493
25895
  function labeledBox(m, M, group) {
25494
25896
  const color2 = M.color != null ? M.color : hashColor(m.category || m.type), h = Math.max(0.05, m.h || 0.5);
25495
25897
  boxC("plain", m.x, M.base + (m.y || 0) + h / 2, m.z, m.w, h, m.d, color2, 0, m.ry || 0, 0);
25496
- shared.ctx.labels.push({ pos: new THREE.Vector3(m.x, M.base + (m.y || 0) + h + 0.15, m.z), text: m.type, group, type: "no_model" });
25898
+ 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" });
25497
25899
  }
25498
25900
  Object.assign(K, { houseItems, waterTankOfHouse, hashColor, labeledBox });
25499
25901
  }
25500
- function installVegetationBridge(K, shared) {
25902
+ function installVegetationBridge(K, shared2) {
25501
25903
  const seedKey = (id) => K.seedKey(id);
25502
25904
  const { THREE, SEED, rngString } = K;
25503
25905
  const VEG_POT = ["potted_areca", "potted_snake_plant", "potted_fern"], VEG_CACTUS = { cactus_mandacaru: "mandacaru", cactus_palm: "prickly_pear", cactus_crown: "crown_cactus", cactus_xique: "xique_xique", cactus_pot: "potted_cactus" };
@@ -25523,7 +25925,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25523
25925
  for (const k of Object.keys(VEG_CACTUS)) VEG_MAP[k] = [VEG_CACTUS[k]];
25524
25926
  const VEG_PLANTER = { planter_bed: ["rose_bush_red", "rose_bush_pink", "rose_bush_white", "marigold", "periwinkle_pink", "periwinkle_white", "daisy"], planter_bed_small: ["rose_bush_red", "marigold", "periwinkle_pink", "daisy"], garden_bed: ["lawn_tuft", "wild_flowers"] };
25525
25927
  function vegItem(m, M, group) {
25526
- const V = shared.ctx.veg;
25928
+ const V = shared2.ctx.veg;
25527
25929
  if (!V) return false;
25528
25930
  const ids = VEG_MAP[m.type], can2 = VEG_PLANTER[m.type];
25529
25931
  if (!ids && !can2) return false;
@@ -25564,7 +25966,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25564
25966
  return true;
25565
25967
  }
25566
25968
  function assembleVegetation(groups) {
25567
- const V = shared.ctx.veg;
25969
+ const V = shared2.ctx.veg;
25568
25970
  if (!V) return;
25569
25971
  let pl = 0, tri = 0;
25570
25972
  const col = [], lod = [0, 0, 0], mats = V.mats();
@@ -25587,17 +25989,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25587
25989
  for (const c of lot.colliders) col.push(Object.assign({ y: G.y, group: G.group }, c));
25588
25990
  for (let i = 0; i < 3; i++) lod[i] += lot.lodCounts[i];
25589
25991
  }
25590
- shared.ctx.vegInfo = { plants: pl, triangles: tri, colliders: col, lodCounts: lod, materials: mats };
25992
+ shared2.ctx.vegInfo = { plants: pl, triangles: tri, colliders: col, lodCounts: lod, materials: mats };
25591
25993
  }
25592
25994
  Object.assign(K, { VEG_POT, VEG_CACTUS, VEG_MAP, VEG_PLANTER, vegItem, assembleVegetation });
25593
25995
  }
25594
- function installInteractionState(K, shared) {
25996
+ function installInteractionState(K, shared2) {
25595
25997
  const { THREE, cfg, colliderChanged, invalidateShadow, invalidate, UV_SCALE, applyPart, texture } = K;
25596
25998
  const ivRoomEffective = (...a) => K.ivRoomEffective(...a);
25597
25999
  const ivRoomLight = (...a) => K.ivRoomLight(...a);
25598
- shared.partState = /* @__PURE__ */ new Map();
26000
+ shared2.partState = /* @__PURE__ */ new Map();
25599
26001
  const newInteractiveState = () => ({ defs: /* @__PURE__ */ new Map(), items: [], pieces: [], lights: /* @__PURE__ */ new Map(), litRooms: /* @__PURE__ */ new Set(), objs: [], anim: /* @__PURE__ */ new Set(), msg: null, target: null });
25600
- shared.inter = newInteractiveState();
26002
+ shared2.inter = newInteractiveState();
25601
26003
  const MESSAGE_MS = 2200;
25602
26004
  UV_SCALE.doorWood = 1;
25603
26005
  UV_SCALE.doorPaint = 1;
@@ -25652,15 +26054,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25652
26054
  }
25653
26055
  const _EY = new THREE.Vector3(0, 1, 0), _UM3 = new THREE.Vector3(1, 1, 1);
25654
26056
  const hudMessage = (text) => {
25655
- shared.inter.msg = { text, until: performance.now() + MESSAGE_MS };
26057
+ shared2.inter.msg = { text, until: performance.now() + MESSAGE_MS };
25656
26058
  if (cfg.onMessage) cfg.onMessage(text);
25657
26059
  };
25658
26060
  function definePiece(name, def) {
25659
26061
  def.name = name;
25660
26062
  def.meshes = [];
25661
- def.t = def.target = shared.partState.has(name) ? shared.partState.get(name) : def.t0 || 0;
25662
- shared.inter.defs.set(name, def);
25663
- shared.inter.pieces.push(def);
26063
+ def.t = def.target = shared2.partState.has(name) ? shared2.partState.get(name) : def.t0 || 0;
26064
+ shared2.inter.defs.set(name, def);
26065
+ shared2.inter.pieces.push(def);
25664
26066
  return def;
25665
26067
  }
25666
26068
  const localOf = (M, lx, lz) => {
@@ -25672,7 +26074,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25672
26074
  return true;
25673
26075
  }
25674
26076
  function assembleInteractive(gs) {
25675
- for (const [name, def] of shared.inter.defs) {
26077
+ for (const [name, def] of shared2.inter.defs) {
25676
26078
  const g = gs[name];
25677
26079
  if (!g) continue;
25678
26080
  delete gs[name];
@@ -25694,13 +26096,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25694
26096
  const parent = def.leaf ? def.leaf.gs[def.k] : gs[def.parent] || (gs[def.parent] = new THREE.Group());
25695
26097
  if (parent) parent.add(outer);
25696
26098
  if (def.roomId) {
25697
- if (!shared.inter.lights.has(def.roomId)) shared.inter.lights.set(def.roomId, []);
25698
- shared.inter.lights.get(def.roomId).push(def);
26099
+ if (!shared2.inter.lights.has(def.roomId)) shared2.inter.lights.set(def.roomId, []);
26100
+ shared2.inter.lights.get(def.roomId).push(def);
25699
26101
  }
25700
26102
  applyPiece(def);
25701
26103
  }
25702
- for (const roomId of shared.inter.litRooms) applyLight(roomId);
25703
- shared.inter.defs.forEach((d) => {
26104
+ for (const roomId of shared2.inter.litRooms) applyLight(roomId);
26105
+ shared2.inter.defs.forEach((d) => {
25704
26106
  if (d.col) d.col.off = d.t > 0.5;
25705
26107
  });
25706
26108
  }
@@ -25740,8 +26142,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25740
26142
  }
25741
26143
  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 };
25742
26144
  function animateInteractive(dt) {
25743
- if (!shared.inter.anim.size) return;
25744
- for (const p of shared.inter.anim) {
26145
+ if (!shared2.inter.anim.size) return;
26146
+ for (const p of shared2.inter.anim) {
25745
26147
  const step = dt / (DURATION[p.kind] || 0.5), d = p.target - p.t;
25746
26148
  p.t = Math.abs(d) <= step ? p.target : p.t + Math.sign(d) * step;
25747
26149
  applyPiece(p);
@@ -25749,39 +26151,39 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25749
26151
  p.col.off = p.target > 0.5;
25750
26152
  colliderChanged(p.col);
25751
26153
  }
25752
- if (p.t === p.target) shared.inter.anim.delete(p);
26154
+ if (p.t === p.target) shared2.inter.anim.delete(p);
25753
26155
  }
25754
26156
  invalidateShadow();
25755
26157
  }
25756
26158
  function togglePiece(p) {
25757
26159
  p.target = p.target > 0.5 ? 0 : 1;
25758
- shared.partState.set(p.name, p.target);
26160
+ shared2.partState.set(p.name, p.target);
25759
26161
  if (p.col && p.col.off !== p.target > 0.5) {
25760
26162
  p.col.off = p.target > 0.5;
25761
26163
  colliderChanged(p.col);
25762
26164
  }
25763
- shared.inter.anim.add(p);
26165
+ shared2.inter.anim.add(p);
25764
26166
  }
25765
- const lightBase = (roomId) => roomId == null ? true : shared.partState.has("light:" + roomId) ? !!shared.partState.get("light:" + roomId) : !!shared.ctx.night;
26167
+ const lightBase = (roomId) => roomId == null ? true : shared2.partState.has("light:" + roomId) ? !!shared2.partState.get("light:" + roomId) : !!shared2.ctx.night;
25766
26168
  const lightOn = (roomId) => {
25767
- const S = roomId != null && shared.ctx.iv && shared.ctx.iv.roomStates.get(roomId);
26169
+ const S = roomId != null && shared2.ctx.iv && shared2.ctx.iv.roomStates.get(roomId);
25768
26170
  return S ? S.ef : lightBase(roomId);
25769
26171
  };
25770
26172
  function applyLight(roomId) {
25771
26173
  const on = lightOn(roomId);
25772
- for (const d of shared.inter.lights.get(roomId) || []) for (const m of d.meshes) if (m.name.endsWith("/emissive")) m.material = on ? shared.mats.emissive : shared.mats.off;
25773
- const sw = shared.inter.defs.get("ix:int:" + roomId);
26174
+ 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;
26175
+ const sw = shared2.inter.defs.get("ix:int:" + roomId);
25774
26176
  if (sw) {
25775
26177
  sw.target = on ? 1 : 0;
25776
- if (sw.t !== sw.target) shared.inter.anim.add(sw);
26178
+ if (sw.t !== sw.target) shared2.inter.anim.add(sw);
25777
26179
  }
25778
26180
  invalidate();
25779
26181
  }
25780
26182
  function toggleLight(roomId) {
25781
- const S = shared.ctx.iv && shared.ctx.iv.roomStates.get(roomId);
26183
+ const S = shared2.ctx.iv && shared2.ctx.iv.roomStates.get(roomId);
25782
26184
  if (S) {
25783
- ivRoomLight(shared.ctx.iv, roomId, !S.ef);
25784
- const ef = ivRoomEffective(shared.ctx.iv, S);
26185
+ ivRoomLight(shared2.ctx.iv, roomId, !S.ef);
26186
+ const ef = ivRoomEffective(shared2.ctx.iv, S);
25785
26187
  if (ef !== S.ef) {
25786
26188
  S.ef = ef;
25787
26189
  applyLight(roomId);
@@ -25789,13 +26191,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25789
26191
  }
25790
26192
  return;
25791
26193
  }
25792
- shared.partState.set("light:" + roomId, !lightOn(roomId));
26194
+ shared2.partState.set("light:" + roomId, !lightOn(roomId));
25793
26195
  applyLight(roomId);
25794
26196
  if (cfg.onLight) cfg.onLight(roomId, lightOn(roomId));
25795
26197
  }
25796
26198
  Object.assign(K, { newInteractiveState, MESSAGE_MS, createInteractiveMaterials, _EY, _UM3, hudMessage, definePiece, localOf, visibleChain, assembleInteractive, applyPiece, DURATION, animateInteractive, togglePiece, lightBase, lightOn, applyLight, toggleLight });
25797
26199
  }
25798
- function installInteractionCollision(K, shared) {
26200
+ function installInteractionCollision(K, shared2) {
25799
26201
  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)/;
25800
26202
  function registerCollision(m, M) {
25801
26203
  const h = m.h || 0, y = M.y || 0;
@@ -25805,7 +26207,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25805
26207
  w = Math.min(w, 0.5);
25806
26208
  d = Math.min(d, 0.5);
25807
26209
  }
25808
- shared.inter.objs.push({ f: M.floor, cx: m.x, cz: m.z, c: Math.cos(M.ry), s: Math.sin(M.ry), hw: w / 2, hd: d / 2, type: m.type });
26210
+ 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 });
25809
26211
  }
25810
26212
  function objectDistance(o, x, z) {
25811
26213
  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;
@@ -25813,7 +26215,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25813
26215
  }
25814
26216
  function collideObject(x, z, fx, fz, floor) {
25815
26217
  const R = 0.2;
25816
- for (const o of shared.inter.objs) {
26218
+ for (const o of shared2.inter.objs) {
25817
26219
  if (o.f !== -1 ? o.f !== floor : floor !== 0) continue;
25818
26220
  const d1 = objectDistance(o, x, z);
25819
26221
  if (d1 < R && d1 < objectDistance(o, fx, fz) - 1e-6) return true;
@@ -25823,7 +26225,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25823
26225
  function collideAt(x, z, floor, opt) {
25824
26226
  opt = opt || {};
25825
26227
  const R = opt.radius != null ? opt.radius : 0.24;
25826
- for (const c of shared.ctx.colliders) {
26228
+ for (const c of shared2.ctx.colliders) {
25827
26229
  if (c.off) continue;
25828
26230
  if (c.f !== -1 && c.f !== floor) continue;
25829
26231
  if (c.f === -1 && floor !== 0) continue;
@@ -25835,7 +26237,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25835
26237
  }
25836
26238
  Object.assign(K, { NO_COLLIDE, registerCollision, objectDistance, collideObject, collideAt });
25837
26239
  }
25838
- function installInteractionItems(K, shared) {
26240
+ function installInteractionItems(K, shared2) {
25839
26241
  const { t, LIGHTS, cursor, definePiece, localOf, registerCollision, togglePiece } = K;
25840
26242
  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)$/;
25841
26243
  const DRAWER_ITEM = /^(console_table|dresser|nightstand|vanity_table)$/;
@@ -25860,7 +26262,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25860
26262
  }
25861
26263
  function lightItem(m, M, ent, api, parent) {
25862
26264
  M.on = M.light = M.lit = true;
25863
- const n0 = LIGHTS.length, name = shared.quality === "game" ? "ix:light:" + m.room + "@" + parent : "ix:light:" + m.id;
26265
+ const n0 = LIGHTS.length, name = shared2.quality === "game" ? "ix:light:" + m.room + "@" + parent : "ix:light:" + m.id;
25864
26266
  cursor.group = name;
25865
26267
  try {
25866
26268
  ent.f(M, api);
@@ -25868,8 +26270,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25868
26270
  cursor.group = parent;
25869
26271
  }
25870
26272
  for (let i = n0; i < LIGHTS.length; i++) LIGHTS[i].roomId = m.room;
25871
- if (!shared.inter.defs.has(name)) definePiece(name, { kind: "light", pivot: [0, 0, 0], ry: 0, parent, roomId: m.room });
25872
- shared.inter.litRooms.add(m.room);
26273
+ if (!shared2.inter.defs.has(name)) definePiece(name, { kind: "light", pivot: [0, 0, 0], ry: 0, parent, roomId: m.room });
26274
+ shared2.inter.litRooms.add(m.room);
25873
26275
  }
25874
26276
  function curtainItem(m, M, ent, api, parent) {
25875
26277
  M.open = false;
@@ -25897,12 +26299,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25897
26299
  for (const c of body) api[c[0]](M, ...c[1]);
25898
26300
  if (!parts.length) return;
25899
26301
  const [ax, az] = localOf(M, 0, 0.2);
25900
- shared.inter.items.push({ type: "curtain", id: m.id, floor: M.floor, anchor: [ax, M.base + (M.y || 0) + (m.h || 2) * 0.5, az], range: 2.4, angle: 1, pieces: parts, text: () => t(parts[0].target > 0.5 ? "prompt.close" : "prompt.open", { what: t("what.curtain") }), action: () => {
26302
+ 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: () => {
25901
26303
  const al = parts[0].target > 0.5 ? 0 : 1;
25902
26304
  for (const p of parts) {
25903
26305
  p.target = al;
25904
- shared.partState.set(p.name, al);
25905
- shared.inter.anim.add(p);
26306
+ shared2.partState.set(p.name, al);
26307
+ shared2.inter.anim.add(p);
25906
26308
  }
25907
26309
  } });
25908
26310
  }
@@ -25972,8 +26374,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25972
26374
  p.def = def;
25973
26375
  parts.push(def);
25974
26376
  const [ax, az] = localOf(M, cx, front + 0.08);
25975
- shared.inter.items.push({ type: drawer ? "drawer" : "cabinet", id: m.id, floor: M.floor, anchor: [ax, M.base + (M.y || 0) + (p.y0 + p.y1) / 2, az], range: 1.6, angle: 0.4, pieces: [def], text: () => t(def.target > 0.5 ? "prompt.close" : "prompt.open", { what: t("what." + name) }), action: () => togglePiece(def) });
25976
- def.item = shared.inter.items[shared.inter.items.length - 1];
26377
+ 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) });
26378
+ def.item = shared2.inter.items[shared2.inter.items.length - 1];
25977
26379
  });
25978
26380
  calls.forEach((c, i) => {
25979
26381
  const p = owner.get(i);
@@ -25989,10 +26391,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
25989
26391
  }
25990
26392
  Object.assign(K, { DOOR_ITEM, DRAWER_ITEM, LIGHT_TYPES, objectName, recordApi, buildItem: buildItem2, lightItem, curtainItem, furnitureItem });
25991
26393
  }
25992
- function installInteractionFittings(K, shared) {
26394
+ function installInteractionFittings(K, shared2) {
25993
26395
  const { t, EPS: EPS3, OPEN_AREA, Y0, applyPiece, bx, cursor, definePiece, gates, lightOn, roomAt, slideDirection, toggleLight, togglePiece } = K;
25994
26396
  function gatesInteractive() {
25995
- const lt = shared.ctx.r.lot;
26397
+ const lt = shared2.ctx.r.lot;
25996
26398
  if (!lt) return;
25997
26399
  const cz0 = (lt.rect[1] + lt.rect[3]) / 2;
25998
26400
  const orig = K.getBx(), gs = lt.gates, opening = gs.map((g) => g.open), reg = gs.map((g) => {
@@ -26014,7 +26416,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26014
26416
  }
26015
26417
  return orig(mat, x0, y0, z0, x1, y1, z1, color2);
26016
26418
  });
26017
- const n0 = shared.ctx.colliders.length;
26419
+ const n0 = shared2.ctx.colliders.length;
26018
26420
  try {
26019
26421
  gs.forEach((g) => {
26020
26422
  g.open = false;
@@ -26026,7 +26428,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26026
26428
  g.open = opening[i];
26027
26429
  });
26028
26430
  }
26029
- const cols = shared.ctx.colliders.slice(n0), cz = (lt.rect[1] + lt.rect[3]) / 2, cu = (lt.rect[0] + lt.rect[2]) / 2;
26431
+ const cols = shared2.ctx.colliders.slice(n0), cz = (lt.rect[1] + lt.rect[3]) / 2, cu = (lt.rect[0] + lt.rect[2]) / 2;
26030
26432
  reg.forEach((r, i) => {
26031
26433
  const g = r.g;
26032
26434
  if (!isFinite(r.x0)) return;
@@ -26035,25 +26437,25 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26035
26437
  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 }));
26036
26438
  if (p.col) p.col.off = p.target > 0.5;
26037
26439
  const text = () => t(p.target > 0.5 ? "prompt.close" : "prompt.open", { what: t(ped ? "what.pedestrianGate" : "what.garageGate") });
26038
- shared.inter.items.push({ type: "gate", id: g.id, floor: -1, anchor: [g.u, 1, g.v + sd * 0.4], range: 2.8, angle: 0.9, pieces: [p], text, action: () => togglePiece(p), noWall: true });
26440
+ 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 });
26039
26441
  });
26040
26442
  }
26041
26443
  function mailboxInteractive() {
26042
- for (const m of shared.ctx.r.items) {
26444
+ for (const m of shared2.ctx.r.items) {
26043
26445
  if (m.type !== "mailbox") continue;
26044
- const g = shared.ctx.parts && shared.ctx.parts["mailbox_" + m.id];
26446
+ const g = shared2.ctx.parts && shared2.ctx.parts["mailbox_" + m.id];
26045
26447
  if (!g) continue;
26046
26448
  const name = "ix:correio:" + m.id, def = definePiece(name, { kind: "part", pivot: [0, 0, 0], ry: 0, parent: "lot" });
26047
26449
  def.inner = g;
26048
26450
  const fx = Math.sin(m.ry || 0), fz = Math.cos(m.ry || 0), ay = (m.y || 1) + (m.h || 0.3) * 0.4;
26049
- shared.inter.items.push({ type: "mailbox", id: m.id, floor: -1, anchor: [m.x + fx * 0.2, ay, m.z + fz * 0.2], range: 2.2, angle: 0.7, pieces: [def], text: () => t(def.target > 0.5 ? "prompt.close" : "prompt.open", { what: t("what.mailbox") }), action: () => togglePiece(def), noWall: true });
26451
+ 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 });
26050
26452
  applyPiece(def);
26051
26453
  }
26052
26454
  }
26053
26455
  function placeSwitches() {
26054
- const R = shared.ctx.r, used = /* @__PURE__ */ new Set();
26456
+ const R = shared2.ctx.r, used = /* @__PURE__ */ new Set();
26055
26457
  for (const c of R.rooms) {
26056
- if (c.type === "void" || OPEN_AREA(c) || !shared.inter.litRooms.has(c.id) || used.has(c.id) || shared.ctx.iv && shared.ctx.iv.switchRooms.has(c.id)) continue;
26458
+ 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;
26057
26459
  const doors = R.doors.filter((p) => p.floor === c.floor && (p.a === c.id || p.b === c.id));
26058
26460
  doors.sort((p, q) => ((q.exterior ? 1 : 0) - (p.exterior ? 1 : 0)) * (c.type === "living" ? 1 : -1));
26059
26461
  for (const p of doors) if (putSwitch(c, p)) {
@@ -26063,7 +26465,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26063
26465
  }
26064
26466
  }
26065
26467
  function putSwitch(c, p) {
26066
- const R = shared.ctx.r, f = p.floor, alongU = p.axis === "u", L = p.pos, a = p.at - p.width / 2, b = p.at + p.width / 2;
26468
+ 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;
26067
26469
  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;
26068
26470
  const inside2 = (sd2) => {
26069
26471
  const cc = roomAt(f, alongU ? p.at : L + sd2 * 0.4, alongU ? L + sd2 * 0.4 : p.at);
@@ -26090,17 +26492,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26090
26492
  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 });
26091
26493
  piece2.t = piece2.target = lightOn(roomId) ? 1 : 0;
26092
26494
  const an = alongU ? [u, yc, face + sd * 0.12] : [face + sd * 0.12, yc, u];
26093
- shared.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) });
26495
+ 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) });
26094
26496
  return true;
26095
26497
  }
26096
26498
  return false;
26097
26499
  }
26098
26500
  Object.assign(K, { gatesInteractive, mailboxInteractive, placeSwitches, putSwitch });
26099
26501
  }
26100
- function installInteractionDoors(K, shared) {
26502
+ function installInteractionDoors(K, shared2) {
26101
26503
  const { t, colliderChanged, invalidateShadow, applyPiece, hudMessage } = K;
26102
26504
  function linkDoorLeaves() {
26103
- for (const fo of shared.ctx.leaves) fo.handles = (fo.handleNames || []).map((n) => shared.inter.defs.get(n)).filter(Boolean);
26505
+ for (const fo of shared2.ctx.leaves) fo.handles = (fo.handleNames || []).map((n) => shared2.inter.defs.get(n)).filter(Boolean);
26104
26506
  }
26105
26507
  function handleApply(fo) {
26106
26508
  for (const mc of fo.handles || []) {
@@ -26112,7 +26514,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26112
26514
  if (fo.phase === "rattle") return;
26113
26515
  if (fo.phase === "handle" || fo.phase === "swing") {
26114
26516
  fo.open = !fo.open;
26115
- shared.doorState.set(fo.id, fo.open);
26517
+ shared2.doorState.set(fo.id, fo.open);
26116
26518
  fo.col.off = fo.open;
26117
26519
  colliderChanged(fo.col);
26118
26520
  fo.anim = true;
@@ -26122,25 +26524,25 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26122
26524
  if (fo.blockedFlag || fo.locked) {
26123
26525
  fo.phase = "rattle";
26124
26526
  fo.jig = 0.7;
26125
- shared.ctx.animateDoorsOn = true;
26527
+ shared2.ctx.animateDoorsOn = true;
26126
26528
  hudMessage(t(fo.blockedFlag ? "message.boarded" : "message.locked"));
26127
26529
  return;
26128
26530
  }
26129
26531
  fo.open = !fo.open;
26130
- shared.doorState.set(fo.id, fo.open);
26532
+ shared2.doorState.set(fo.id, fo.open);
26131
26533
  fo.col.off = fo.open;
26132
26534
  colliderChanged(fo.col);
26133
26535
  fo.anim = true;
26134
- shared.ctx.animateDoorsOn = true;
26536
+ shared2.ctx.animateDoorsOn = true;
26135
26537
  if (fo.handles && fo.handles.length) {
26136
26538
  fo.phase = "handle";
26137
26539
  fo.hT = fo.hT || 0;
26138
26540
  } else fo.phase = "swing";
26139
26541
  }
26140
26542
  function animateDoors(dt) {
26141
- if (!shared.ctx.animateDoorsOn) return;
26543
+ if (!shared2.ctx.animateDoorsOn) return;
26142
26544
  let active = false;
26143
- for (const fo of shared.ctx.leaves) {
26545
+ for (const fo of shared2.ctx.leaves) {
26144
26546
  if (!fo.phase) continue;
26145
26547
  active = true;
26146
26548
  if (fo.phase === "handle") {
@@ -26170,13 +26572,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26170
26572
  }
26171
26573
  }
26172
26574
  }
26173
- shared.ctx.animateDoorsOn = active;
26575
+ shared2.ctx.animateDoorsOn = active;
26174
26576
  invalidateShadow();
26175
26577
  }
26176
26578
  function wallBlocks(ex, ez, ax, az, floor) {
26177
- const n = shared.ctx.wallColliders != null ? shared.ctx.wallColliders : 0;
26579
+ const n = shared2.ctx.wallColliders != null ? shared2.ctx.wallColliders : 0;
26178
26580
  for (let i = 0; i < n; i++) {
26179
- const c = shared.ctx.colliders[i];
26581
+ const c = shared2.ctx.colliders[i];
26180
26582
  if (c.f !== floor && !(c.f === -1 && floor === 0)) continue;
26181
26583
  let t0 = 0, t1 = 1;
26182
26584
  const dx = ax - ex, dz = az - ez;
@@ -26208,7 +26610,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26208
26610
  }
26209
26611
  Object.assign(K, { linkDoorLeaves, handleApply, toggleDoor, animateDoors, wallBlocks, doorText, applyLeaf });
26210
26612
  }
26211
- function installInteractionTarget(K, shared) {
26613
+ function installInteractionTarget(K, shared2) {
26212
26614
  const { doorText, toggleDoor, visibleChain, wallBlocks } = K;
26213
26615
  const ivTarget = (...a) => K.ivTarget(...a);
26214
26616
  function targetOf(o, opt) {
@@ -26219,7 +26621,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26219
26621
  const tries = (score, text, action, target) => {
26220
26622
  if (!best || score < best.score) best = { score, text, action, target };
26221
26623
  };
26222
- for (const fo of shared.ctx.leaves) {
26624
+ for (const fo of shared2.ctx.leaves) {
26223
26625
  if (fo.floor !== floor) continue;
26224
26626
  const d = Math.hypot(fo.cx - ex, fo.cz - ez);
26225
26627
  if (d > 1.7) continue;
@@ -26227,11 +26629,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26227
26629
  if (angle > 1.35 && d > 0.9) continue;
26228
26630
  tries(angle * 1.6 + d * 0.5 + (angle < 0.25 ? 0 : 0.6), doorText(fo), () => toggleDoor(fo), fo);
26229
26631
  }
26230
- const vis = shared.inter.pieces.flatMap((p) => p.meshes).filter(visibleChain), hit = vis.length && opt.strike ? opt.strike(vis) : null;
26231
- const kitA = shared.ctx.iv ? ivTarget(shared.ctx.iv, o, opt && opt.interactives) : null;
26632
+ const vis = shared2.inter.pieces.flatMap((p) => p.meshes).filter(visibleChain), hit = vis.length && opt.strike ? opt.strike(vis) : null;
26633
+ const kitA = shared2.ctx.iv ? ivTarget(shared2.ctx.iv, o, opt && opt.interactives) : null;
26232
26634
  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;
26233
26635
  const pieceHit = hit && !nearKit && hit.object.userData.piece;
26234
- for (const it of shared.inter.items) {
26636
+ for (const it of shared2.inter.items) {
26235
26637
  if (it.floor !== floor && !(it.floor === -1 && floor === 0)) continue;
26236
26638
  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);
26237
26639
  if (dh > it.range + 0.4) continue;
@@ -26246,14 +26648,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26246
26648
  }
26247
26649
  Object.assign(K, { targetOf });
26248
26650
  }
26249
- function installInteractablesBridge(K, shared) {
26651
+ function installInteractablesBridge(K, shared2) {
26250
26652
  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;
26251
26653
  const enter = (...a) => K.enter(...a);
26252
26654
  const roomLightMask = (...a) => K.roomLightMask(...a);
26253
26655
  const IV_MATERIAL = { plain: "plain", metal: "metal", wood: "wood", glass: "glass", fabric: "fabric", plant: "plant", water: "water", emissive: "emissive", atlas_picture: "picture", atlas_floor: "floor" };
26254
26656
  const IV_WIRE = { conduit: 13618628, cable: 2762532, drop: 1381653, cord: 1776413, earth: 3111482, hose: 11556124 };
26255
26657
  const IV_DOOR = /^(door|drawer)/;
26256
- const ivGroup = (e) => e.floor < 0 ? "lot" : "f" + Math.min(e.floor, shared.ctx.r.floors.length - 1);
26658
+ const ivGroup = (e) => e.floor < 0 ? "lot" : "f" + Math.min(e.floor, shared2.ctx.r.floors.length - 1);
26257
26659
  function ivAccumulate(mat, g, ox, oy, oz, ry, color2) {
26258
26660
  const P = g.attributes.position, N = g.attributes.normal, C = color2 == null ? g.attributes.color : null, U = g.attributes.uv, I = g.index, nv = P.count, ni = I ? I.count : nv;
26259
26661
  const A = accFor(mat);
@@ -26297,7 +26699,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26297
26699
  A.ni += ni;
26298
26700
  }
26299
26701
  function ivBuild(h, water) {
26300
- const ik = K.IVK, r = shared.ctx.r, A = ik.A, world0 = null;
26702
+ const ik = K.IVK, r = shared2.ctx.r, A = ik.A, world0 = null;
26301
26703
  void world0;
26302
26704
  const plane2 = A.plan(r, { seed: r.seed });
26303
26705
  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 };
@@ -26318,7 +26720,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26318
26720
  const wants = (roomId) => lightBase(roomId);
26319
26721
  const entById = new Map(plane2.items.map((e) => [e.id, e]));
26320
26722
  const entByItem = new Map(plane2.items.map((e) => [e.item, e]));
26321
- IV.mats = { plain: shared.mats.plain, metal: shared.mats.metal, wood: shared.mats.wood, glass: shared.mats.glass, fabric: shared.mats.fabric, plant: shared.mats.plant, water: shared.mats.water, emissive: shared.mats.emissive, atlas_picture: shared.mats.picture, atlas_floor: shared.mats.floor };
26723
+ 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 };
26322
26724
  const ev = (e) => ivEvent(h, e);
26323
26725
  const world = IV.world = A.createWorld(r, { water, seed: r.seed, onEvent: ev });
26324
26726
  const add0 = world.add;
@@ -26326,7 +26728,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26326
26728
  const e = entById.get(id);
26327
26729
  if (e && e.type === "lamp") {
26328
26730
  const roomId = IV.lampRoom.get(id);
26329
- spec.devices[0].on = roomId ? wants(roomId) : !!shared.ctx.night;
26731
+ spec.devices[0].on = roomId ? wants(roomId) : !!shared2.ctx.night;
26330
26732
  spec.parts = (spec.parts || []).concat([{ id: "_x", pivot: [0, 0, 0], motion: { kind: "slide", axis: [0, 1, 0], distance: 1e-3 }, label: "" }]);
26331
26733
  spec.interactions = [{ id: "device.lamp", pos: [0, 0, 0], action: { do: "toggle_device", device: "lamp" }, label: "", requires: { object: id, part: "_x" } }];
26332
26734
  } else if (e && e.type === "wall_switch") {
@@ -26352,7 +26754,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26352
26754
  }
26353
26755
  if (e.type === "lamp" && o.devices && o.devices.lamp) {
26354
26756
  const roomId = IV.lampRoom.get(id);
26355
- o.devices.lamp.on = roomId ? wants(roomId) : !!shared.ctx.night;
26757
+ o.devices.lamp.on = roomId ? wants(roomId) : !!shared2.ctx.night;
26356
26758
  } else if (e.type === "wall_switch" && o.parts && o.parts.rocker !== void 0) {
26357
26759
  const l = (e.connections.controls || [])[0], roomId = l && IV.lampRoom.get(l);
26358
26760
  if (roomId) o.parts.rocker = wants(roomId) ? 1 : 0;
@@ -26444,7 +26846,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26444
26846
  const ik = IV.k, w = IV.world, wl = (o, p) => ik.GI.localToWorld(o.transform, p), g0 = cursor.group;
26445
26847
  const tube2 = (pts, radius, color2, ox, oy, oz, ry) => {
26446
26848
  try {
26447
- const m = ik.gfx.createCord(pts, radius, shared.mats.plain);
26849
+ const m = ik.gfx.createCord(pts, radius, shared2.mats.plain);
26448
26850
  ivAccumulate("plain", m.geometry, ox, oy, oz, ry, color2);
26449
26851
  m.geometry.dispose();
26450
26852
  } catch (e) {
@@ -26487,7 +26889,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26487
26889
  for (const E of IV.roots) {
26488
26890
  (gs[E.group] || (gs[E.group] = new THREE.Group())).add(E.root);
26489
26891
  }
26490
- for (const [roomId] of IV.roomStates) if (!shared.inter.litRooms.has(roomId)) IV.roomStates.delete(roomId);
26892
+ for (const [roomId] of IV.roomStates) if (!shared2.inter.litRooms.has(roomId)) IV.roomStates.delete(roomId);
26491
26893
  for (const E of IV.entries.values()) if (E.parts && Object.keys(E.parts).length) IV.k.gfx.syncObject(IV.world, E.id, E.parts, { time: 0 });
26492
26894
  for (const E of IV.entries.values()) if (E.screen) ivScreen(IV, E);
26493
26895
  }
@@ -26518,7 +26920,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26518
26920
  break;
26519
26921
  case "device": {
26520
26922
  const roomId = IV.lampRoom.get(e.object);
26521
- if (roomId) shared.partState.set("light:" + roomId, !!e.on);
26923
+ if (roomId) shared2.partState.set("light:" + roomId, !!e.on);
26522
26924
  invalidate();
26523
26925
  break;
26524
26926
  }
@@ -26671,7 +27073,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26671
27073
  gm.setIndex(new THREE.BufferAttribute(A.i.slice(0, A.ni), 1));
26672
27074
  gm.computeBoundingSphere();
26673
27075
  if (!IV.items) {
26674
- IV.items = new THREE.Mesh(gm, shared.mats.plain);
27076
+ IV.items = new THREE.Mesh(gm, shared2.mats.plain);
26675
27077
  IV.items.name = "iv-items";
26676
27078
  IV.items.castShadow = false;
26677
27079
  IV.items.receiveShadow = true;
@@ -26812,17 +27214,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26812
27214
  }
26813
27215
  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 });
26814
27216
  }
26815
- function installAnimationClotheslines(K, shared) {
27217
+ function installAnimationClotheslines(K, shared2) {
26816
27218
  const { invalidate, CLOTHES_UNIFORMS } = K;
26817
27219
  const WIND = { t0: performance.now(), last: 0, base: 0.55 };
26818
27220
  function animateClotheslines(now) {
26819
- if (!shared.ctx.clotheslines || !shared.ctx.clotheslines.length) return;
27221
+ if (!shared2.ctx.clotheslines || !shared2.ctx.clotheslines.length) return;
26820
27222
  if (now - WIND.last < 33) return;
26821
27223
  WIND.last = now;
26822
27224
  const t = (now - WIND.t0) / 1e3;
26823
27225
  CLOTHES_UNIFORMS.uTime.value = t;
26824
27226
  CLOTHES_UNIFORMS.uVento.value = WIND.base + 0.45 * Math.sin(t * 0.23) * Math.sin(t * 0.11 + 1.3) + 0.25 * Math.max(0, Math.sin(t * 0.57));
26825
- const g = shared.ctx.parts && shared.ctx.parts["laundry_" + shared.ctx.clotheslines[0]];
27227
+ const g = shared2.ctx.parts && shared2.ctx.parts["laundry_" + shared2.ctx.clotheslines[0]];
26826
27228
  if (g) {
26827
27229
  let vis = true;
26828
27230
  for (let n = g; n; n = n.parent) if (!n.visible) {
@@ -26835,30 +27237,30 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26835
27237
  }
26836
27238
  Object.assign(K, { WIND, animateClotheslines });
26837
27239
  }
26838
- function installBuildInstance(K, shared) {
27240
+ function installBuildInstance(K, shared2) {
26839
27241
  const { PROPS, THREE, DOC, cfg, HP, createInteractiveMaterials, createMaterials, typeTable } = K;
26840
27242
  const props = PROPS.create(THREE, { document: DOC, emit: () => {
26841
27243
  } });
26842
27244
  const TYPES = typeTable(props);
26843
- shared.mats = createMaterials(props);
26844
- createInteractiveMaterials(shared.mats);
27245
+ shared2.mats = createMaterials(props);
27246
+ createInteractiveMaterials(shared2.mats);
26845
27247
  if (cfg.materials) for (const k of Object.keys(cfg.materials)) {
26846
27248
  const v = cfg.materials[k];
26847
- shared.mats[k] = typeof v === "function" ? v(shared.mats[k], k) || shared.mats[k] : v;
27249
+ shared2.mats[k] = typeof v === "function" ? v(shared2.mats[k], k) || shared2.mats[k] : v;
26848
27250
  }
26849
27251
  const newState = () => ({ doors: /* @__PURE__ */ new Map(), inter: /* @__PURE__ */ new Map(), water: null, iv: null });
26850
27252
  function enter(h) {
26851
- shared.ctx = h.ctx;
26852
- shared.inter = h.inter;
26853
- shared.doorState = h.state.doors;
26854
- shared.partState = h.state.inter;
26855
- shared.mirrors = h.mirrors;
26856
- shared.quality = h.quality;
27253
+ shared2.ctx = h.ctx;
27254
+ shared2.inter = h.inter;
27255
+ shared2.doorState = h.state.doors;
27256
+ shared2.partState = h.state.inter;
27257
+ shared2.mirrors = h.mirrors;
27258
+ shared2.quality = h.quality;
26857
27259
  }
26858
27260
  const tagDamage = (type) => ({ type, hp: HP[type], hpMax: HP[type] });
26859
27261
  Object.assign(K, { props, TYPES, newState, enter, tagDamage });
26860
27262
  }
26861
- function installInteractablesKit(K, shared) {
27263
+ function installInteractablesKit(K, shared2) {
26862
27264
  const { t, THREE, DOC, cfg, Reflector } = K;
26863
27265
  const roomLightMask = (...a) => K.roomLightMask(...a);
26864
27266
  const IVK = (() => {
@@ -26876,15 +27278,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26876
27278
  const l = cfg.vegetation || null, G = l && (l.GameVegetation || (l.buildLot ? l : null)), S = l && (l.GameVegetationSpecies || (l.toSpec ? l : null));
26877
27279
  return G && S && G.buildLot && S.toSpec ? { G, S } : null;
26878
27280
  })();
26879
- shared.vegMaterials = null;
26880
- const vegMaterials = () => shared.vegMaterials || (shared.vegMaterials = (() => {
27281
+ shared2.vegMaterials = null;
27282
+ const vegMaterials = () => shared2.vegMaterials || (shared2.vegMaterials = (() => {
26881
27283
  const m = VEG.G.createVegetationMaterials(THREE);
26882
27284
  for (const k of ["wood", "foliage", "flowers", "fruit", "spines"]) roomLightMask(m[k]);
26883
27285
  return m;
26884
27286
  })());
26885
27287
  Object.assign(K, { IVK, VEG, vegMaterials });
26886
27288
  }
26887
- function installLightsRoomLight(K, shared) {
27289
+ function installLightsRoomLight(K, shared2) {
26888
27290
  const { THREE, rectsOf: rectsOf2 } = K;
26889
27291
  const MAX_LIGHTS = 12, EMPTY = [1e9, 1e9, -1e9, -1e9];
26890
27292
  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 } };
@@ -26923,7 +27325,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
26923
27325
  function lighting(o) {
26924
27326
  o = o || {};
26925
27327
  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;
26926
- for (const k of Object.keys(shared.mats)) roomLightMask(shared.mats[k]);
27328
+ for (const k of Object.keys(shared2.mats)) roomLightMask(shared2.mats[k]);
26927
27329
  const PL = [], sig = new Array(N).fill(""), seg2 = { n: 0 };
26928
27330
  for (let i = 0; i < N; i++) {
26929
27331
  const l = new THREE.PointLight(16763008, 0, 8, 1.6);
@@ -27116,9 +27518,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27116
27518
  }
27117
27519
  return view;
27118
27520
  }
27119
- function installDestructionPieces(K, shared) {
27521
+ function installDestructionPieces(K, shared2) {
27120
27522
  const { THREE, floorAtY, pieceRecord } = K;
27121
- shared.destructionSeq = 0;
27523
+ shared2.destructionSeq = 0;
27122
27524
  const FRAGMENT_COLOR = { brick: 11031866, concrete: 10132118, plaster: 14210248, ceramic: 11821630, glass: 11456472, tempered_glass: 11456472, wood_soft: 11569752, wood_hard: 8016948, plywood: 12098154, mdf: 12098154, steel: 9080466, aluminium: 12106944, plastic: 3107496, copper: 12088115, stone: 9079428, fabric: 13616296 };
27123
27525
  const FRAGMENT_GEO = new THREE.BoxGeometry(1, 1, 1), FRAGMENT_MAT = {};
27124
27526
  const fragmentMaterial = (m) => FRAGMENT_MAT[m] || (FRAGMENT_MAT[m] = new THREE.MeshLambertMaterial({ color: FRAGMENT_COLOR[m] != null ? FRAGMENT_COLOR[m] : 9079428 }));
@@ -27127,7 +27529,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27127
27529
  objs = objs.filter(Boolean);
27128
27530
  if (!objs.length) return;
27129
27531
  const pc = pieceRecord(id, mat, role, extra);
27130
- shared.ctx.pieceObjects.set(id, objs);
27532
+ shared2.ctx.pieceObjects.set(id, objs);
27131
27533
  for (const o of objs) o.traverse((m) => {
27132
27534
  if (!m.isMesh) return;
27133
27535
  const u = m.userData;
@@ -27138,22 +27540,22 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27138
27540
  if (pc.explodes) u.destructionExplodes = pc.explodes;
27139
27541
  });
27140
27542
  };
27141
- for (const fo of shared.ctx.leaves) {
27543
+ for (const fo of shared2.ctx.leaves) {
27142
27544
  const pr = r.doors.find((p) => p.id === fo.id);
27143
27545
  tagObject("door:" + fo.id, fo.gs, fo.type === "steel" ? "steel" : pr && pr.exterior ? "wood_hard" : "mdf", null, { floor: fo.floor, mass: fo.type === "steel" ? 60 : 18, tags: ["door"] });
27144
27546
  }
27145
27547
  const cap = r.utilities.plumbing ? +r.utilities.plumbing.capacityL || 0 : 0;
27146
- for (const [id, g] of Object.entries(shared.ctx.parts || {})) {
27548
+ for (const [id, g] of Object.entries(shared2.ctx.parts || {})) {
27147
27549
  const tp = g.userData.part;
27148
27550
  if (tp === "water_tank") {
27149
- const e = shared.ctx.structureIndex.water_tank, L = cap || (g.userData.volume ? Math.round(g.userData.volume * 1e3) : 0);
27551
+ const e = shared2.ctx.structureIndex.water_tank, L = cap || (g.userData.volume ? Math.round(g.userData.volume * 1e3) : 0);
27150
27552
  tagObject("water_tank", [g], "plastic", e ? e.role : null, { floor: e ? e.floor : 0, contains: L ? { fluid: "water", liters: L } : void 0, mass: e ? e.mass : 25, thickness: 4e-3, fill: 0.05, tags: ["tank"] });
27151
27553
  } else if (tp === "gas_cylinder") tagObject(id, [g], "steel", null, { mass: 11, form: "cylinder", thickness: 3e-3, fill: 0.03, contains: { fluid: "gas", liters: 13, pressurized: true }, explodes: { energy: 12e4, radius: 5, atC: 300 }, tags: ["gas_bottle"] });
27152
27554
  else if (tp === "wall_pipe") tagObject(id, [g], "plastic", null, { mass: 3, tags: ["pipe"] });
27153
27555
  else if (tp === "shower_door") tagObject(id, [g], "tempered_glass", null, { mass: 25 });
27154
27556
  else if (tp === "gate_leaf" || tp === "mailbox_door") tagObject(id, [g], "steel", null, { mass: 30 });
27155
27557
  }
27156
- for (const def of shared.inter.defs.values()) {
27558
+ for (const def of shared2.inter.defs.values()) {
27157
27559
  if (!def.outer) continue;
27158
27560
  if (/^gate/.test(def.kind)) tagObject(def.name, [def.outer], "steel", null, { mass: 80, tags: ["gate"] });
27159
27561
  else if (def.kind === "swing" || def.kind === "drawer") tagObject(def.name, [def.outer], "mdf", null, { mass: 6 });
@@ -27172,13 +27574,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27172
27574
  for (const f of o.userData.ranges) add(f.id, { mesh: o, v0: f.v0, v1: f.v1, i0: f.i0, i1: f.i1, whole: f.v0 === 0 && f.v1 === nv });
27173
27575
  }
27174
27576
  });
27175
- for (const [id, objs] of shared.ctx.pieceObjects) for (const o of objs) add(id, { obj: o });
27577
+ for (const [id, objs] of shared2.ctx.pieceObjects) for (const o of objs) add(id, { obj: o });
27176
27578
  const box32 = (id) => {
27177
27579
  const b = new THREE.Box3(), v = new THREE.Vector3();
27178
27580
  for (const it of meshes.get(id) || []) {
27179
27581
  if (it.obj) {
27180
27582
  const bb = new THREE.Box3().setFromObject(it.obj);
27181
- if (!bb.isEmpty()) for (const x of [bb.min.x, bb.max.x]) for (const y of [bb.min.y, bb.max.y]) for (const z of [bb.min.z, bb.max.z]) b.expandByPoint(v.set(x, y, z).applyMatrix4(shared.ctx.unitInverse));
27583
+ if (!bb.isEmpty()) for (const x of [bb.min.x, bb.max.x]) for (const y of [bb.min.y, bb.max.y]) for (const z of [bb.min.z, bb.max.z]) b.expandByPoint(v.set(x, y, z).applyMatrix4(shared2.ctx.unitInverse));
27182
27584
  } else {
27183
27585
  const P = it.mesh.geometry.attributes.position.array;
27184
27586
  for (let k = it.v0; k < it.v1; k++) b.expandByPoint(v.set(P[k * 3], P[k * 3 + 1], P[k * 3 + 2]));
@@ -27188,15 +27590,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27188
27590
  };
27189
27591
  const parts = [], byId = /* @__PURE__ */ new Map(), supports = E0.supports.map((a) => Object.assign({}, a));
27190
27592
  for (const e of E0.parts) {
27191
- const p = Object.assign({}, e, { meshes: (meshes.get(e.id) || []).length, extra: false }), pc = shared.ctx.pieces.get(e.id);
27593
+ const p = Object.assign({}, e, { meshes: (meshes.get(e.id) || []).length, extra: false }), pc = shared2.ctx.pieces.get(e.id);
27192
27594
  if (pc) {
27193
27595
  for (const k of ["contains", "explodes", "tags", "form", "thickness", "fill"]) if (pc[k] != null && p[k] == null) p[k] = pc[k];
27194
27596
  }
27195
27597
  parts.push(p);
27196
27598
  byId.set(p.id, p);
27197
27599
  }
27198
- const base = parts.length, view = shared.ctx.panelView || panelViewOf(null, false), panelIds = new Set(view.panels.map((e) => e.id));
27199
- for (const [id, pc] of shared.ctx.pieces) {
27600
+ const base = parts.length, view = shared2.ctx.panelView || panelViewOf(null, false), panelIds = new Set(view.panels.map((e) => e.id));
27601
+ for (const [id, pc] of shared2.ctx.pieces) {
27200
27602
  if (byId.has(id) || panelIds.has(id) || !meshes.has(id)) continue;
27201
27603
  const b = box32(id);
27202
27604
  if (!b) continue;
@@ -27230,7 +27632,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27230
27632
  parts.splice(0, parts.length, ...parts.filter((p) => !gone.has(p.id)));
27231
27633
  for (const id of gone) byId.delete(id);
27232
27634
  for (const e of view.panels) {
27233
- const p = Object.assign({}, e, { meshes: (meshes.get(e.id) || []).length, extra: false }), pc = shared.ctx.pieces.get(e.id);
27635
+ const p = Object.assign({}, e, { meshes: (meshes.get(e.id) || []).length, extra: false }), pc = shared2.ctx.pieces.get(e.id);
27234
27636
  if (pc) {
27235
27637
  for (const k of ["contains", "explodes", "tags", "form", "thickness", "fill"]) if (pc[k] != null && p[k] == null) p[k] = pc[k];
27236
27638
  }
@@ -27302,6 +27704,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27302
27704
  function collapseRange(mesh2, v0, v1) {
27303
27705
  const pos = mesh2.geometry.attributes.position;
27304
27706
  const a = pos.array;
27707
+ const u = mesh2.userData;
27708
+ if (!u._p0) u._p0 = a.slice();
27709
+ const list2 = u.collapsedRanges ?? (u.collapsedRanges = []);
27710
+ if (!list2.some((r) => r[0] === v0 && r[1] === v1)) list2.push([v0, v1]);
27305
27711
  const saved = a.slice(v0 * 3, v1 * 3);
27306
27712
  const x = a[v0 * 3], y = a[v0 * 3 + 1], z = a[v0 * 3 + 2];
27307
27713
  for (let k = v0; k < v1; k++) {
@@ -27316,6 +27722,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27316
27722
  const pos = mesh2.geometry.attributes.position;
27317
27723
  pos.array.set(saved, v0 * 3);
27318
27724
  pos.needsUpdate = true;
27725
+ const list2 = mesh2.userData.collapsedRanges;
27726
+ if (list2) mesh2.userData.collapsedRanges = list2.filter((r) => r[0] !== v0);
27319
27727
  }
27320
27728
  function noise2(x, y, cell) {
27321
27729
  const h = (i2, j2) => {
@@ -27330,13 +27738,22 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27330
27738
  var SPALL_MIN = 0.025;
27331
27739
  var SPALL_RAGGED = 0.045;
27332
27740
  var COVER2 = 0.015;
27741
+ var MAX_FLAKES = 64;
27742
+ function clipToBox(unit, box4) {
27743
+ const lo = [Math.max(unit.x - unit.sx / 2, box4[0]), Math.max(unit.y - unit.sy / 2, box4[1]), Math.max(unit.z - unit.sz / 2, box4[2])];
27744
+ const hi = [Math.min(unit.x + unit.sx / 2, box4[3]), Math.min(unit.y + unit.sy / 2, box4[4]), Math.min(unit.z + unit.sz / 2, box4[5])];
27745
+ if (hi[0] - lo[0] <= 1e-4 || hi[1] - lo[1] <= 1e-4 || hi[2] - lo[2] <= 1e-4) return null;
27746
+ return { x: (lo[0] + hi[0]) / 2, y: (lo[1] + hi[1]) / 2, z: (lo[2] + hi[2]) / 2, sx: hi[0] - lo[0], sy: hi[1] - lo[1], sz: hi[2] - lo[2], colour: unit.colour };
27747
+ }
27333
27748
  function installDestructionBreach(K, _shared) {
27334
27749
  const { THREE, fragmentMaterial, invalidate, invalidateShadow } = K;
27335
27750
  function createBreachView(opts) {
27336
27751
  const { house, structure } = opts;
27337
27752
  const views = /* @__PURE__ */ new Map();
27753
+ const dirty = /* @__PURE__ */ new Set();
27754
+ const paintBudgetMs = opts.paintBudgetMs ?? Infinity;
27755
+ const dropped = [];
27338
27756
  let lod = 0;
27339
- const unitMaterial = new THREE.MeshLambertMaterial({ color: 16777215 });
27340
27757
  const unitGeometry = new THREE.BoxGeometry(1, 1, 1);
27341
27758
  const tmp = { m: new THREE.Matrix4(), q: new THREE.Quaternion(), p: new THREE.Vector3(), s: new THREE.Vector3(), c: new THREE.Color() };
27342
27759
  const local = (p) => {
@@ -27405,6 +27822,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27405
27822
  const mesh2 = new THREE.Mesh(g, material);
27406
27823
  mesh2.name = "breach-shell";
27407
27824
  mesh2.userData.breachMask = mask;
27825
+ mesh2.userData.cutAt = (p) => {
27826
+ const v = local([p.x, p.y, p.z]);
27827
+ const i = Math.floor(((mask.alongU ? v[0] : v[2]) - mask.start) / mask.len * mask.w), j = Math.floor((v[1] - mask.y0) / mask.height * mask.h);
27828
+ return i >= 0 && i < mask.w && j >= 0 && j < mask.h && mask.data[j * mask.w + i] > 127;
27829
+ };
27408
27830
  mesh2.position.copy(it.mesh.position);
27409
27831
  mesh2.quaternion.copy(it.mesh.quaternion);
27410
27832
  mesh2.scale.copy(it.mesh.scale);
@@ -27420,6 +27842,29 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27420
27842
  toHouse.value.copy(house.matrixWorld).invert().multiply(mesh2.matrixWorld);
27421
27843
  return mesh2;
27422
27844
  }
27845
+ function unitsMaterial(core) {
27846
+ const material = new THREE.MeshLambertMaterial({ color: 16777215, side: THREE.DoubleSide });
27847
+ material.onBeforeCompile = (sh) => {
27848
+ sh.uniforms.uCore = { value: core.texture };
27849
+ sh.uniforms.uCoreRect = { value: core.rect };
27850
+ sh.uniforms.uCoreAlongX = { value: core.alongU ? 1 : 0 };
27851
+ sh.vertexShader = sh.vertexShader.replace("void main() {", "varying vec3 vHousePos;\nvoid main() {").replace("#include <begin_vertex>", "#include <begin_vertex>\n#ifdef USE_INSTANCING\nvHousePos = (instanceMatrix * vec4(transformed, 1.0)).xyz;\n#else\nvHousePos = transformed;\n#endif");
27852
+ sh.fragmentShader = sh.fragmentShader.replace("void main() {", "uniform sampler2D uCore;\nuniform vec4 uCoreRect;\nuniform float uCoreAlongX;\nvarying vec3 vHousePos;\nvoid main() {\n vec2 cUv = vec2(((uCoreAlongX > 0.5 ? vHousePos.x : vHousePos.z) - uCoreRect.x) / uCoreRect.z, (vHousePos.y - uCoreRect.y) / uCoreRect.w);\n if (cUv.x >= 0.0 && cUv.x <= 1.0 && cUv.y >= 0.0 && cUv.y <= 1.0 && texture2D(uCore, cUv).r > 0.5) discard;").replace("#include <color_fragment>", "#include <color_fragment>\nif (!gl_FrontFacing) diffuseColor.rgb *= 0.55;");
27853
+ };
27854
+ material.customProgramCacheKey = () => "breachCore";
27855
+ material.userData.breachCore = core;
27856
+ return material;
27857
+ }
27858
+ function drawnBounds(items) {
27859
+ house.updateMatrixWorld(true);
27860
+ const box4 = new THREE.Box3(), toHouse = new THREE.Matrix4().copy(house.matrixWorld).invert();
27861
+ for (const it of items) {
27862
+ const a = it.mesh.userData._p0 || it.mesh.geometry.attributes.position.array;
27863
+ tmp.m.multiplyMatrices(toHouse, it.mesh.matrixWorld);
27864
+ for (let k = it.v0; k < it.v1; k++) box4.expandByPoint(tmp.p.set(a[k * 3], a[k * 3 + 1], a[k * 3 + 2]).applyMatrix4(tmp.m));
27865
+ }
27866
+ return [box4.min.x, box4.min.y, box4.min.z, box4.max.x, box4.max.y, box4.max.z];
27867
+ }
27423
27868
  function maskOf(hostId, parts) {
27424
27869
  const host = structure.byId.get(hostId);
27425
27870
  const [u0, v0, u1, v1] = host.aabb;
@@ -27435,51 +27880,86 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27435
27880
  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) };
27436
27881
  }
27437
27882
  const boxDistance = (s, y, a, b, c, d) => Math.hypot(Math.max(a - s, 0, s - b), Math.max(c - y, 0, y - d));
27883
+ 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);
27884
+ function covered(c, boxes) {
27885
+ const n = 8;
27886
+ let hit = 0;
27887
+ for (let j = 0; j < n; j++) {
27888
+ const y = c.y0 + (j + 0.5) / n * (c.y1 - c.y0);
27889
+ for (let i = 0; i < n; i++) {
27890
+ const s = c.a + (i + 0.5) / n * (c.b - c.a);
27891
+ if (boxes.some((k) => s >= k.s0 && s <= k.s1 && y >= k.y0 && y <= k.y1)) hit++;
27892
+ }
27893
+ }
27894
+ return hit / (n * n);
27895
+ }
27438
27896
  function paint(view) {
27439
- const { mask } = view;
27897
+ const { mask, core } = view;
27440
27898
  const along = (p) => (mask.alongU ? p[0] : p[2]) - mask.start;
27441
27899
  const holes = [];
27900
+ const pits = [];
27442
27901
  const discs = [];
27902
+ const flakes = [];
27443
27903
  const shown = [];
27444
27904
  for (const id of view.parts) {
27445
- const part = structure.byId.get(id), units2 = specOf(id).units, chips = view.chips.get(id), opening = view.openings.get(id);
27905
+ 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);
27446
27906
  const all = cells(part, units2);
27447
27907
  const thick = mask.alongU ? part.aabb[3] - part.aabb[1] : part.aabb[2] - part.aabb[0];
27448
27908
  const mid = mask.alongU ? (part.aabb[1] + part.aabb[3]) / 2 : (part.aabb[0] + part.aabb[2]) / 2;
27449
27909
  if (opening) discs.push({ s: along(opening.center), y: opening.center[1], r: opening.radius });
27450
- const gone = (c) => chips.some((p) => p[1] >= c.y0 && p[1] <= c.y1 && along(p) >= c.a && along(p) <= c.b) || opening && Math.hypot((c.a + c.b) / 2 - along(opening.center), (c.y0 + c.y1) / 2 - opening.center[1]) < opening.radius;
27910
+ for (const k of spalls) flakes.push({ s: along(k.center), y: k.center[1], r: k.radius });
27911
+ const boxes = chips.map((k) => ({ s0: along(k.center) - k.along, s1: along(k.center) + k.along, y0: k.center[1] - k.up, y1: k.center[1] + k.up }));
27912
+ const gone = (c) => covered(c, boxes.filter((k) => k.s1 > c.a && k.s0 < c.b && k.y1 > c.y0 && k.y0 < c.y1)) >= 0.9 || opening && Math.hypot((c.a + c.b) / 2 - along(opening.center), (c.y0 + c.y1) / 2 - opening.center[1]) < opening.radius;
27451
27913
  const kept = [];
27452
27914
  for (const c of all) (gone(c) ? holes : kept).push(c);
27453
27915
  for (const c of kept) shown.push({ c, part, units: units2, thick, mid });
27916
+ for (const k of boxes) {
27917
+ if (holes.some((h) => k.s0 >= h.a - 1e-4 && k.s1 <= h.b + 1e-4 && k.y0 >= h.y0 - 1e-4 && k.y1 <= h.y1 + 1e-4)) continue;
27918
+ pits.push({ s: (k.s0 + k.s1) / 2, y: (k.y0 + k.y1) / 2, rs: (k.s1 - k.s0) / 2, ry: (k.y1 - k.y0) / 2 });
27919
+ }
27454
27920
  }
27455
27921
  const reach = SPALL_MIN + SPALL_RAGGED;
27922
+ const ragged = (s, y) => 0.6 * noise2(s, y, 0.03) + 0.4 * noise2(s + 7.3, y - 3.1, 0.011);
27456
27923
  mask.data.fill(0);
27457
- const stamp = (s0, s1, y0, y1, inside2) => {
27458
- const i0 = Math.max(0, Math.floor((s0 - reach) / mask.len * mask.w)), i1 = Math.min(mask.w - 1, Math.ceil((s1 + reach) / mask.len * mask.w));
27459
- const j0 = Math.max(0, Math.floor((y0 - reach - mask.y0) / mask.height * mask.h)), j1 = Math.min(mask.h - 1, Math.ceil((y1 + reach - mask.y0) / mask.height * mask.h));
27924
+ core.data.fill(0);
27925
+ const stamp = (m, s0, s1, y0, y1, inside2) => {
27926
+ const i0 = Math.max(0, Math.floor((s0 - reach) / m.len * m.w)), i1 = Math.min(m.w - 1, Math.ceil((s1 + reach) / m.len * m.w));
27927
+ const j0 = Math.max(0, Math.floor((y0 - reach - m.y0) / m.height * m.h)), j1 = Math.min(m.h - 1, Math.ceil((y1 + reach - m.y0) / m.height * m.h));
27460
27928
  for (let j = j0; j <= j1; j++) {
27461
- const y = mask.y0 + (j + 0.5) / mask.h * mask.height;
27929
+ const y = m.y0 + (j + 0.5) / m.h * m.height;
27462
27930
  for (let i = i0; i <= i1; i++) {
27463
- const s = (i + 0.5) / mask.w * mask.len;
27464
- const edge = SPALL_MIN + SPALL_RAGGED * (0.6 * noise2(s, y, 0.03) + 0.4 * noise2(s + 7.3, y - 3.1, 0.011));
27465
- if (inside2(s, y) <= edge) mask.data[j * mask.w + i] = 255;
27931
+ const s = (i + 0.5) / m.w * m.len;
27932
+ if (inside2(s, y)) m.data[j * m.w + i] = 255;
27466
27933
  }
27467
27934
  }
27468
27935
  };
27469
- for (const c of holes) stamp(c.a, c.b, c.y0, c.y1, (s, y) => boxDistance(s, y, c.a, c.b, c.y0, c.y1));
27470
- for (const d of discs) stamp(d.s - d.r, d.s + d.r, d.y - d.r, d.y + d.r, (s, y) => Math.max(0, Math.hypot(s - d.s, y - d.y) - d.r));
27936
+ const plaster = (d, s, y) => d <= SPALL_MIN + SPALL_RAGGED * ragged(s, y);
27937
+ for (const c of holes) stamp(mask, c.a, c.b, c.y0, c.y1, (s, y) => plaster(boxDistance(s, y, c.a, c.b, c.y0, c.y1), s, y));
27938
+ for (const d of discs) stamp(mask, d.s - d.r, d.s + d.r, d.y - d.r, d.y + d.r, (s, y) => plaster(Math.max(0, Math.hypot(s - d.s, y - d.y) - d.r), s, y));
27939
+ for (const f of flakes) {
27940
+ const rough = (s, y) => Math.hypot(s - f.s, y - f.y) - f.r * (0.65 + 0.7 * ragged(s * 2.3, y * 2.3));
27941
+ stamp(mask, f.s - 2 * f.r, f.s + 2 * f.r, f.y - 2 * f.r, f.y + 2 * f.r, (s, y) => rough(s, y) <= 0);
27942
+ }
27943
+ for (const p of pits) {
27944
+ stamp(mask, p.s - p.rs, p.s + p.rs, p.y - p.ry, p.y + p.ry, (s, y) => plaster(Math.max(0, ellipseDistance(s, y, p.s, p.y, p.rs, p.ry)), s, y));
27945
+ stamp(core, p.s - p.rs, p.s + p.rs, p.y - p.ry, p.y + p.ry, (s, y) => ellipseDistance(s, y, p.s, p.y, p.rs, p.ry) <= -0.35 * Math.min(p.rs, p.ry) * noise2(s * 1.7, y * 1.3, 0.012));
27946
+ }
27471
27947
  mask.texture.needsUpdate = true;
27472
- const near = (c) => holes.some((h) => boxDistance((c.a + c.b) / 2, (c.y0 + c.y1) / 2, h.a - (c.b - c.a) / 2, h.b + (c.b - c.a) / 2, h.y0 - (c.y1 - c.y0) / 2, h.y1 + (c.y1 - c.y0) / 2) <= reach) || discs.some((d) => boxDistance(d.s, d.y, c.a, c.b, c.y0, c.y1) <= d.r + reach);
27948
+ core.texture.needsUpdate = true;
27949
+ const near = (c) => holes.some((h) => boxDistance((c.a + c.b) / 2, (c.y0 + c.y1) / 2, h.a - (c.b - c.a) / 2, h.b + (c.b - c.a) / 2, h.y0 - (c.y1 - c.y0) / 2, h.y1 + (c.y1 - c.y0) / 2) <= reach) || discs.some((d) => boxDistance(d.s, d.y, c.a, c.b, c.y0, c.y1) <= d.r + reach) || pits.some((p) => boxDistance(p.s, p.y, c.a, c.b, c.y0, c.y1) <= Math.max(p.rs, p.ry) + reach) || flakes.some((f) => boxDistance(f.s, f.y, c.a, c.b, c.y0, c.y1) <= 2 * f.r);
27473
27950
  const list2 = [];
27474
27951
  const tone = (hex3, k) => tmp.c.setHex(hex3).multiplyScalar(k).getHex();
27475
27952
  for (const { c, part, units: units2, thick, mid } of shown) {
27476
27953
  if (!near(c)) continue;
27477
27954
  const centre = mask.start + (c.a + c.b) / 2, y = (c.y0 + c.y1) / 2, len = c.b - c.a, h = c.y1 - c.y0;
27478
- const at = (s, dy, d, colour) => list2.push({ x: mask.alongU ? centre : mid, y, z: mask.alongU ? mid : centre, sx: mask.alongU ? s : d, sy: dy, sz: mask.alongU ? d : s, colour });
27955
+ const at = (s, dy, d, colour) => {
27956
+ const unit = clipToBox({ x: mask.alongU ? centre : mid, y, z: mask.alongU ? mid : centre, sx: mask.alongU ? s : d, sy: dy, sz: mask.alongU ? d : s, colour }, view.bounds);
27957
+ if (unit) list2.push(unit);
27958
+ };
27479
27959
  const base = fragmentMaterial(part.material).color.getHex();
27480
27960
  const n = noise2(centre * 3.1, y * 2.7, 0.07);
27481
27961
  if (units2.mortar === "concrete") {
27482
- at(len, h, thick - 2 * COVER2 - 0.03 * n, tone(base, 0.86 + 0.2 * n));
27962
+ at(len, h, thick - 2 * COVER2, tone(base, 0.9 + 0.04 * n));
27483
27963
  } else {
27484
27964
  at(len, h, thick - 2 * COVER2 - 0.012, 10327948);
27485
27965
  at(len - 0.012, h - 0.012, thick - 2 * COVER2, tone(base, 0.8 + 0.35 * n));
@@ -27489,7 +27969,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27489
27969
  view.units.removeFromParent();
27490
27970
  view.units.dispose();
27491
27971
  }
27492
- const units = new THREE.InstancedMesh(unitGeometry, unitMaterial, Math.max(1, list2.length));
27972
+ const units = new THREE.InstancedMesh(unitGeometry, view.unitMaterial, Math.max(1, list2.length));
27493
27973
  units.name = "breach:" + view.host;
27494
27974
  list2.forEach((u, i) => {
27495
27975
  tmp.m.compose(tmp.p.set(u.x, u.y, u.z), tmp.q.identity(), tmp.s.set(u.sx, u.sy, u.sz));
@@ -27505,6 +27985,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27505
27985
  house.add(units);
27506
27986
  view.units = units;
27507
27987
  view.gone = holes.length;
27988
+ view.pits = pits.length;
27989
+ view.flakes = flakes.length;
27990
+ }
27991
+ function chipBox(chip, alongU) {
27992
+ house.updateMatrixWorld(true);
27993
+ const q = tmp.q.set(chip.rotation[0], chip.rotation[1], chip.rotation[2], chip.rotation[3]).premultiply(house.getWorldQuaternion(new THREE.Quaternion()).invert());
27994
+ let a = 0, u = 0;
27995
+ for (let k = 0; k < 3; k++) {
27996
+ const axis = tmp.p.set(k === 0 ? 1 : 0, k === 1 ? 1 : 0, k === 2 ? 1 : 0).applyQuaternion(q);
27997
+ a += Math.abs(alongU ? axis.x : axis.z) * chip.size[k] / 2;
27998
+ u += Math.abs(axis.y) * chip.size[k] / 2;
27999
+ }
28000
+ return { center: local(chip.center), along: a, up: u };
27508
28001
  }
27509
28002
  function draw2(partId, change) {
27510
28003
  if (lod !== 0) return false;
@@ -27516,23 +28009,50 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27516
28009
  if (!items.length) return false;
27517
28010
  const parts = [hostId, ...riders(hostId)].filter((id) => structure.byId.get(id) && specOf(id)?.units);
27518
28011
  if (!parts.includes(partId)) return false;
27519
- const mask = maskOf(hostId, parts);
27520
- view = { host: hostId, parts, items, mask, shells: [], saved: null, units: null, gone: 0, chips: new Map(parts.map((id) => [id, []])), openings: /* @__PURE__ */ new Map() };
28012
+ const mask = maskOf(hostId, parts), core = maskOf(hostId, parts);
28013
+ view = {
28014
+ host: hostId,
28015
+ parts,
28016
+ items,
28017
+ mask,
28018
+ core,
28019
+ unitMaterial: unitsMaterial(core),
28020
+ shells: [],
28021
+ saved: null,
28022
+ units: null,
28023
+ gone: 0,
28024
+ pits: 0,
28025
+ bounds: drawnBounds(items),
28026
+ chips: new Map(parts.map((id) => [id, []])),
28027
+ spalls: new Map(parts.map((id) => [id, []])),
28028
+ openings: /* @__PURE__ */ new Map(),
28029
+ flakes: 0
28030
+ };
27521
28031
  }
27522
28032
  if (!view.chips.has(partId)) return false;
27523
28033
  if (change.opening) {
27524
28034
  if (view.openings.has(partId)) return false;
27525
28035
  view.openings.set(partId, { center: local(change.opening.center), radius: change.opening.radius });
27526
28036
  }
27527
- if (change.chip) view.chips.get(partId).push(local(change.chip));
28037
+ if (change.chip) view.chips.get(partId).push(chipBox(change.chip, view.mask.alongU));
28038
+ if (change.spall) {
28039
+ const list2 = view.spalls.get(partId);
28040
+ list2.push({ center: local(change.spall.center), radius: change.spall.radius });
28041
+ if (list2.length > MAX_FLAKES) list2.shift();
28042
+ }
27528
28043
  if (!view.saved) {
27529
28044
  view.shells = view.items.map((it) => shell(it, view.mask));
28045
+ for (const m of view.shells) m.userData.behind = () => view.units;
27530
28046
  view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
27531
28047
  }
27532
- paint(view);
27533
28048
  views.set(hostId, view);
27534
- invalidate();
27535
- invalidateShadow();
28049
+ if (opts.deferPaint && change.spall) dirty.add(view);
28050
+ else {
28051
+ dirty.delete(view);
28052
+ paint(view);
28053
+ invalidate();
28054
+ invalidateShadow();
28055
+ }
27536
28056
  return true;
27537
28057
  }
27538
28058
  function plain2(view, shown) {
@@ -27541,24 +28061,70 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27541
28061
  else s.data = collapseRange(s.it.mesh, s.v0, s.it.v1);
27542
28062
  }
27543
28063
  }
28064
+ function flush(budgetMs = paintBudgetMs) {
28065
+ if (dirty.size === 0) return 0;
28066
+ const deadline = performance.now() + budgetMs;
28067
+ for (const view of dirty) {
28068
+ dirty.delete(view);
28069
+ paint(view);
28070
+ if (performance.now() >= deadline) break;
28071
+ }
28072
+ invalidate();
28073
+ invalidateShadow();
28074
+ return dirty.size;
28075
+ }
27544
28076
  function dispose(view) {
27545
- view.units.removeFromParent();
27546
- view.units.dispose();
28077
+ dirty.delete(view);
28078
+ if (view.units) {
28079
+ view.units.removeFromParent();
28080
+ view.units.dispose();
28081
+ }
28082
+ view.unitMaterial.dispose();
27547
28083
  for (const m of view.shells) {
27548
28084
  m.removeFromParent();
27549
28085
  m.geometry.dispose();
27550
28086
  m.material.dispose();
27551
28087
  }
27552
28088
  view.mask.texture.dispose();
28089
+ view.core.texture.dispose();
27553
28090
  }
27554
28091
  return {
27555
28092
  /** Handles a `stage` event of the house's object. Returns true when the wall was cut. */
27556
28093
  stage(event) {
27557
28094
  return event.stage === 2 && !!event.opening ? draw2(event.part, { opening: event.opening }) : false;
27558
28095
  },
27559
- /** Handles a `chip` event: the unit that came out leaves a hole in the wall where it was. Returns true when the wall was cut. */
28096
+ /**
28097
+ * Handles a `spall` of a wall of units: the coat comes off in a ragged patch and the units show under it, drawn by the house (the destruction
28098
+ * renderer leaves its flat patch out on the meshes `claim` marked). Returns true when the wall was cut.
28099
+ */
28100
+ spall(event) {
28101
+ const r = Math.sqrt(Math.max(0, event.area) / Math.PI);
28102
+ return r > 0 ? draw2(event.part, { spall: { center: event.point, radius: r } }) : false;
28103
+ },
28104
+ /**
28105
+ * Marks the meshes that draw a wall of units as drawing its spalls itself (`userData.drawnSpalls`, the part ids): the destruction renderer then
28106
+ * throws the bits and leaves its patch out. Call it once the spec is known.
28107
+ */
28108
+ claim() {
28109
+ var _a;
28110
+ for (const q of opts.spec()?.parts ?? []) {
28111
+ if (!q.units) continue;
28112
+ const host = hostOf(q.id);
28113
+ if (!host) continue;
28114
+ for (const it of structure.meshesOf(host)) {
28115
+ if (!it.mesh) continue;
28116
+ const list2 = (_a = it.mesh.userData).drawnSpalls ?? (_a.drawnSpalls = []);
28117
+ if (!list2.includes(q.id)) list2.push(q.id);
28118
+ }
28119
+ }
28120
+ },
28121
+ /**
28122
+ * Handles a `chip` event: what came out (a unit, or a crater a shot broke through one) leaves a hole in the wall where it was; a `torn` chip (what a blow
28123
+ * tore off a face) leaves the marks the renderer drew. Returns true when the wall was cut.
28124
+ */
27560
28125
  chip(event) {
27561
- return draw2(event.part, { chip: event.center });
28126
+ if (event.torn) return false;
28127
+ return draw2(event.part, { chip: { center: event.center, size: event.size ?? [0, 0, 0], rotation: event.rotation ?? [0, 0, 0, 1] } });
27562
28128
  },
27563
28129
  /** The part broke or fell: its damage goes (the plain range stays collapsed, the renderer hides the part). */
27564
28130
  drop(partId) {
@@ -27566,9 +28132,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27566
28132
  if (!v) return;
27567
28133
  dispose(v);
27568
28134
  views.delete(partId);
28135
+ if (v.saved) dropped.push(v);
27569
28136
  },
27570
28137
  /** LOD 0 draws the cut wall; LOD 1 and 2 give the wall its box back. */
27571
28138
  setLod(level) {
28139
+ flush(Infinity);
27572
28140
  const was = lod;
27573
28141
  lod = level;
27574
28142
  if (was === 0 === (level === 0)) return;
@@ -27587,22 +28155,28 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27587
28155
  if (lod === 0) plain2(v, true);
27588
28156
  }
27589
28157
  views.clear();
28158
+ for (const v of dropped) plain2(v, true);
28159
+ dropped.length = 0;
27590
28160
  },
28161
+ flush,
27591
28162
  /** The wall has damage drawn. */
27592
28163
  has(partId) {
27593
28164
  return views.has(partId);
27594
28165
  },
27595
- /** Walls with damage drawn, units out of them, and units laid bare at the edge of the cuts. */
27596
- statistics: () => ({
28166
+ /** Walls with damage drawn, units out of them, craters shots broke through units that stay, and units laid bare at the edge of the cuts. */
28167
+ statistics: () => (flush(Infinity), {
27597
28168
  walls: views.size,
27598
28169
  gone: [...views.values()].reduce((n, v) => n + v.gone, 0),
28170
+ craters: [...views.values()].reduce((n, v) => n + v.pits, 0),
28171
+ flakes: [...views.values()].reduce((n, v) => n + v.flakes, 0),
27599
28172
  units: [...views.values()].reduce((n, v) => n + v.units.count, 0)
27600
28173
  })
27601
28174
  };
27602
28175
  }
27603
28176
  Object.assign(K, { createBreachView });
27604
28177
  }
27605
- function installDestructionWorld(K, shared) {
28178
+ var FOLLOW_FLUSH_FALLBACK_MS = 100;
28179
+ function installDestructionWorld(K, shared2) {
27606
28180
  const { THREE, cfg, invalidateShadow, invalidate, rngString, FRAGMENT_GEO, fragmentMaterial, createBreachView } = K;
27607
28181
  function createHouseDestruction(root, house, structure, parts, colliders, water) {
27608
28182
  const D = { world: cfg.destruction || null, id: null, active: false }, hiddenPieces = /* @__PURE__ */ new Set(), bodies = /* @__PURE__ */ new Map(), frags = [], facets = /* @__PURE__ */ new Map();
@@ -27610,7 +28184,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27610
28184
  const R = cfg.destructionRenderer || null, listeners = /* @__PURE__ */ new Set();
27611
28185
  D.renderer = R;
27612
28186
  D.spec = null;
27613
- const breach = createBreachView({ house, structure, spec: () => D.spec });
28187
+ const breach = createBreachView({ house, structure, spec: () => D.spec, deferPaint: true, ...cfg.breachPaintBudgetMs !== void 0 ? { paintBudgetMs: cfg.breachPaintBudgetMs } : {} });
27614
28188
  D.breach = breach;
27615
28189
  D.onEvent = (fn) => {
27616
28190
  listeners.add(fn);
@@ -27795,6 +28369,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27795
28369
  case "chip":
27796
28370
  breach.chip(e);
27797
28371
  break;
28372
+ case "spall":
28373
+ breach.spall(e);
28374
+ break;
27798
28375
  case "collapse":
27799
28376
  for (const id of e.parts) {
27800
28377
  breach.drop(id);
@@ -27835,8 +28412,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27835
28412
  house.matrixWorld.decompose(p, q, sc);
27836
28413
  D.specOptions = specOptions || null;
27837
28414
  D.spec = structure.spec(specOptions);
27838
- D.id = D.world.add(D.spec, { id: "house3d:" + ++shared.destructionSeq, position: [p.x, p.y, p.z], rotation: [q.x, q.y, q.z, q.w] });
27839
- if (R) R.bind(D.id, house, { parts: rangesOf() });
28415
+ D.id = D.world.add(D.spec, { id: "house3d:" + ++shared2.destructionSeq, position: [p.x, p.y, p.z], rotation: [q.x, q.y, q.z, q.w] });
28416
+ breach.claim();
28417
+ if (R) R.bind(D.id, house, { parts: rangesOf(), onFrame: () => breach.flush() });
27840
28418
  off = D.world.on("*", handleEvent);
27841
28419
  D.active = true;
27842
28420
  return D;
@@ -27851,6 +28429,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27851
28429
  };
27852
28430
  D.follow = (world, id, spec) => {
27853
28431
  D.spec = spec;
28432
+ breach.claim();
28433
+ let fallback = null;
27854
28434
  const offFollow = world.on("*", (e) => {
27855
28435
  if (e.object !== id) return;
27856
28436
  switch (e.type) {
@@ -27860,6 +28440,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27860
28440
  case "chip":
27861
28441
  breach.chip(e);
27862
28442
  break;
28443
+ case "spall":
28444
+ breach.spall(e);
28445
+ break;
27863
28446
  case "fracture":
27864
28447
  breach.drop(e.part);
27865
28448
  break;
@@ -27869,10 +28452,16 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27869
28452
  default:
27870
28453
  break;
27871
28454
  }
28455
+ if (!fallback && typeof setTimeout === "function") fallback = setTimeout(() => {
28456
+ fallback = null;
28457
+ breach.flush(Infinity);
28458
+ }, FOLLOW_FLUSH_FALLBACK_MS);
27872
28459
  });
27873
28460
  return { restore: () => breach.restore(), dispose: () => {
27874
28461
  offFollow();
27875
28462
  breach.restore();
28463
+ }, update: () => {
28464
+ breach.flush();
27876
28465
  } };
27877
28466
  };
27878
28467
  D.piece = (id) => D.active ? D.world.part(D.id, id) : null;
@@ -27905,6 +28494,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27905
28494
  return r;
27906
28495
  };
27907
28496
  D.animate = (dt) => {
28497
+ breach.flush();
27908
28498
  if (R) return;
27909
28499
  let moved = false;
27910
28500
  for (const [id, list2] of bodies) {
@@ -27968,7 +28558,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27968
28558
  }
27969
28559
  Object.assign(K, { createHouseDestruction });
27970
28560
  }
27971
- function installBuildBuild(K, shared) {
28561
+ function installBuildBuild(K, shared2) {
27972
28562
  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;
27973
28563
  function build(r0, opts) {
27974
28564
  opts = opts || {};
@@ -27979,43 +28569,43 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
27979
28569
  cursor.accs.clear();
27980
28570
  LIGHTS.length = 0;
27981
28571
  const pr = opts.building || {};
27982
- shared.ctx.r = r;
27983
- shared.ctx.colors = r.colors;
27984
- shared.ctx.cut = !!opts.cut;
27985
- shared.ctx.night = !!opts.night;
27986
- shared.ctx.labels = [];
27987
- shared.ctx.colliders = [];
27988
- shared.ctx.stairs = [];
27989
- shared.ctx.noTerrain = opts.terrain === false;
27990
- shared.ctx.roomById = {};
27991
- for (const c of r.rooms) shared.ctx.roomById[c.id] = c;
27992
- shared.ctx.pieces = /* @__PURE__ */ new Map();
27993
- shared.ctx.pieceObjects = /* @__PURE__ */ new Map();
27994
- shared.ctx.structureIndex = {};
27995
- for (const e of r0.structure && r0.structure.parts || []) shared.ctx.structureIndex[e.id] = e;
28572
+ shared2.ctx.r = r;
28573
+ shared2.ctx.colors = r.colors;
28574
+ shared2.ctx.cut = !!opts.cut;
28575
+ shared2.ctx.night = !!opts.night;
28576
+ shared2.ctx.labels = [];
28577
+ shared2.ctx.colliders = [];
28578
+ shared2.ctx.stairs = [];
28579
+ shared2.ctx.noTerrain = opts.terrain === false;
28580
+ shared2.ctx.roomById = {};
28581
+ for (const c of r.rooms) shared2.ctx.roomById[c.id] = c;
28582
+ shared2.ctx.pieces = /* @__PURE__ */ new Map();
28583
+ shared2.ctx.pieceObjects = /* @__PURE__ */ new Map();
28584
+ shared2.ctx.structureIndex = {};
28585
+ for (const e of r0.structure && r0.structure.parts || []) shared2.ctx.structureIndex[e.id] = e;
27996
28586
  {
27997
- const view = shared.ctx.panelView = panelViewOf(r0.structure, !!cfg.destruction);
27998
- shared.ctx.panelsOf = /* @__PURE__ */ new Map();
27999
- for (const id of view.replaced) delete shared.ctx.structureIndex[id];
28587
+ const view = shared2.ctx.panelView = panelViewOf(r0.structure, !!cfg.destruction);
28588
+ shared2.ctx.panelsOf = /* @__PURE__ */ new Map();
28589
+ for (const id of view.replaced) delete shared2.ctx.structureIndex[id];
28000
28590
  for (const e of view.panels) {
28001
- shared.ctx.structureIndex[e.id] = e;
28002
- const l = shared.ctx.panelsOf.get(e.slab);
28591
+ shared2.ctx.structureIndex[e.id] = e;
28592
+ const l = shared2.ctx.panelsOf.get(e.slab);
28003
28593
  if (l) l.push(e);
28004
- else shared.ctx.panelsOf.set(e.slab, [e]);
28594
+ else shared2.ctx.panelsOf.set(e.slab, [e]);
28005
28595
  }
28006
28596
  }
28007
- shared.ctx.panes = r0.roof && r0.roof.panes || [];
28008
- shared.ctx.noPiece = false;
28597
+ shared2.ctx.panes = r0.roof && r0.roof.panes || [];
28598
+ shared2.ctx.noPiece = false;
28009
28599
  cursor.separate = opts.pieces === "meshes";
28010
28600
  cursor.pc = null;
28011
- shared.ctx.apartment = r.template === "apartment_modern";
28012
- shared.ctx.pa = Math.max(3, Math.min(20, pr.floors != null ? pr.floors : 5));
28013
- shared.ctx.pf = Math.max(1, Math.min(shared.ctx.pa, pr.floor != null ? pr.floor : 3));
28014
- shared.ctx.pu = Math.max(0, pr.unit != null ? pr.unit : 0);
28015
- shared.ctx.showBuilding = shared.ctx.apartment && (pr.showIt == null ? true : !!pr.showIt);
28016
- shared.ctx.limits = { x0: -2, z0: -2, x1: r.w + 2, z1: r.d + 2 };
28017
- shared.ctx.veg = VEG ? { G: VEG.G, S: VEG.S, mats: vegMaterials, groups: /* @__PURE__ */ new Map(), ok: /* @__PURE__ */ new Map(), opts: shared.quality === "game" ? { quality: "game" } : { lod: 0, triangleBudget: 6e4 } } : null;
28018
- shared.ctx.vegInfo = null;
28601
+ shared2.ctx.apartment = r.template === "apartment_modern";
28602
+ shared2.ctx.pa = Math.max(3, Math.min(20, pr.floors != null ? pr.floors : 5));
28603
+ shared2.ctx.pf = Math.max(1, Math.min(shared2.ctx.pa, pr.floor != null ? pr.floor : 3));
28604
+ shared2.ctx.pu = Math.max(0, pr.unit != null ? pr.unit : 0);
28605
+ shared2.ctx.showBuilding = shared2.ctx.apartment && (pr.showIt == null ? true : !!pr.showIt);
28606
+ shared2.ctx.limits = { x0: -2, z0: -2, x1: r.w + 2, z1: r.d + 2 };
28607
+ 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;
28608
+ shared2.ctx.vegInfo = null;
28019
28609
  terrain();
28020
28610
  if (r.lot) {
28021
28611
  if (!opts.noPerimeter) {
@@ -28026,7 +28616,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28026
28616
  }
28027
28617
  walls();
28028
28618
  baseboardAndSidewalk();
28029
- shared.ctx.wallColliders = shared.ctx.colliders.length;
28619
+ shared2.ctx.wallColliders = shared2.ctx.colliders.length;
28030
28620
  doors();
28031
28621
  windows();
28032
28622
  floorsAndSlabs();
@@ -28034,14 +28624,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28034
28624
  buildStairs();
28035
28625
  elevator();
28036
28626
  const water = createWater(r, h.state);
28037
- shared.ctx.iv = null;
28627
+ shared2.ctx.iv = null;
28038
28628
  h.IV = null;
28039
28629
  if (IVK) {
28040
28630
  try {
28041
- h.IV = shared.ctx.iv = ivBuild(h, water);
28631
+ h.IV = shared2.ctx.iv = ivBuild(h, water);
28042
28632
  } catch (e) {
28043
28633
  console.warn("interactables", e);
28044
- shared.ctx.iv = h.IV = null;
28634
+ shared2.ctx.iv = h.IV = null;
28045
28635
  }
28046
28636
  }
28047
28637
  const noModel = houseItems();
@@ -28050,14 +28640,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28050
28640
  electricalStructure();
28051
28641
  roofs();
28052
28642
  solar();
28053
- if (shared.ctx.showBuilding) building();
28643
+ if (shared2.ctx.showBuilding) building();
28054
28644
  for (const c of r.rooms) {
28055
28645
  if (c.type === "void") continue;
28056
28646
  const [a, b, c2, d] = rectsOf2(c)[0];
28057
- shared.ctx.labels.push({ pos: new THREE.Vector3((a + c2) / 2, Y0(c.floor) + 1.1, (b + d) / 2), text: c.name, group: "f" + c.floor, type: "room", floor: c.floor });
28647
+ shared2.ctx.labels.push({ pos: new THREE.Vector3((a + c2) / 2, Y0(c.floor) + 1.1, (b + d) / 2), text: c.name, group: "f" + c.floor, type: "room", floor: c.floor });
28058
28648
  }
28059
- const mirrorsCopy = MIRRORS.map((E, i) => Object.assign({ i }, E)), gs = closeScene(shared.mats);
28060
- for (const fo of shared.ctx.leaves) {
28649
+ const mirrorsCopy = MIRRORS.map((E, i) => Object.assign({ i }, E)), gs = closeScene(shared2.mats);
28650
+ for (const fo of shared2.ctx.leaves) {
28061
28651
  const parent = gs["f" + fo.floor] || (gs["f" + fo.floor] = new THREE.Group());
28062
28652
  fo.gs = [];
28063
28653
  for (const gd of fo.groups) {
@@ -28070,22 +28660,22 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28070
28660
  }
28071
28661
  applyLeaf(fo);
28072
28662
  }
28073
- if (shared.ctx.iv) ivAssemble(shared.ctx.iv, gs);
28663
+ if (shared2.ctx.iv) ivAssemble(shared2.ctx.iv, gs);
28074
28664
  assembleInteractive(gs);
28075
28665
  linkDoorLeaves();
28076
28666
  mailboxInteractive();
28077
28667
  const root = markKitOrigin(new THREE.Group(), { owner: "game-floorplan-three", kind: "structure", id: r.template }), house = new THREE.Group();
28078
28668
  root.name = "house3d";
28079
28669
  root.add(house);
28080
- shared.mirrors.house = house;
28081
- if (shared.ctx.apartment) {
28082
- const u = r.building.units[Math.min(shared.ctx.pu, r.building.units.length - 1)];
28083
- house.position.set(u.u, shared.ctx.showBuilding ? 0 : -r.floors[0].y0, u.v);
28670
+ shared2.mirrors.house = house;
28671
+ if (shared2.ctx.apartment) {
28672
+ const u = r.building.units[Math.min(shared2.ctx.pu, r.building.units.length - 1)];
28673
+ house.position.set(u.u, shared2.ctx.showBuilding ? 0 : -r.floors[0].y0, u.v);
28084
28674
  house.rotation.y = u.ry;
28085
- shared.ctx.unitRy = u.ry;
28675
+ shared2.ctx.unitRy = u.ry;
28086
28676
  }
28087
28677
  house.updateMatrixWorld(true);
28088
- shared.ctx.unitInverse = house.matrixWorld.clone().invert();
28678
+ shared2.ctx.unitInverse = house.matrixWorld.clone().invert();
28089
28679
  for (const [k, g] of Object.entries(gs)) {
28090
28680
  g.name = k;
28091
28681
  (k === "floor" || k === "building" ? root : house).add(g);
@@ -28094,31 +28684,31 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28094
28684
  h.root = root;
28095
28685
  h.house = house;
28096
28686
  h.houseGroup = house;
28097
- shared.ctx.noModel = noModel;
28098
- shared.ctx.lights = LIGHTS.filter((l) => l.type !== "lantern" && l.type !== "candles" || shared.ctx.night).map((l) => ({ ...l }));
28099
- shared.ctx.animateDoorsOn = shared.ctx.animateDoorsOn || false;
28100
- for (const c of shared.ctx.colliders) {
28687
+ shared2.ctx.noModel = noModel;
28688
+ shared2.ctx.lights = LIGHTS.filter((l) => l.type !== "lantern" && l.type !== "candles" || shared2.ctx.night).map((l) => ({ ...l }));
28689
+ shared2.ctx.animateDoorsOn = shared2.ctx.animateDoorsOn || false;
28690
+ for (const c of shared2.ctx.colliders) {
28101
28691
  c.aabb = [c.x0, c.z0, c.x1, c.z1];
28102
28692
  if (c.type === "wall") c.damageable = tagDamage("masonry");
28103
28693
  }
28104
- const colliders = shared.ctx.colliders.concat(shared.inter.objs.map((o) => ({ type: "furniture", f: o.f, obb: { cx: o.cx, cz: o.cz, hw: o.hw, hd: o.hd, c: o.c, s: o.s }, item: o.type, off: false })));
28694
+ const colliders = shared2.ctx.colliders.concat(shared2.inter.objs.map((o) => ({ type: "furniture", f: o.f, obb: { cx: o.cx, cz: o.cz, hw: o.hw, hd: o.hd, c: o.c, s: o.s }, item: o.type, off: false })));
28105
28695
  const parts = {}, setOpen = (def, t) => {
28106
28696
  def.target = t;
28107
28697
  def.t = t;
28108
- shared.partState.set(def.name, t);
28698
+ shared2.partState.set(def.name, t);
28109
28699
  if (def.col) {
28110
28700
  def.col.off = t > 0.5;
28111
28701
  colliderChanged(def.col);
28112
28702
  }
28113
28703
  applyPiece(def);
28114
- shared.inter.anim.delete(def);
28704
+ shared2.inter.anim.delete(def);
28115
28705
  invalidateShadow();
28116
28706
  };
28117
28707
  const mark = (o, id) => {
28118
28708
  if (o) o.userData.partId = id;
28119
28709
  };
28120
28710
  const PART_DAMAGE = { water_tank: "water", shower_door: "glass", gate_leaf: "metal", mailbox_door: "metal", mirror: "glass", cooking_gas_cylinder: "gas" };
28121
- for (const [id, g] of Object.entries(shared.ctx.parts || {})) {
28711
+ for (const [id, g] of Object.entries(shared2.ctx.parts || {})) {
28122
28712
  const tp = g.userData.part, dn = PART_DAMAGE[tp];
28123
28713
  if (dn) g.userData.damageable = tagDamage(dn);
28124
28714
  mark(g, id);
@@ -28138,7 +28728,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28138
28728
  return g.userData.t || 0;
28139
28729
  }, meta: g.userData };
28140
28730
  }
28141
- for (const fo of shared.ctx.leaves) {
28731
+ for (const fo of shared2.ctx.leaves) {
28142
28732
  const id = "door:" + fo.id, dn = tagDamage(fo.type === "steel" ? "metal" : "wood");
28143
28733
  fo.damageable = dn;
28144
28734
  for (const g of fo.gs) mark(g, id);
@@ -28150,14 +28740,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28150
28740
  fo.col.off = fo.open;
28151
28741
  colliderChanged(fo.col);
28152
28742
  }
28153
- shared.doorState.set(fo.id, fo.open);
28743
+ shared2.doorState.set(fo.id, fo.open);
28154
28744
  applyLeaf(fo);
28155
28745
  invalidateShadow();
28156
28746
  }, get t() {
28157
28747
  return fo.t;
28158
28748
  }, leaf: fo };
28159
28749
  }
28160
- for (const def of shared.inter.defs.values()) {
28750
+ for (const def of shared2.inter.defs.values()) {
28161
28751
  if (!def.outer) continue;
28162
28752
  const cab = def.kind === "swing" || def.kind === "drawer", gate = /^gate/.test(def.kind);
28163
28753
  const dn = cab ? tagDamage("wood") : gate ? tagDamage("metal") : null;
@@ -28167,7 +28757,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28167
28757
  return def.t;
28168
28758
  }, def };
28169
28759
  }
28170
- if (shared.ctx.iv) ivParts(shared.ctx.iv, parts, tagDamage);
28760
+ if (shared2.ctx.iv) ivParts(shared2.ctx.iv, parts, tagDamage);
28171
28761
  const cars = [];
28172
28762
  CARS.forEach((C, i) => {
28173
28763
  const mod = carModel(C.k, C.seed);
@@ -28207,18 +28797,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28207
28797
  const actOn = (e, a) => {
28208
28798
  enter(h);
28209
28799
  if (cfg.onInteract && cfg.onInteract(e, a) === false) return false;
28210
- shared.inter.target = a || { target: e.ref, text: e.label, action: e._action };
28800
+ shared2.inter.target = a || { target: e.ref, text: e.label, action: e._action };
28211
28801
  e._action();
28212
28802
  return true;
28213
28803
  };
28214
- for (const fo of shared.ctx.leaves) {
28804
+ for (const fo of shared2.ctx.leaves) {
28215
28805
  const e = { id: "door:" + fo.id, type: fo.type === "steel" ? "garage_door" : "door", floor: fo.floor, pos: [fo.cx, Y0(fo.floor) + 1, fo.cz], radius: 1.7, get label() {
28216
28806
  return doorText(fo);
28217
28807
  }, ref: fo, _action: () => toggleDoor(fo) };
28218
28808
  e.act = () => actOn(e);
28219
28809
  interactables.push(e);
28220
28810
  }
28221
- for (const it of shared.inter.items) {
28811
+ for (const it of shared2.inter.items) {
28222
28812
  const k = it.type + ":" + it.id, n = usedMap.get(k) || 0;
28223
28813
  usedMap.set(k, n + 1);
28224
28814
  const e = { id: n ? k + "#" + n : k, type: it.type, floor: it.floor, pos: it.anchor.slice(), radius: it.range, angle: it.angle, get label() {
@@ -28228,12 +28818,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28228
28818
  interactables.push(e);
28229
28819
  it.pub = e;
28230
28820
  }
28231
- for (const fo of shared.ctx.leaves) fo.pub = interactables.find((e) => e.ref === fo);
28821
+ for (const fo of shared2.ctx.leaves) fo.pub = interactables.find((e) => e.ref === fo);
28232
28822
  const lodObjects = [];
28233
- for (const def of shared.inter.defs.values()) if (def.outer && /^(light|drawer|swing|curtain|light_switch|handle)$/.test(def.kind)) lodObjects.push(def.outer);
28234
- for (const [id, g] of Object.entries(shared.ctx.parts || {})) if (/^(handle|shower_door)$/.test(g.userData.part) && g.visible !== false) lodObjects.push(g);
28235
- if (shared.ctx.iv) {
28236
- for (const E of shared.ctx.iv.roots) lodObjects.push(E.root);
28823
+ for (const def of shared2.inter.defs.values()) if (def.outer && /^(light|drawer|swing|curtain|light_switch|handle)$/.test(def.kind)) lodObjects.push(def.outer);
28824
+ for (const [id, g] of Object.entries(shared2.ctx.parts || {})) if (/^(handle|shower_door)$/.test(g.userData.part) && g.visible !== false) lodObjects.push(g);
28825
+ if (shared2.ctx.iv) {
28826
+ for (const E of shared2.ctx.iv.roots) lodObjects.push(E.root);
28237
28827
  }
28238
28828
  const countDraw = () => {
28239
28829
  let n = 0, t = 0;
@@ -28251,7 +28841,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28251
28841
  for (const o of lodObjects) o.visible = true;
28252
28842
  const budget = opts.drawCallBudget != null ? opts.drawCallBudget : cfg.drawCallBudget;
28253
28843
  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 };
28254
- shared.ctx.tBuild = stats2.tBuild;
28844
+ shared2.ctx.tBuild = stats2.tBuild;
28255
28845
  const applyLod = (n) => {
28256
28846
  n = Math.max(0, Math.min(2, n | 0));
28257
28847
  if (n === h.lodCurrent) return;
@@ -28317,39 +28907,39 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28317
28907
  building: gs.building || null,
28318
28908
  waterTank: r.waterTank ? (() => {
28319
28909
  const pt = Object.values(parts).find((p) => p.type === "water_tank") || null;
28320
- return { part: pt, group: pt ? pt.group : null, pos: shared.ctx.waterTankPos || null, plant: r.waterTank };
28910
+ return { part: pt, group: pt ? pt.group : null, pos: shared2.ctx.waterTankPos || null, plant: r.waterTank };
28321
28911
  })() : null,
28322
28912
  colliders,
28323
28913
  parts,
28324
28914
  cars,
28325
28915
  interactables,
28326
- doors: shared.ctx.leaves,
28327
- stairs: shared.ctx.stairs,
28328
- labels: shared.ctx.labels,
28916
+ doors: shared2.ctx.leaves,
28917
+ stairs: shared2.ctx.stairs,
28918
+ labels: shared2.ctx.labels,
28329
28919
  noModel,
28330
28920
  lights: (() => {
28331
28921
  const by = {};
28332
- for (const l of shared.ctx.lights) {
28922
+ for (const l of shared2.ctx.lights) {
28333
28923
  const k = l.roomId != null ? l.roomId : l.room;
28334
28924
  (by[k] || (by[k] = [])).push(l);
28335
28925
  }
28336
- return { list: shared.ctx.lights, byRoom: by };
28926
+ return { list: shared2.ctx.lights, byRoom: by };
28337
28927
  })(),
28338
- limits: shared.ctx.limits,
28339
- apartment: shared.ctx.apartment,
28340
- showBuilding: shared.ctx.showBuilding,
28341
- buildingConfig: { floors: shared.ctx.pa, floor: shared.ctx.pf, unit: shared.ctx.pu },
28342
- unitRy: shared.ctx.unitRy || 0,
28343
- night: shared.ctx.night,
28344
- cut: shared.ctx.cut,
28928
+ limits: shared2.ctx.limits,
28929
+ apartment: shared2.ctx.apartment,
28930
+ showBuilding: shared2.ctx.showBuilding,
28931
+ buildingConfig: { floors: shared2.ctx.pa, floor: shared2.ctx.pf, unit: shared2.ctx.pu },
28932
+ unitRy: shared2.ctx.unitRy || 0,
28933
+ night: shared2.ctx.night,
28934
+ cut: shared2.ctx.cut,
28345
28935
  interactives: h.IV ? ivPublish(h) : null,
28346
28936
  state: h.state,
28347
28937
  stats: stats2,
28348
- vegetation: shared.ctx.vegInfo || null,
28349
- solar: shared.ctx.solarInfo || null,
28938
+ vegetation: shared2.ctx.vegInfo || null,
28939
+ solar: shared2.ctx.solarInfo || null,
28350
28940
  water,
28351
- electrical: shared.ctx.electricalInfo || null,
28352
- gutters: shared.ctx.gutterInfo || null,
28941
+ electrical: shared2.ctx.electricalInfo || null,
28942
+ gutters: shared2.ctx.gutterInfo || null,
28353
28943
  // per frame: doors, parts, wind-blown laundry and (with a focus) distance LOD; dt in seconds, time in ms (rAF); focus = {x,y,z} in world coordinates
28354
28944
  update(dt, time, focus) {
28355
28945
  enter(h);
@@ -28359,9 +28949,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28359
28949
  if (destruction.active || destruction.statistics().falling || destruction.statistics().fragments) destruction.animate(dt);
28360
28950
  if (h.IV) ivUpdate(h, dt, time, focus);
28361
28951
  if (time != null) animateClotheslines(time);
28362
- if (shared.vegMaterials) {
28363
- shared.vegMaterials.update((time != null ? time : performance.now()) / 1e3);
28364
- shared.vegMaterials.setActors(focus ? [{ x: focus.x, y: focus.y, z: focus.z, radius: 0.9 }] : []);
28952
+ if (shared2.vegMaterials) {
28953
+ shared2.vegMaterials.update((time != null ? time : performance.now()) / 1e3);
28954
+ shared2.vegMaterials.setActors(focus ? [{ x: focus.x, y: focus.y, z: focus.z, radius: 0.9 }] : []);
28365
28955
  }
28366
28956
  if (focus && cfg.lod !== false) {
28367
28957
  const L = Object.assign({ interior: 45, hide: 220 }, cfg.lod), d = distance2(focus), at = h.lodCurrent;
@@ -28373,12 +28963,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28373
28963
  show(o) {
28374
28964
  enter(h);
28375
28965
  o = o || {};
28376
- const rr = shared.ctx.r, nA = rr.floors.length, a = o.floor == null ? -1 : o.floor, sel = a >= nA ? -1 : a, cut = !!o.cut;
28966
+ const rr = shared2.ctx.r, nA = rr.floors.length, a = o.floor == null ? -1 : o.floor, sel = a >= nA ? -1 : a, cut = !!o.cut;
28377
28967
  for (const [k, g] of Object.entries(gs)) {
28378
28968
  let v = true;
28379
28969
  if (k[0] === "f") v = sel < 0 || +k.slice(1) <= sel;
28380
28970
  else if (k[0] === "t") v = !cut && (sel < 0 || +k.slice(1) < sel);
28381
- else if (k === "roof") v = !cut && sel < 0 && (!shared.ctx.apartment || !shared.ctx.showBuilding || shared.ctx.pf === shared.ctx.pa);
28971
+ else if (k === "roof") v = !cut && sel < 0 && (!shared2.ctx.apartment || !shared2.ctx.showBuilding || shared2.ctx.pf === shared2.ctx.pa);
28382
28972
  else if (k === "attic_tank") v = (cut || sel >= 0) && (sel < 0 || nA - 1 <= sel);
28383
28973
  else if (k === "lot") v = o.lot == null ? true : !!o.lot;
28384
28974
  g.visible = v;
@@ -28395,11 +28985,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28395
28985
  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);
28396
28986
  },
28397
28987
  message() {
28398
- return shared.inter.msg && performance.now() < shared.inter.msg.until ? shared.inter.msg.text : null;
28988
+ return shared2.inter.msg && performance.now() < shared2.inter.msg.until ? shared2.inter.msg.text : null;
28399
28989
  },
28400
28990
  toggleDoor(fo) {
28401
28991
  enter(h);
28402
- toggleDoor(typeof fo === "string" ? shared.ctx.leaves.find((f) => f.id === fo) : fo);
28992
+ toggleDoor(typeof fo === "string" ? shared2.ctx.leaves.find((f) => f.id === fo) : fo);
28403
28993
  },
28404
28994
  lightOn(roomId) {
28405
28995
  enter(h);
@@ -28471,13 +29061,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28471
29061
  });
28472
29062
  root.removeFromParent();
28473
29063
  },
28474
- internal: { h, ctx: shared.ctx, inter: shared.inter, partState: shared.partState, doorState: shared.doorState, mirrors: shared.mirrors }
29064
+ internal: { h, ctx: shared2.ctx, inter: shared2.inter, partState: shared2.partState, doorState: shared2.doorState, mirrors: shared2.mirrors }
28475
29065
  };
28476
29066
  return res;
28477
29067
  }
28478
29068
  Object.assign(K, { build });
28479
29069
  }
28480
- function buildApi(K, shared) {
29070
+ function buildApi(K, shared2) {
28481
29071
  const { cfg, VERSION: VERSION2, ATLAS, TEX, applyPart, carGroup, carModel, props, TYPES, roomLightMask, lighting, newState, build } = K;
28482
29072
  return {
28483
29073
  version: VERSION2,
@@ -28487,26 +29077,26 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28487
29077
  mv: props,
28488
29078
  applyPart,
28489
29079
  // the kernel and the shared state, for recorders that run the team's builders into something else than the house (`furnitureSpec`, `tapSpec`): not a stable api
28490
- internals: { K, shared },
29080
+ internals: { K, shared: shared2 },
28491
29081
  get materials() {
28492
- return shared.mats;
29082
+ return shared2.mats;
28493
29083
  },
28494
29084
  roomLightMask,
28495
29085
  lighting,
28496
29086
  setNight(n) {
28497
- shared.mats.glass.emissive.set(n ? 9067040 : 0);
28498
- shared.mats.glass.opacity = n ? 0.4 : 0.24;
29087
+ shared2.mats.glass.emissive.set(n ? 9067040 : 0);
29088
+ shared2.mats.glass.opacity = n ? 0.4 : 0.24;
28499
29089
  },
28500
29090
  cars: { model: carModel, group: carGroup, info: (k, seed) => {
28501
29091
  const m = carModel(k, seed);
28502
29092
  return m && { parts: m.parts.length, tris: m.tris, L: m.L, W: m.W, H: m.H };
28503
29093
  } },
28504
29094
  dispose() {
28505
- if (shared.vegMaterials) {
28506
- shared.vegMaterials.dispose();
28507
- shared.vegMaterials = null;
29095
+ if (shared2.vegMaterials) {
29096
+ shared2.vegMaterials.dispose();
29097
+ shared2.vegMaterials = null;
28508
29098
  }
28509
- for (const m of Object.values(shared.mats)) {
29099
+ for (const m of Object.values(shared2.mats)) {
28510
29100
  if (m && m.dispose) m.dispose();
28511
29101
  }
28512
29102
  for (const [k, t] of Object.entries(TEX)) if (t && t.dispose && !(cfg.textures && cfg.textures[k])) t.dispose();
@@ -28531,7 +29121,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28531
29121
  const colliderChanged = (c) => {
28532
29122
  if (c && cfg.onCollider) cfg.onCollider(c);
28533
29123
  };
28534
- const shared = { mats: null, quality: cfg.quality === "game" ? "game" : "high" };
29124
+ const shared2 = { mats: null, quality: cfg.quality === "game" ? "game" : "high" };
28535
29125
  const seedKey = (id) => {
28536
29126
  if (cfg.seedKey && id != null) {
28537
29127
  const k = cfg.seedKey(String(id));
@@ -28540,61 +29130,61 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28540
29130
  return id;
28541
29131
  };
28542
29132
  const K = { t: createTranslator2(cfg.locale), seedKey, THREE: shapeGeometries(THREE), cfg, DOC, PROPS, Reflector, FLEET, HP, invalidate, invalidateShadow, colliderChanged, VERSION, rectsOf, isOpenArea, OPEN_ROOM_TYPES: OPEN_ROOM_TYPES2 };
28543
- installKernelGeometry(K, shared);
28544
- installKernelNoise(K, shared);
28545
- installMaterialsTextures(K, shared);
28546
- installMaterialsMaterials(K, shared);
28547
- installKernelCloseScene(K, shared);
28548
- installHouseHelpers(K, shared);
28549
- installHouseWalls(K, shared);
28550
- installHouseDoors(K, shared);
28551
- installHouseWindows(K, shared);
28552
- installHouseFloors(K, shared);
28553
- installHouseStairs(K, shared);
28554
- installLightsFixtures(K, shared);
28555
- installLightsDecor(K, shared);
28556
- installLotTerrain(K, shared);
28557
- installLotPerimeter(K, shared);
28558
- installLotGates(K, shared);
28559
- installRoofRoofs(K, shared);
28560
- installRoofGutters(K, shared);
28561
- installRoofSlabs(K, shared);
28562
- installRoofTiles(K, shared);
28563
- installRoofRect(K, shared);
28564
- installMirrors(K, shared);
28565
- installCars(K, shared);
28566
- installHouseBuilding(K, shared);
28567
- installUtilitiesWater(K, shared);
28568
- installUtilitiesElectrical(K, shared);
28569
- installHouseBaseboard(K, shared);
28570
- installUtilitiesSolar(K, shared);
28571
- installHouseOutbuildings(K, shared);
28572
- installFurnitureApi(K, shared);
28573
- installFurnitureBuilders(K, shared);
28574
- installFurnitureTypeTable(K, shared);
28575
- installFurnitureTaps(K, shared);
28576
- installFurnitureFixtures(K, shared);
28577
- installFurniturePlants(K, shared);
28578
- installFurnitureYard(K, shared);
28579
- installFurnitureExtraTypes(K, shared);
28580
- installFurniturePlaceItems(K, shared);
28581
- installVegetationBridge(K, shared);
28582
- installInteractionState(K, shared);
28583
- installInteractionCollision(K, shared);
28584
- installInteractionItems(K, shared);
28585
- installInteractionFittings(K, shared);
28586
- installInteractionDoors(K, shared);
28587
- installInteractionTarget(K, shared);
28588
- installInteractablesBridge(K, shared);
28589
- installAnimationClotheslines(K, shared);
28590
- installBuildInstance(K, shared);
28591
- installInteractablesKit(K, shared);
28592
- installLightsRoomLight(K, shared);
28593
- installDestructionPieces(K, shared);
28594
- installDestructionBreach(K, shared);
28595
- installDestructionWorld(K, shared);
28596
- installBuildBuild(K, shared);
28597
- return buildApi(K, shared);
29133
+ installKernelGeometry(K, shared2);
29134
+ installKernelNoise(K, shared2);
29135
+ installMaterialsTextures(K, shared2);
29136
+ installMaterialsMaterials(K, shared2);
29137
+ installKernelCloseScene(K, shared2);
29138
+ installHouseHelpers(K, shared2);
29139
+ installHouseWalls(K, shared2);
29140
+ installHouseDoors(K, shared2);
29141
+ installHouseWindows(K, shared2);
29142
+ installHouseFloors(K, shared2);
29143
+ installHouseStairs(K, shared2);
29144
+ installLightsFixtures(K, shared2);
29145
+ installLightsDecor(K, shared2);
29146
+ installLotTerrain(K, shared2);
29147
+ installLotPerimeter(K, shared2);
29148
+ installLotGates(K, shared2);
29149
+ installRoofRoofs(K, shared2);
29150
+ installRoofGutters(K, shared2);
29151
+ installRoofSlabs(K, shared2);
29152
+ installRoofTiles(K, shared2);
29153
+ installRoofRect(K, shared2);
29154
+ installMirrors(K, shared2);
29155
+ installCars(K, shared2);
29156
+ installHouseBuilding(K, shared2);
29157
+ installUtilitiesWater(K, shared2);
29158
+ installUtilitiesElectrical(K, shared2);
29159
+ installHouseBaseboard(K, shared2);
29160
+ installUtilitiesSolar(K, shared2);
29161
+ installHouseOutbuildings(K, shared2);
29162
+ installFurnitureApi(K, shared2);
29163
+ installFurnitureBuilders(K, shared2);
29164
+ installFurnitureTypeTable(K, shared2);
29165
+ installFurnitureTaps(K, shared2);
29166
+ installFurnitureFixtures(K, shared2);
29167
+ installFurniturePlants(K, shared2);
29168
+ installFurnitureYard(K, shared2);
29169
+ installFurnitureExtraTypes(K, shared2);
29170
+ installFurniturePlaceItems(K, shared2);
29171
+ installVegetationBridge(K, shared2);
29172
+ installInteractionState(K, shared2);
29173
+ installInteractionCollision(K, shared2);
29174
+ installInteractionItems(K, shared2);
29175
+ installInteractionFittings(K, shared2);
29176
+ installInteractionDoors(K, shared2);
29177
+ installInteractionTarget(K, shared2);
29178
+ installInteractablesBridge(K, shared2);
29179
+ installAnimationClotheslines(K, shared2);
29180
+ installBuildInstance(K, shared2);
29181
+ installInteractablesKit(K, shared2);
29182
+ installLightsRoomLight(K, shared2);
29183
+ installDestructionPieces(K, shared2);
29184
+ installDestructionBreach(K, shared2);
29185
+ installDestructionWorld(K, shared2);
29186
+ installBuildBuild(K, shared2);
29187
+ return buildApi(K, shared2);
28598
29188
  }
28599
29189
  var WOOD_THIN = 0.035;
28600
29190
  var BOARD_TOP_THICK = 0.07;
@@ -28817,21 +29407,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
28817
29407
  const seed = Math.round(opts.seed ?? 1);
28818
29408
  const plain2 = SHELVING.test(type) ? "paper" : "plastic";
28819
29409
  const root = { x: seed, z: 0, ry: 0, w, d, h, y: 0, base: 0, palette: o.palette, seed: `furniture_${type}_${seed}` };
28820
- const { K, shared } = renderer.internals;
29410
+ const { K, shared: shared2 } = renderer.internals;
28821
29411
  const before = K.PARTS.length;
28822
29412
  const made = recordSpec(
28823
29413
  THREE,
28824
29414
  type,
28825
29415
  root,
28826
29416
  (A) => {
28827
- const saved = { api0: shared.api0, ctx: shared.ctx };
28828
- shared.api0 = A;
28829
- shared.ctx = shared.ctx ?? {};
29417
+ const saved = { api0: shared2.api0, ctx: shared2.ctx };
29418
+ shared2.api0 = A;
29419
+ shared2.ctx = shared2.ctx ?? {};
28830
29420
  try {
28831
29421
  ent.f(root, A);
28832
29422
  } finally {
28833
- shared.api0 = saved.api0;
28834
- shared.ctx = saved.ctx;
29423
+ shared2.api0 = saved.api0;
29424
+ shared2.ctx = saved.ctx;
28835
29425
  }
28836
29426
  },
28837
29427
  { materials: { plain: plain2, ...o.materials }, chairs: o.chairs, carcass: SHELVING.test(type) }
@@ -29400,7 +29990,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29400
29990
  const provider = options.provider ?? createFindsProvider(catalog);
29401
29991
  const items = catalog.list();
29402
29992
  const categories = [...ITEM_CATEGORIES.map((c) => c.id), ...[...catalog.categories.keys()].filter((id) => !ITEM_CATEGORIES.some((c) => c.id === id))].filter((id) => items.some((item) => item.category === id));
29403
- const shelves = shelvesLayout(items, categories);
29993
+ const openerOf = (item) => {
29994
+ const id = item.seal?.openWith?.find((tool2) => catalog.has(tool2));
29995
+ return id === void 0 ? void 0 : catalog.get(id);
29996
+ };
29997
+ const laid = items.flatMap((item) => {
29998
+ const opener = openerOf(item);
29999
+ return opener ? [item, { id: opener.id, category: item.category, size: opener.size }] : [item];
30000
+ });
30001
+ const shelves = shelvesLayout(laid, categories);
29404
30002
  const showcase = listItemModels().map((id) => ({ id, size: sizeOfModel(id), def: catalog.has(id) ? catalog.get(id) : void 0 }));
29405
30003
  const state = {
29406
30004
  category: CATEGORY_ALL,
@@ -29451,12 +30049,27 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29451
30049
  const contents = itemContents(subject);
29452
30050
  return contents ? { fluid: { container: contents.container, part: SHELL_PART_ID } } : {};
29453
30051
  };
30052
+ const sealOf = (def, fluid) => {
30053
+ const model = def.model;
30054
+ if (!def.seal || model === void 0 || !itemOpening(model)) return fluid;
30055
+ const openWith = def.seal.openWith ? [...def.seal.openWith, ...def.seal.openWith.map((id) => `${ITEM_PREFIX}${id}`)] : void 0;
30056
+ const seal = {
30057
+ ...def.seal,
30058
+ ...openWith ? { openWith } : {},
30059
+ open: (root) => void (latestTHREE && openItem(latestTHREE, root, model)),
30060
+ contents: (root, share) => setOpeningContents(root, share),
30061
+ // a screw cap is turned off by the other hand before the first bite or sip
30062
+ ...itemOpening(model)?.style === "screw_cap" ? { openUse: "unscrew", turn: (root, state2) => void turnItem(root, model, state2) } : {}
30063
+ };
30064
+ const eaten = def.category === "food" && fluid.fluid ? { fluid: { ...fluid.fluid, uses: ["eat", "pour_out"] } } : fluid;
30065
+ return { ...eaten, seal };
30066
+ };
29454
30067
  const itemOf = (def) => ({
29455
30068
  id: `${ITEM_PREFIX}${def.id}`,
29456
30069
  name: nameOf(def),
29457
30070
  movable: true,
29458
30071
  thumbnail: itemThumbnailSvg(drawable(def)),
29459
- ...fluidOf({ ...def.model === void 0 ? {} : { model: def.model }, size: def.size, weight: def.weight }),
30072
+ ...sealOf(def, fluidOf({ ...def.model === void 0 ? {} : { model: def.model }, size: def.size, weight: def.weight })),
29460
30073
  build: (THREE) => {
29461
30074
  const T2 = THREE;
29462
30075
  latestTHREE = T2;
@@ -29553,9 +30166,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29553
30166
  }
29554
30167
  };
29555
30168
  const clearBoxes = () => {
29556
- for (const box4 of boxes) {
29557
- box4.parent?.remove(box4);
29558
- }
30169
+ discardObject3D(boxes);
29559
30170
  boxes = [];
29560
30171
  };
29561
30172
  const applyBoxes = () => {
@@ -29574,7 +30185,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29574
30185
  };
29575
30186
  const clearFinds = () => {
29576
30187
  if (findsGroup) {
29577
- findsGroup.parent?.remove(findsGroup);
30188
+ discardObject3D(findsGroup);
29578
30189
  findsGroup = null;
29579
30190
  }
29580
30191
  };
@@ -29820,7 +30431,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29820
30431
  id: "modeled",
29821
30432
  name: text.metrics.modeled,
29822
30433
  read: () => {
29823
- const shown = visibleEntries().filter((entry2) => entry2.group === "shelf");
30434
+ const shown = [...new Map(visibleEntries().filter((entry2) => entry2.group === "shelf").map((entry2) => [entry2.itemId, entry2])).values()];
29824
30435
  return `${shown.filter((entry2) => entry2.kind === "model").length}/${shown.length}`;
29825
30436
  }
29826
30437
  },
@@ -29832,7 +30443,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
29832
30443
  latestTHREE = lent.THREE;
29833
30444
  const offChange = lent.bench?.onChange(onChange);
29834
30445
  const offFrame = lent.onFrame((dt) => {
29835
- for (const entry2 of entries2) if (entry2.group === "showcase" && entry2.root.parent) entry2.root.rotation.y += dt * SPIN;
30446
+ for (let i = entries2.length - 1; i >= 0; i--) if (!entries2[i].root.parent) entries2.splice(i, 1);
30447
+ for (let i = shelfRoots.length - 1; i >= 0; i--) if (!shelfRoots[i].parent) shelfRoots.splice(i, 1);
30448
+ for (const entry2 of entries2) if (entry2.group === "showcase") entry2.root.rotation.y += dt * SPIN;
29836
30449
  });
29837
30450
  return () => {
29838
30451
  offChange?.();