@adatechnology/game-floorplan-three 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +11 -1
- package/dist/index.global.js +310 -70
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +98 -24
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/dist/index.d.ts
CHANGED
|
@@ -599,7 +599,8 @@ interface FurnitureSpecResult {
|
|
|
599
599
|
* Materials: `wood` is `wood_hard`, and `wood_soft` for thin boards and panels (under 3.5 cm); `metal` is `steel`; `fabric`, `glass` and `plant` keep
|
|
600
600
|
* their name; `plain` is `plastic`, or `paper` for shelves and racks (their books and boxes). Parts that touch the floor are anchored. Joints come from
|
|
601
601
|
* `inferJoints` (screws between wood, welds or bolts between metal...), except that paper rests on what it lies on with a `resting` joint (weak: it falls when
|
|
602
|
-
* the board breaks) and is not joined to its neighbours.
|
|
602
|
+
* the board breaks) and is not joined to its neighbours. Shelves and racks stand as a carcass: the sides carry, each shelf needs both of its ends
|
|
603
|
+
* held, and the back panel carries nothing, so a broken side drops the shelves it held, with their books.
|
|
603
604
|
*
|
|
604
605
|
* @example
|
|
605
606
|
* const { spec, build, top } = furnitureSpec(THREE, 'bookcase') // 1.2 x 0.35 x 2 m, boards and books
|
|
@@ -648,6 +649,15 @@ interface WallPiece {
|
|
|
648
649
|
readonly spec: any;
|
|
649
650
|
/** Draws the wall with the house renderer: meshes carry `userData.destructionPart` of their part, in the space of the spec. */
|
|
650
651
|
build(THREE: any): any;
|
|
652
|
+
/**
|
|
653
|
+
* Once a drawing from `build` is in a destruction world as `objectId` (with this `spec`), the house renderer follows its events and draws on it what
|
|
654
|
+
* a generic destruction renderer cannot: the bricks that shots and blows knock out (`chip`) and the opening of a breach, as gaps in the wall's
|
|
655
|
+
* courses. `restore` puts the wall back (after `world.reset`), `dispose` stops following.
|
|
656
|
+
*/
|
|
657
|
+
follow(root: any, world: any, objectId: string): {
|
|
658
|
+
restore(): void;
|
|
659
|
+
dispose(): void;
|
|
660
|
+
} | null;
|
|
651
661
|
}
|
|
652
662
|
/**
|
|
653
663
|
* The plan of a free-standing wall along x, centred on the origin: a one-storey plan whose only wall is exterior on both sides, with the masonry construction of
|
package/dist/index.global.js
CHANGED
|
@@ -3551,8 +3551,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
3551
3551
|
var OPEN_ROOM_TYPES = /* @__PURE__ */ new Set(["balcony", "terrace", "veranda", "balcony_gourmet"]);
|
|
3552
3552
|
var rectsOf = (c) => c.parts && c.parts.length ? c.parts : [[c.u0, c.v0, c.u1, c.v1]];
|
|
3553
3553
|
var isOpenArea = (c) => OPEN_ROOM_TYPES.has(c.type) || c.outdoor === true;
|
|
3554
|
-
function planLod(
|
|
3555
|
-
const l =
|
|
3554
|
+
function planLod(houses2, focus, budget) {
|
|
3555
|
+
const l = houses2.map((c) => ({ c, d: c.distance(focus), n0: c.stats.drawCalls, n1: c.stats.drawCallsLOD1, level: 0 })).sort((a, b) => a.d - b.d);
|
|
3556
3556
|
let total = l.reduce((s, x) => s + x.n0, 0);
|
|
3557
3557
|
for (let i = l.length - 1; i >= 0 && total > budget; i--) {
|
|
3558
3558
|
total -= l[i].n0 - l[i].n1;
|
|
@@ -10695,12 +10695,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
10695
10695
|
A.invalidate = () => {
|
|
10696
10696
|
for (let i = 0; i < NS; i++) PL[i].shadow.needsUpdate = true;
|
|
10697
10697
|
};
|
|
10698
|
-
A.update = function(
|
|
10698
|
+
A.update = function(houses2, focus, op) {
|
|
10699
10699
|
op = op || {};
|
|
10700
|
-
|
|
10700
|
+
houses2 = (Array.isArray(houses2) ? houses2 : [houses2]).filter(Boolean);
|
|
10701
10701
|
_f.set(focus.x, focus.y, focus.z);
|
|
10702
10702
|
const rooms = [], exterior = [];
|
|
10703
|
-
for (const house of
|
|
10703
|
+
for (const house of houses2) {
|
|
10704
10704
|
if (house.group && !house.group.visible) continue;
|
|
10705
10705
|
house.house.updateMatrixWorld(true);
|
|
10706
10706
|
const M = house.house.matrixWorld, by = /* @__PURE__ */ new Map();
|
|
@@ -11232,6 +11232,62 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
11232
11232
|
return angle === 0 ? q : quat.mul(q, quat.fromAxisAngle([0, 0, 1], angle));
|
|
11233
11233
|
};
|
|
11234
11234
|
var clamp = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
11235
|
+
var splinterBox = (inp, box3, limit = inp.maxFragments) => {
|
|
11236
|
+
const { rnd } = inp;
|
|
11237
|
+
const dims = box3.s;
|
|
11238
|
+
const [fmin, fmax] = inp.fragmentSize;
|
|
11239
|
+
const g = inp.grain ?? [0, 1, 2].sort((a2, b2) => dims[b2] - dims[a2])[0];
|
|
11240
|
+
const [a, b] = [0, 1, 2].filter((i) => i !== g);
|
|
11241
|
+
const w = Math.max(fmin * 1.5, 0.01);
|
|
11242
|
+
const c = clamp(Math.round(dims[a] * dims[b] / (w * w)), 3, Math.max(3, Math.floor(limit / 2)));
|
|
11243
|
+
const maxLen = fmax * 4;
|
|
11244
|
+
const cells = bsp(box3, c, [a, b], rnd);
|
|
11245
|
+
const pieces = [];
|
|
11246
|
+
for (const cell of cells) {
|
|
11247
|
+
const extra = rnd() < 0.4 ? 1 : 0;
|
|
11248
|
+
const k = Math.max(1, Math.ceil(dims[g] / maxLen)) + extra;
|
|
11249
|
+
for (const p of bsp(cell, k, [g], rnd)) pieces.push(p);
|
|
11250
|
+
}
|
|
11251
|
+
return pieces.slice(0, limit).map((p) => ({ center: p.c, size: [p.s[g], p.s[a], p.s[b]], q: frame(g, a, b), shape: "splinter", weight: p.s[0] * p.s[1] * p.s[2] }));
|
|
11252
|
+
};
|
|
11253
|
+
var severAt = (inp, root, at, gap) => {
|
|
11254
|
+
const dims = root.s;
|
|
11255
|
+
const L = [0, 1, 2].sort((x, y) => dims[y] - dims[x])[0];
|
|
11256
|
+
const half = dims[L] / 2;
|
|
11257
|
+
const lo = clamp(at - gap / 2, -half, half), hi = clamp(at + gap / 2, -half, half);
|
|
11258
|
+
const out = [];
|
|
11259
|
+
const stub = (from, to) => {
|
|
11260
|
+
if (to - from < 0.02) return;
|
|
11261
|
+
const c = [root.c[0], root.c[1], root.c[2]], sz = [dims[0], dims[1], dims[2]];
|
|
11262
|
+
c[L] = (from + to) / 2;
|
|
11263
|
+
sz[L] = to - from;
|
|
11264
|
+
out.push({ center: c, size: sz, q: quat.identity(), shape: "slab", weight: sz[0] * sz[1] * sz[2] });
|
|
11265
|
+
};
|
|
11266
|
+
stub(-half, lo);
|
|
11267
|
+
stub(hi, half);
|
|
11268
|
+
const band = { c: [root.c[0], root.c[1], root.c[2]], s: [dims[0], dims[1], dims[2]] };
|
|
11269
|
+
band.c[L] = (lo + hi) / 2;
|
|
11270
|
+
band.s[L] = Math.max(hi - lo, 0.01);
|
|
11271
|
+
for (const p of splinterBox(inp, band, Math.max(3, inp.maxFragments - out.length))) out.push(p);
|
|
11272
|
+
return out;
|
|
11273
|
+
};
|
|
11274
|
+
var tearStack = (inp, root, t, u, v, n, sheet) => {
|
|
11275
|
+
const { dims, rnd, maxFragments } = inp;
|
|
11276
|
+
const layers = clamp(Math.ceil(dims[t] / STACK_LAYER), 2, 4);
|
|
11277
|
+
const per = clamp(n, 3, Math.max(3, Math.floor(maxFragments / layers)));
|
|
11278
|
+
const out = [];
|
|
11279
|
+
for (let k = 0; k < layers; k++) {
|
|
11280
|
+
const off = -dims[t] / 2 + (k + 0.5) * dims[t] / layers;
|
|
11281
|
+
for (const b of bsp(root, per, [u, v], rnd)) {
|
|
11282
|
+
if (out.length >= maxFragments) return out;
|
|
11283
|
+
const c = [b.c[0], b.c[1], b.c[2]];
|
|
11284
|
+
c[t] = off;
|
|
11285
|
+
out.push({ center: c, size: [b.s[u], b.s[v], sheet], q: frame(u, v, t, (rnd() - 0.5) * 0.8), shape: "scrap", weight: b.s[u] * b.s[v], inner: out.length % 4 !== 0 });
|
|
11286
|
+
}
|
|
11287
|
+
}
|
|
11288
|
+
return out;
|
|
11289
|
+
};
|
|
11290
|
+
var STACK_LAYER = 0.012;
|
|
11235
11291
|
var planFragments = (inp) => {
|
|
11236
11292
|
const { style, dims, rnd, maxFragments } = inp;
|
|
11237
11293
|
const [fmin, fmax] = inp.fragmentSize;
|
|
@@ -11253,27 +11309,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
11253
11309
|
return out;
|
|
11254
11310
|
}
|
|
11255
11311
|
if (style === "splinter") {
|
|
11256
|
-
|
|
11257
|
-
const
|
|
11258
|
-
const w = Math.max(fmin * 1.5, 0.01);
|
|
11259
|
-
const c = clamp(Math.round(dims[a] * dims[b] / (w * w)), 3, Math.max(3, Math.floor(maxFragments / 2)));
|
|
11260
|
-
const maxLen = fmax * 4;
|
|
11261
|
-
const cells = bsp(root, c, [a, b], rnd);
|
|
11262
|
-
const pieces = [];
|
|
11263
|
-
for (const cell of cells) {
|
|
11264
|
-
let list2 = [cell];
|
|
11265
|
-
const extra = rnd() < 0.4 ? 1 : 0;
|
|
11266
|
-
const k = Math.max(1, Math.ceil(dims[g] / maxLen)) + extra;
|
|
11267
|
-
list2 = bsp(cell, k, [g], rnd);
|
|
11268
|
-
for (const p of list2) pieces.push(p);
|
|
11269
|
-
}
|
|
11270
|
-
for (const p of pieces.slice(0, maxFragments)) {
|
|
11271
|
-
out.push({ center: p.c, size: [p.s[g], p.s[a], p.s[b]], q: frame(g, a, b), shape: "splinter", weight: p.s[0] * p.s[1] * p.s[2] });
|
|
11272
|
-
}
|
|
11312
|
+
if (inp.cut) return severAt(inp, root, inp.cut.at, inp.cut.gap);
|
|
11313
|
+
for (const p of splinterBox(inp, root)) out.push(p);
|
|
11273
11314
|
return out;
|
|
11274
11315
|
}
|
|
11275
11316
|
if (style === "tear") {
|
|
11276
11317
|
const n2 = clamp(Math.round(dims[u] * dims[v] / (mean * mean)), 3, maxFragments);
|
|
11318
|
+
const sheet = inp.sheet ?? 0;
|
|
11319
|
+
if (sheet > 0 && dims[t] > sheet * 4) return tearStack(inp, root, t, u, v, n2, sheet);
|
|
11277
11320
|
const th2 = Math.min(inp.thickness, dims[t]);
|
|
11278
11321
|
for (const b of bsp(root, n2, [u, v], rnd)) {
|
|
11279
11322
|
out.push({ center: [b.c[0], b.c[1], b.c[2]], size: [b.s[u], b.s[v], th2], q: frame(u, v, t), shape: "scrap", weight: b.s[u] * b.s[v] });
|
|
@@ -12856,6 +12899,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
12856
12899
|
0.03,
|
|
12857
12900
|
0.15
|
|
12858
12901
|
],
|
|
12902
|
+
sheet: 1e-3,
|
|
12859
12903
|
damageScale: {
|
|
12860
12904
|
slash: 3
|
|
12861
12905
|
},
|
|
@@ -12871,7 +12915,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
12871
12915
|
smoke: "grey"
|
|
12872
12916
|
},
|
|
12873
12917
|
visual: {
|
|
12874
|
-
charColor: 1709072
|
|
12918
|
+
charColor: 1709072,
|
|
12919
|
+
innerColor: 15524048
|
|
12875
12920
|
},
|
|
12876
12921
|
tags: [
|
|
12877
12922
|
"fabric",
|
|
@@ -13253,9 +13298,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
13253
13298
|
var BREACH_AREA = 0.25;
|
|
13254
13299
|
var BREACH_BLAST_REACH = 0.12;
|
|
13255
13300
|
var RESIDUAL_CAPACITY = 0.15;
|
|
13301
|
+
var SEVER_BAND = 0.1;
|
|
13302
|
+
var SEVER_ASPECT = 3;
|
|
13303
|
+
var SEVER_BALLISTIC = 2;
|
|
13256
13304
|
var SUPPORT_TOLERANCE = 0.05;
|
|
13257
13305
|
var UNIT_FRAGMENT_FACTOR = 4;
|
|
13258
13306
|
var BREACH_GRID_CAP = 4096;
|
|
13307
|
+
var CHIP_ENERGY = 200;
|
|
13308
|
+
var CHIP_SPLASH = 0.5;
|
|
13259
13309
|
var CUT_SLICE = 1;
|
|
13260
13310
|
var cutFactorOf = (shape) => clamp2(Math.max(...shapeDims(shape)) / CUT_SLICE, 1, 50);
|
|
13261
13311
|
var clamp2 = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
@@ -13299,6 +13349,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
13299
13349
|
let windCfg = windOpts ? resolveWind(windOpts) : null;
|
|
13300
13350
|
const ignitionRules = resolveIgnitionRules(options.ignition);
|
|
13301
13351
|
const breachBlastFactor = options.breach?.blastFactor ?? BREACH_BLAST_FACTOR;
|
|
13352
|
+
const chipEnergy = options.breach?.chipEnergy ?? CHIP_ENERGY;
|
|
13302
13353
|
const rng2 = createRng(options.seed ?? 1);
|
|
13303
13354
|
const rnd = () => rng2.next();
|
|
13304
13355
|
let time = 0;
|
|
@@ -13672,41 +13723,68 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
13672
13723
|
markDamaged(p);
|
|
13673
13724
|
if (p.rt.hinge >= flexure.failRotationDeg * Math.PI / 180) hingeDrop(o, p, src);
|
|
13674
13725
|
};
|
|
13726
|
+
const freeSpan = (p, supports) => {
|
|
13727
|
+
if (supports.length === 0) return Infinity;
|
|
13728
|
+
const d = p.dims;
|
|
13729
|
+
const L = [0, 1, 2].sort((a, b) => d[b] - d[a])[0];
|
|
13730
|
+
const spans = supports.map((k) => contactBox(p, k)).map(([lo, hi]) => [lo[L], hi[L]]);
|
|
13731
|
+
let far = 0;
|
|
13732
|
+
for (let i = 0; i <= 16; i++) {
|
|
13733
|
+
const x = (i / 16 - 0.5) * d[L];
|
|
13734
|
+
let near = Infinity;
|
|
13735
|
+
for (const [lo, hi] of spans) near = Math.min(near, Math.max(lo - x, x - hi, 0));
|
|
13736
|
+
far = Math.max(far, near);
|
|
13737
|
+
}
|
|
13738
|
+
return 2 * far;
|
|
13739
|
+
};
|
|
13675
13740
|
const solveStructure = (o) => {
|
|
13676
13741
|
o.maxStress = 0;
|
|
13677
13742
|
if (!o.hasStructure) return;
|
|
13678
13743
|
const parts = o.parts;
|
|
13679
13744
|
const n = parts.length;
|
|
13680
13745
|
const dist = new Array(n).fill(-1);
|
|
13681
|
-
const queue = [];
|
|
13682
13746
|
const ok = (i) => parts[i].structural && !isLost(parts[i]);
|
|
13683
13747
|
const isPartition = (i) => parts[i].spec.structure?.role === "partition";
|
|
13684
|
-
|
|
13685
|
-
|
|
13686
|
-
|
|
13687
|
-
|
|
13688
|
-
|
|
13689
|
-
|
|
13690
|
-
if (
|
|
13691
|
-
|
|
13692
|
-
|
|
13693
|
-
|
|
13694
|
-
|
|
13695
|
-
|
|
13696
|
-
|
|
13748
|
+
const out = /* @__PURE__ */ new Set();
|
|
13749
|
+
let queue = [];
|
|
13750
|
+
let lowerOf = /* @__PURE__ */ new Map();
|
|
13751
|
+
for (; ; ) {
|
|
13752
|
+
dist.fill(-1);
|
|
13753
|
+
queue = [];
|
|
13754
|
+
for (let i = 0; i < n; i++) if (ok(i) && !out.has(i) && parts[i].anchored) {
|
|
13755
|
+
dist[i] = 0;
|
|
13756
|
+
queue.push(i);
|
|
13757
|
+
}
|
|
13758
|
+
for (let h = 0; h < queue.length; h++) {
|
|
13759
|
+
const s = queue[h];
|
|
13760
|
+
if (isPartition(s)) continue;
|
|
13761
|
+
for (const j of o.byPart.get(parts[s].spec.id)) {
|
|
13762
|
+
if (j.st.open || !j.bears) continue;
|
|
13763
|
+
const r = j.ia === s ? j.ib : j.ia;
|
|
13764
|
+
if (dist[r] >= 0 || !ok(r) || out.has(r) || restsOn(o, j, r) !== s) continue;
|
|
13765
|
+
dist[r] = dist[s] + 1;
|
|
13766
|
+
queue.push(r);
|
|
13767
|
+
}
|
|
13697
13768
|
}
|
|
13698
|
-
|
|
13699
|
-
|
|
13700
|
-
|
|
13701
|
-
|
|
13702
|
-
|
|
13703
|
-
|
|
13704
|
-
|
|
13705
|
-
|
|
13706
|
-
|
|
13769
|
+
lowerOf = /* @__PURE__ */ new Map();
|
|
13770
|
+
let dropped = false;
|
|
13771
|
+
for (const i of queue) {
|
|
13772
|
+
const lower = [];
|
|
13773
|
+
for (const j of o.byPart.get(parts[i].spec.id)) {
|
|
13774
|
+
if (j.st.open || !j.bears) continue;
|
|
13775
|
+
const k = restsOn(o, j, i);
|
|
13776
|
+
if (k >= 0 && dist[k] >= 0 && dist[k] < dist[i] && !isPartition(k)) lower.push(k);
|
|
13777
|
+
}
|
|
13778
|
+
lowerOf.set(i, lower);
|
|
13779
|
+
const max = parts[i].spec.structure?.maxSpan;
|
|
13780
|
+
if (max !== void 0 && !parts[i].anchored && freeSpan(parts[i], lower.map((k) => parts[k])) > max) {
|
|
13781
|
+
out.add(i);
|
|
13782
|
+
dropped = true;
|
|
13783
|
+
}
|
|
13707
13784
|
}
|
|
13708
|
-
|
|
13785
|
+
if (!dropped) break;
|
|
13709
13786
|
}
|
|
13787
|
+
const incoming = new Array(n).fill(0);
|
|
13710
13788
|
const bending = new Array(n).fill(0);
|
|
13711
13789
|
const through = parts.map(() => []);
|
|
13712
13790
|
const pass = (k, at, mass) => {
|
|
@@ -14218,6 +14296,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14218
14296
|
const r = rayPart(o, p, origin, d);
|
|
14219
14297
|
if (!r || r.t0 < 0 || r.t0 > maxDist) continue;
|
|
14220
14298
|
if (p.st.opening && insideOpening(o, p, vec.madd(origin, d, r.t0))) continue;
|
|
14299
|
+
if (p.st.chipped && insideChip(p, objLocal(o, vec.madd(origin, d, r.t0)))) continue;
|
|
14221
14300
|
if (!best || r.t0 < best.distance) best = { object: o.id, part: p.spec.id, point: vec.madd(origin, d, r.t0), normal: r.n, distance: r.t0, pathLen: r.t1 - r.t0 };
|
|
14222
14301
|
}
|
|
14223
14302
|
}
|
|
@@ -14481,6 +14560,62 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14481
14560
|
if (total < (p.spec.breach?.area ?? BREACH_AREA)) return;
|
|
14482
14561
|
openBreach(o, p, [sum[0] / total, sum[1] / total, sum[2] / total], total, energy, dir, src);
|
|
14483
14562
|
};
|
|
14563
|
+
const unitGrids = /* @__PURE__ */ new WeakMap();
|
|
14564
|
+
const gridOf = (p) => {
|
|
14565
|
+
let grid = unitGrids.get(p);
|
|
14566
|
+
if (!grid) unitGrids.set(p, grid = unitGrid(p.dims, p.thin, unitsOf2(p), BREACH_GRID_CAP));
|
|
14567
|
+
return grid;
|
|
14568
|
+
};
|
|
14569
|
+
const insideChip = (p, objectPoint) => {
|
|
14570
|
+
const cells = p.st.chipped;
|
|
14571
|
+
if (!cells?.length) return false;
|
|
14572
|
+
const [u, v] = planeAxes(p.thin);
|
|
14573
|
+
const lp = toLocal(p.pos, p.q, objectPoint);
|
|
14574
|
+
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);
|
|
14575
|
+
};
|
|
14576
|
+
const chipUnits = (o, p, wp, energy, dir, radius, src) => {
|
|
14577
|
+
var _a, _b;
|
|
14578
|
+
if (!p.spec.units || p.spec.reinforcement || !p.staged || chipEnergy <= 0 || energy <= 0 || p.st.stripped || isLost(p) || (p.st.stage ?? 0) >= 2) return;
|
|
14579
|
+
const [u, v] = planeAxes(p.thin);
|
|
14580
|
+
const lp = toLocal(p.pos, p.q, objLocal(o, wp));
|
|
14581
|
+
const grid = gridOf(p);
|
|
14582
|
+
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
14583
|
+
const out = [];
|
|
14584
|
+
for (let i = 0; i < grid.length; i++) {
|
|
14585
|
+
const cell = grid[i];
|
|
14586
|
+
if (worn[i] === -1) continue;
|
|
14587
|
+
const gap = Math.hypot(Math.max(0, Math.abs(lp[u] - cell.center[u]) - cell.size[u] / 2), Math.max(0, Math.abs(lp[v] - cell.center[v]) - cell.size[v] / 2));
|
|
14588
|
+
if (gap > radius) continue;
|
|
14589
|
+
const share = gap === 0 ? 1 : CHIP_SPLASH * (1 - gap / radius);
|
|
14590
|
+
const total = (worn[i] ?? 0) + energy * share;
|
|
14591
|
+
const mass = p.mat.density * cell.size[0] * cell.size[1] * cell.size[2];
|
|
14592
|
+
if (total < chipEnergy * mass) {
|
|
14593
|
+
worn[i] = total;
|
|
14594
|
+
continue;
|
|
14595
|
+
}
|
|
14596
|
+
worn[i] = -1;
|
|
14597
|
+
out.push(cell);
|
|
14598
|
+
}
|
|
14599
|
+
if (out.length === 0) return;
|
|
14600
|
+
const { c, q } = partXf(o, p);
|
|
14601
|
+
const chipped = (_b = p.st).chipped ?? (_b.chipped = []);
|
|
14602
|
+
const holes = localHolesOf(p);
|
|
14603
|
+
for (const cell of out) {
|
|
14604
|
+
const mass = Math.min(p.st.mass, p.mat.density * cell.size[0] * cell.size[1] * cell.size[2]);
|
|
14605
|
+
const center = toWorld(c, q, cell.center);
|
|
14606
|
+
const speed = clamp2(Math.sqrt(2 * energy * 0.05 / Math.max(mass, 0.05)), 0.5, 6);
|
|
14607
|
+
const fragments = cellFragments(o, p, [cell], wp, dir, speed, mass, `c${chipped.length}_`);
|
|
14608
|
+
p.st.holes = p.st.holes.filter((_, k) => marksInBox(cell.center, cell.size, void 0, [holes[k]]).length === 0);
|
|
14609
|
+
chipped.push({ center: [cell.center[0], cell.center[1], cell.center[2]], size: [cell.size[0], cell.size[1], cell.size[2]] });
|
|
14610
|
+
p.st.mass = Math.max(0, p.st.mass - mass);
|
|
14611
|
+
p.rt.removed = (p.rt.removed ?? 0) + mass;
|
|
14612
|
+
markDamaged(p);
|
|
14613
|
+
setStage(o, p, 1, {}, src);
|
|
14614
|
+
emit({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [cell.size[0], cell.size[1], cell.size[2]], rotation: q, fragments });
|
|
14615
|
+
debris(o, p, p.mat.breakDebris, center, vec.scale(dir ?? [0, 1, 0], -1), 6, 2, src);
|
|
14616
|
+
}
|
|
14617
|
+
for (const cell of out) addBreach(o, p, toWorld(c, q, cell.center), cell.size[u] * cell.size[v], energy, dir, src);
|
|
14618
|
+
};
|
|
14484
14619
|
const openBreach = (o, p, center, total, energy, dir, src) => {
|
|
14485
14620
|
const [u, v] = planeAxes(p.thin);
|
|
14486
14621
|
const radius = clamp2(Math.sqrt(total / Math.PI), Math.sqrt((p.spec.breach?.area ?? BREACH_AREA) / Math.PI), breachRadius);
|
|
@@ -14492,7 +14627,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14492
14627
|
failPart(o, p, worldCenter, dir, energy, 12, src);
|
|
14493
14628
|
return;
|
|
14494
14629
|
}
|
|
14495
|
-
const
|
|
14630
|
+
const worn = p.rt.chips;
|
|
14631
|
+
const cells = cellsWithin(gridOf(p).filter((_, i) => worn?.[i] !== -1), p.thin, lc, radius);
|
|
14496
14632
|
const removed = p.st.mass * cells.reduce((sum, cell) => sum + cell.size[u] * cell.size[v], 0) / (p.dims[u] * p.dims[v]);
|
|
14497
14633
|
const speed = clamp2(Math.sqrt(2 * energy * 0.1 / Math.max(removed, 0.05)), 0.5, 8);
|
|
14498
14634
|
const fragments = cellFragments(o, p, cells, worldCenter, dir, speed, removed, "b");
|
|
@@ -14576,6 +14712,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14576
14712
|
const grain = p.spec.grain ? AXIS[p.spec.grain] : void 0;
|
|
14577
14713
|
const hitLocal = toLocal(c, q, hitW);
|
|
14578
14714
|
const unitPlan = p.spec.units ? unitFragmentPlan(p, maxFragments * UNIT_FRAGMENT_FACTOR) : [];
|
|
14715
|
+
const axis = style === "splinter" ? severAxis(p) : -1;
|
|
14716
|
+
const cutAt2 = axis < 0 ? void 0 : p.rt.cutAt ?? (origin ? hitLocal[axis] : void 0);
|
|
14579
14717
|
const plan = unitPlan.length > 0 ? unitPlan : planFragments({
|
|
14580
14718
|
style,
|
|
14581
14719
|
dims: p.dims,
|
|
@@ -14584,7 +14722,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14584
14722
|
hit: hitLocal,
|
|
14585
14723
|
fragmentSize: p.mat.fragmentSize ?? [0.04, 0.2],
|
|
14586
14724
|
maxFragments,
|
|
14587
|
-
rnd
|
|
14725
|
+
rnd,
|
|
14726
|
+
sheet: p.mat.sheet,
|
|
14727
|
+
...cutAt2 !== void 0 ? { cut: { at: cutAt2, gap: SEVER_BAND } } : {}
|
|
14588
14728
|
});
|
|
14589
14729
|
const holes = p.st.holes.length > 0 ? localHolesOf(p) : [];
|
|
14590
14730
|
const mass = p.st.mass;
|
|
@@ -14608,7 +14748,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14608
14748
|
velocity: [dv[0] * k, dv[1] * k + 0.5 * rnd(), dv[2] * k],
|
|
14609
14749
|
angularVelocity: [(rnd() - 0.5) * 12, (rnd() - 0.5) * 12, (rnd() - 0.5) * 12],
|
|
14610
14750
|
mass: mass * f.weight / totW,
|
|
14611
|
-
...marks.length > 0 ? { marks } : {}
|
|
14751
|
+
...marks.length > 0 ? { marks } : {},
|
|
14752
|
+
...f.inner ? { inner: true } : {}
|
|
14612
14753
|
};
|
|
14613
14754
|
});
|
|
14614
14755
|
const reinforcement = p.spec.reinforcement;
|
|
@@ -14642,10 +14783,33 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14642
14783
|
emit({ ...base(o, src), type: "primed", part: p.spec.id, point: partXf(o, p).c, trigger, delay });
|
|
14643
14784
|
};
|
|
14644
14785
|
const CHAIN_TRIGGER_OF = { ballistic: "shot", explosive: "explosion" };
|
|
14786
|
+
const severAxis = (p) => {
|
|
14787
|
+
if (p.mat.fracture !== "splinter" || p.spec.shape.kind !== "box") return -1;
|
|
14788
|
+
const d = p.dims;
|
|
14789
|
+
const order = [0, 1, 2].sort((a, b) => d[b] - d[a]);
|
|
14790
|
+
return d[order[0]] >= SEVER_ASPECT * d[order[1]] && d[order[0]] >= 3 * SEVER_BAND ? order[0] : -1;
|
|
14791
|
+
};
|
|
14792
|
+
const bandOf = (o, p, axis, origin) => {
|
|
14793
|
+
const { c, q } = partXf(o, p);
|
|
14794
|
+
const along = toLocal(c, q, origin)[axis];
|
|
14795
|
+
const L = p.dims[axis];
|
|
14796
|
+
return clamp2(Math.floor((along + L / 2) / SEVER_BAND), 0, Math.ceil(L / SEVER_BAND) - 1);
|
|
14797
|
+
};
|
|
14645
14798
|
const applyDamage = (o, p, amount, type, origin, dir, fragEnergy, cap, src) => {
|
|
14799
|
+
var _a;
|
|
14646
14800
|
if (isLost(p) || amount <= 0) return 0;
|
|
14647
14801
|
const prev = p.st.hp;
|
|
14648
14802
|
p.st.hp -= amount;
|
|
14803
|
+
const axis = origin && type !== "fire" && type !== "heat" ? severAxis(p) : -1;
|
|
14804
|
+
if (axis >= 0 && p.st.hp > 0) {
|
|
14805
|
+
const band = bandOf(o, p, axis, origin);
|
|
14806
|
+
const cuts = (_a = p.rt).cuts ?? (_a.cuts = {});
|
|
14807
|
+
cuts[band] = (cuts[band] ?? 0) + amount * (type === "ballistic" ? SEVER_BALLISTIC : 1);
|
|
14808
|
+
if (cuts[band] >= p.st.maxHp * SEVER_BAND / p.dims[axis]) {
|
|
14809
|
+
p.rt.cutAt = -p.dims[axis] / 2 + (band + 0.5) * SEVER_BAND;
|
|
14810
|
+
p.st.hp = 0;
|
|
14811
|
+
}
|
|
14812
|
+
}
|
|
14649
14813
|
markDamaged(p);
|
|
14650
14814
|
const trigger = CHAIN_TRIGGER_OF[type];
|
|
14651
14815
|
const chained = trigger !== void 0 && chainDelayOf(p.spec, trigger) !== void 0;
|
|
@@ -14684,7 +14848,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14684
14848
|
const ballistic = (o, p, entry2, n, d, E, caliber, pathLen, src, round3 = {}) => {
|
|
14685
14849
|
const mat = p.mat;
|
|
14686
14850
|
const piercing = round3.piercing ?? 1;
|
|
14687
|
-
if (p.st.stripped || p.st.opening && insideOpening(o, p, objLocal(o, entry2))) {
|
|
14851
|
+
if (p.st.stripped || p.st.opening && insideOpening(o, p, objLocal(o, entry2)) || insideChip(p, objLocal(o, entry2))) {
|
|
14688
14852
|
return { penetrated: true, exitEnergy: E, exitPoint: vec.madd(entry2, d, Math.min(pathLen, p.thickness)), damage: 0 };
|
|
14689
14853
|
}
|
|
14690
14854
|
const sin = Math.min(1, Math.abs(vec.dot(d, n)));
|
|
@@ -14743,6 +14907,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14743
14907
|
debris(o, p, mat.hitDebris, entry2, n, clamp2(Math.round(E / 60) + 2, 2, 14), clamp2(Math.sqrt(E) / 6, 1, 8), src);
|
|
14744
14908
|
wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true);
|
|
14745
14909
|
const dmg = applyDamage(o, p, E * DMG_PER_J * scale, "ballistic", entry2, d, E * 0.1, 12, src);
|
|
14910
|
+
chipUnits(o, p, entry2, penetrated ? Math.min(E, Math.max(thr, E * 0.5)) : E, d, Math.max(0.05, caliber / 1e3 * 8), src);
|
|
14746
14911
|
return { penetrated, exitEnergy: penetrated ? penMm !== void 0 ? E * (1 - thr / Ep) : E - thr / (hard ? piercing : 1) : 0, exitPoint, damage: dmg };
|
|
14747
14912
|
};
|
|
14748
14913
|
const melee = (o, p, kind, E, point, n, d, contactR, src) => {
|
|
@@ -14770,6 +14935,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14770
14935
|
const scale = mat.damageScale?.[kind] ?? 1;
|
|
14771
14936
|
const done = applyDamage(o, p, Ec * DMG_PER_J * scale * (kind === "slash" ? p.cutFactor : 1), kind, point, d, E * 0.1, 12, src);
|
|
14772
14937
|
addBreach(o, p, point, breachAreaOf(p, done, false), E, d, src);
|
|
14938
|
+
if (kind === "blunt") chipUnits(o, p, point, E, d, Math.max(contactR, 0.03), src);
|
|
14773
14939
|
return done;
|
|
14774
14940
|
};
|
|
14775
14941
|
const blastPart = (o, p, point, energy, radius, src, res, reachAt) => {
|
|
@@ -19083,7 +19249,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19083
19249
|
}
|
|
19084
19250
|
return null;
|
|
19085
19251
|
};
|
|
19086
|
-
|
|
19252
|
+
const local = (p) => {
|
|
19253
|
+
house.updateMatrixWorld(true);
|
|
19254
|
+
const v = house.worldToLocal(tmp.p.set(p[0], p[1], p[2]));
|
|
19255
|
+
return [v.x, v.y, v.z];
|
|
19256
|
+
};
|
|
19257
|
+
function courses(part, units, opening, chips, paint) {
|
|
19087
19258
|
const [u0, v0, u1, v1] = part.aabb;
|
|
19088
19259
|
const alongU = u1 - u0 >= v1 - v0;
|
|
19089
19260
|
const len = alongU ? u1 - u0 : v1 - v0;
|
|
@@ -19107,23 +19278,39 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19107
19278
|
const x = alongU ? u0 + mid : (u0 + u1) / 2;
|
|
19108
19279
|
const z = alongU ? (v0 + v1) / 2 : v0 + mid;
|
|
19109
19280
|
const y = part.y0 + (r + 0.5) * rowH;
|
|
19110
|
-
const d = Math.hypot(x - opening.center[0], y - opening.center[1], z - opening.center[2]);
|
|
19111
|
-
if (d < opening.radius) continue;
|
|
19112
|
-
|
|
19281
|
+
const d = opening ? Math.hypot(x - opening.center[0], y - opening.center[1], z - opening.center[2]) : Infinity;
|
|
19282
|
+
if (opening && d < opening.radius) continue;
|
|
19283
|
+
const gone = (c) => Math.abs(c[1] - y) <= rowH / 2 && (alongU ? c[0] >= u0 + a && c[0] <= u0 + b : c[2] >= v0 + a && c[2] <= v0 + b);
|
|
19284
|
+
if (chips.some(gone)) continue;
|
|
19285
|
+
const near = opening && d < opening.radius + 0.25 || chips.some((c) => Math.hypot(c[0] - x, c[1] - y, c[2] - z) < 0.15);
|
|
19286
|
+
list2.push({ x, y, z, sx: alongU ? b - a : thick, sy: rowH, sz: alongU ? thick : b - a, colour: near || paint === null ? edge : paint });
|
|
19113
19287
|
}
|
|
19114
19288
|
}
|
|
19115
19289
|
return list2;
|
|
19116
19290
|
}
|
|
19117
|
-
function
|
|
19118
|
-
if (lod !== 0
|
|
19119
|
-
const part = structure.byId.get(
|
|
19120
|
-
const spec = opts.spec()?.parts?.find((q) => q.id ===
|
|
19291
|
+
function draw2(partId, change) {
|
|
19292
|
+
if (lod !== 0) return false;
|
|
19293
|
+
const part = structure.byId.get(partId);
|
|
19294
|
+
const spec = opts.spec()?.parts?.find((q) => q.id === partId);
|
|
19121
19295
|
if (!part || !spec || !spec.units) return false;
|
|
19122
|
-
|
|
19123
|
-
if (!
|
|
19124
|
-
|
|
19296
|
+
let view = views.get(partId);
|
|
19297
|
+
if (!view) {
|
|
19298
|
+
const items = structure.meshesOf(partId).filter((it) => it.mesh);
|
|
19299
|
+
if (!items.length) return false;
|
|
19300
|
+
view = { mesh: null, saved: null, items, paint: wallColour(items), units: 0, opening: null, chips: [] };
|
|
19301
|
+
}
|
|
19302
|
+
if (change.opening) {
|
|
19303
|
+
if (view.opening) return false;
|
|
19304
|
+
view.opening = { center: local(change.opening.center), radius: change.opening.radius };
|
|
19305
|
+
}
|
|
19306
|
+
if (change.chip) view.chips.push(local(change.chip));
|
|
19307
|
+
const list2 = courses(part, spec.units, view.opening, view.chips, view.paint);
|
|
19308
|
+
if (view.mesh) {
|
|
19309
|
+
view.mesh.removeFromParent();
|
|
19310
|
+
view.mesh.dispose();
|
|
19311
|
+
}
|
|
19125
19312
|
const mesh2 = new THREE.InstancedMesh(unitGeometry, unitMaterial, Math.max(1, list2.length));
|
|
19126
|
-
mesh2.name = "breach:" +
|
|
19313
|
+
mesh2.name = "breach:" + partId;
|
|
19127
19314
|
list2.forEach((u, i) => {
|
|
19128
19315
|
tmp.m.compose(tmp.p.set(u.x, u.y, u.z), tmp.q.identity(), tmp.s.set(u.sx, u.sy, u.sz));
|
|
19129
19316
|
mesh2.setMatrixAt(i, tmp.m);
|
|
@@ -19135,8 +19322,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19135
19322
|
mesh2.castShadow = true;
|
|
19136
19323
|
mesh2.receiveShadow = true;
|
|
19137
19324
|
house.add(mesh2);
|
|
19138
|
-
|
|
19139
|
-
|
|
19325
|
+
if (!view.saved) view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
19326
|
+
view.mesh = mesh2;
|
|
19327
|
+
view.units = list2.length;
|
|
19328
|
+
views.set(partId, view);
|
|
19140
19329
|
invalidate();
|
|
19141
19330
|
invalidateShadow();
|
|
19142
19331
|
return true;
|
|
@@ -19150,7 +19339,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19150
19339
|
return {
|
|
19151
19340
|
/** Handles a `stage` event of the house's object. Returns true when the wall was redrawn as courses. */
|
|
19152
19341
|
stage(event) {
|
|
19153
|
-
return event.stage === 2 ?
|
|
19342
|
+
return event.stage === 2 && !!event.opening ? draw2(event.part, { opening: event.opening }) : false;
|
|
19343
|
+
},
|
|
19344
|
+
/** Handles a `chip` event: the unit that came out leaves a gap in the courses. Returns true when the wall was redrawn. */
|
|
19345
|
+
chip(event) {
|
|
19346
|
+
return draw2(event.part, { chip: event.center });
|
|
19154
19347
|
},
|
|
19155
19348
|
/** The part broke or fell: the courses go (the plain range stays collapsed, the renderer hides the part). */
|
|
19156
19349
|
drop(partId) {
|
|
@@ -19382,6 +19575,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19382
19575
|
case "stage":
|
|
19383
19576
|
breach.stage(e);
|
|
19384
19577
|
break;
|
|
19578
|
+
case "chip":
|
|
19579
|
+
breach.chip(e);
|
|
19580
|
+
break;
|
|
19385
19581
|
case "collapse":
|
|
19386
19582
|
for (const id of e.parts) {
|
|
19387
19583
|
breach.drop(id);
|
|
@@ -19436,6 +19632,32 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19436
19632
|
if (D.active && D.world.has(D.id)) D.world.remove(D.id);
|
|
19437
19633
|
D.active = false;
|
|
19438
19634
|
};
|
|
19635
|
+
D.follow = (world, id, spec) => {
|
|
19636
|
+
D.spec = spec;
|
|
19637
|
+
const offFollow = world.on("*", (e) => {
|
|
19638
|
+
if (e.object !== id) return;
|
|
19639
|
+
switch (e.type) {
|
|
19640
|
+
case "stage":
|
|
19641
|
+
breach.stage(e);
|
|
19642
|
+
break;
|
|
19643
|
+
case "chip":
|
|
19644
|
+
breach.chip(e);
|
|
19645
|
+
break;
|
|
19646
|
+
case "fracture":
|
|
19647
|
+
breach.drop(e.part);
|
|
19648
|
+
break;
|
|
19649
|
+
case "collapse":
|
|
19650
|
+
for (const p of e.parts) breach.drop(p);
|
|
19651
|
+
break;
|
|
19652
|
+
default:
|
|
19653
|
+
break;
|
|
19654
|
+
}
|
|
19655
|
+
});
|
|
19656
|
+
return { restore: () => breach.restore(), dispose: () => {
|
|
19657
|
+
offFollow();
|
|
19658
|
+
breach.restore();
|
|
19659
|
+
} };
|
|
19660
|
+
};
|
|
19439
19661
|
D.piece = (id) => D.active ? D.world.part(D.id, id) : null;
|
|
19440
19662
|
D.state = () => D.active ? D.world.state(D.id) : null;
|
|
19441
19663
|
D.reset = () => {
|
|
@@ -22557,6 +22779,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22557
22779
|
|
|
22558
22780
|
// src/furniture/spec.ts
|
|
22559
22781
|
var WOOD_THIN = 0.035;
|
|
22782
|
+
var SHELF_SPAN = 1.5;
|
|
22783
|
+
var SHELVING = /shelf|bookcase|rack/;
|
|
22784
|
+
function carcass(parts, drawn) {
|
|
22785
|
+
const all = [...drawn.values()];
|
|
22786
|
+
const width = Math.max(...all.map((p) => p.max[0])) - Math.min(...all.map((p) => p.min[0]));
|
|
22787
|
+
for (const part of parts) {
|
|
22788
|
+
if (LOOSE.has(part.material) || part.shape.kind !== "box" || part.rotation) continue;
|
|
22789
|
+
const [x, y, z] = part.shape.size;
|
|
22790
|
+
if (y >= x && y >= z) {
|
|
22791
|
+
if (z < x && x >= 0.6 * width) continue;
|
|
22792
|
+
part.structure = { role: "column" };
|
|
22793
|
+
} else if (y <= x && y <= z) part.structure = { role: "beam", maxSpan: SHELF_SPAN * Math.max(x, z) };
|
|
22794
|
+
}
|
|
22795
|
+
}
|
|
22560
22796
|
var FLOOR_TOUCH = 5e-3;
|
|
22561
22797
|
var LOOSE = /* @__PURE__ */ new Set(["paper"]);
|
|
22562
22798
|
var BASE_MATERIAL = {
|
|
@@ -22672,6 +22908,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22672
22908
|
if (area3 < 0.6 * footprint || p.max[1] < 0.2) continue;
|
|
22673
22909
|
if (!top || p.max[1] > top.y + 1e-6) top = { part: p.id, y: p.max[1] };
|
|
22674
22910
|
}
|
|
22911
|
+
if (opts.carcass) carcass(parts, byId);
|
|
22675
22912
|
const spec = { name, parts, joints, tags: ["furniture"] };
|
|
22676
22913
|
const colors = new Map(drawn.map((p) => [p.id, p.color]));
|
|
22677
22914
|
const build = (T3) => {
|
|
@@ -22715,7 +22952,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22715
22952
|
if (w === void 0 || d === void 0 || h === void 0) throw new Error(`game-floorplan-three: furniture type "${type}" is not in the catalogue, so give w, d and h`);
|
|
22716
22953
|
const o = opts.options ?? {};
|
|
22717
22954
|
const seed = Math.round(opts.seed ?? 1);
|
|
22718
|
-
const plain2 =
|
|
22955
|
+
const plain2 = SHELVING.test(type) ? "paper" : "plastic";
|
|
22719
22956
|
const root = { x: seed, z: 0, ry: 0, w, d, h, y: 0, base: 0, palette: o.palette, seed: `furniture_${type}_${seed}` };
|
|
22720
22957
|
const { K, shared } = renderer.internals;
|
|
22721
22958
|
const before = K.PARTS.length;
|
|
@@ -22734,7 +22971,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22734
22971
|
shared.ctx = saved.ctx;
|
|
22735
22972
|
}
|
|
22736
22973
|
},
|
|
22737
|
-
{ materials: { plain: plain2, ...o.materials }, chairs: o.chairs }
|
|
22974
|
+
{ materials: { plain: plain2, ...o.materials }, chairs: o.chairs, carcass: SHELVING.test(type) }
|
|
22738
22975
|
);
|
|
22739
22976
|
const spouts = K.PARTS.slice(before).filter((p) => p.type === "water_tap").map((p) => [p.pos[0] - root.x, p.pos[1], p.pos[2] - root.z]);
|
|
22740
22977
|
K.PARTS.length = before;
|
|
@@ -22801,7 +23038,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22801
23038
|
function draw(THREE, plan, options) {
|
|
22802
23039
|
return create3(THREE, { ...options, fleet: null }).build(plan, { quality: "game", terrain: false, noPerimeter: true, pieces: "meshes" });
|
|
22803
23040
|
}
|
|
23041
|
+
var houses = /* @__PURE__ */ new WeakMap();
|
|
22804
23042
|
function label(house) {
|
|
23043
|
+
houses.set(house.group, house);
|
|
22805
23044
|
for (const [id, items] of Object.entries(house.destruction.ranges())) {
|
|
22806
23045
|
for (const item of items) {
|
|
22807
23046
|
const object2 = item.isObject3D ? item : item.mesh;
|
|
@@ -22814,12 +23053,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22814
23053
|
const plan = wallPlan(options);
|
|
22815
23054
|
const houseOptions = options.house ?? {};
|
|
22816
23055
|
const probe = draw(THREE, plan, { ...houseOptions, destruction: void 0, destructionRenderer: void 0 });
|
|
22817
|
-
const spec = probe.structure.spec(
|
|
23056
|
+
const spec = probe.structure.spec();
|
|
22818
23057
|
probe.dispose();
|
|
22819
23058
|
return {
|
|
22820
23059
|
plan,
|
|
22821
23060
|
spec,
|
|
22822
|
-
build: (T2) => label(draw(T2, plan, houseOptions))
|
|
23061
|
+
build: (T2) => label(draw(T2, plan, houseOptions)),
|
|
23062
|
+
follow: (root, world, objectId) => houses.get(root)?.destruction?.follow?.(world, objectId, spec) ?? null
|
|
22823
23063
|
};
|
|
22824
23064
|
}
|
|
22825
23065
|
return __toCommonJS(index_exports);
|