@adatechnology/game-items-three 0.7.1 → 0.7.3
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.global.js +618 -73
- package/dist/index.global.js.map +1 -1
- package/package.json +8 -8
package/dist/index.global.js
CHANGED
|
@@ -1558,6 +1558,7 @@ var GameItemsThree = (() => {
|
|
|
1558
1558
|
}
|
|
1559
1559
|
|
|
1560
1560
|
// ../game-contracts/dist/index.js
|
|
1561
|
+
var DEFAULT_BLAST_IMPULSE = { bodyArea: 0.7, lift: 0.15, minSpeed: 0.3, tntPerJoule: 0.24 / 2e5 };
|
|
1561
1562
|
var DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024;
|
|
1562
1563
|
var DEFAULT_IGNITION_RULES = {
|
|
1563
1564
|
fillCurve: [
|
|
@@ -2730,6 +2731,19 @@ var GameItemsThree = (() => {
|
|
|
2730
2731
|
"drink",
|
|
2731
2732
|
"sticky"
|
|
2732
2733
|
]
|
|
2734
|
+
},
|
|
2735
|
+
{
|
|
2736
|
+
id: "mud",
|
|
2737
|
+
color: 4008988,
|
|
2738
|
+
opacity: 0.95,
|
|
2739
|
+
stainColor: 3811866,
|
|
2740
|
+
viscosity: 40,
|
|
2741
|
+
density: 1600,
|
|
2742
|
+
dryTime: 900,
|
|
2743
|
+
gloss: 0.4,
|
|
2744
|
+
tags: [
|
|
2745
|
+
"dirty"
|
|
2746
|
+
]
|
|
2733
2747
|
}
|
|
2734
2748
|
];
|
|
2735
2749
|
var LIQUIDS = liquids_default;
|
|
@@ -13253,6 +13267,22 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
13253
13267
|
return angle === 0 ? q : quat.mul(q, quat.fromAxisAngle([0, 0, 1], angle));
|
|
13254
13268
|
};
|
|
13255
13269
|
var clamp = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
13270
|
+
var splitAlong = (box4, count, axis, rnd) => {
|
|
13271
|
+
const shares = Array.from({ length: count }, () => 0.25 + 1.5 * rnd());
|
|
13272
|
+
const total = shares.reduce((sum, share) => sum + share, 0);
|
|
13273
|
+
const out = [];
|
|
13274
|
+
let from = box4.c[axis] - box4.s[axis] / 2;
|
|
13275
|
+
for (const share of shares) {
|
|
13276
|
+
const length = box4.s[axis] * share / total;
|
|
13277
|
+
const c = [box4.c[0], box4.c[1], box4.c[2]];
|
|
13278
|
+
const size = [box4.s[0], box4.s[1], box4.s[2]];
|
|
13279
|
+
c[axis] = from + length / 2;
|
|
13280
|
+
size[axis] = length;
|
|
13281
|
+
out.push({ c, s: size });
|
|
13282
|
+
from += length;
|
|
13283
|
+
}
|
|
13284
|
+
return out;
|
|
13285
|
+
};
|
|
13256
13286
|
var splinterBox = (inp, box4, limit = inp.maxFragments) => {
|
|
13257
13287
|
const { rnd } = inp;
|
|
13258
13288
|
const dims = box4.s;
|
|
@@ -13262,35 +13292,81 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
13262
13292
|
const w = Math.max(fmin * 1.5, 0.01);
|
|
13263
13293
|
const c = clamp(Math.round(dims[a] * dims[b] / (w * w)), 3, Math.max(3, Math.floor(limit / 2)));
|
|
13264
13294
|
const maxLen = fmax * 4;
|
|
13265
|
-
const cells =
|
|
13295
|
+
const cells = [];
|
|
13296
|
+
for (const cell of bsp(box4, c, [a, b], rnd)) {
|
|
13297
|
+
const wide = cell.s[a] >= cell.s[b] ? a : b;
|
|
13298
|
+
if (rnd() < 0.4 && cell.s[wide] > fmin * 0.5) for (const part of splitAlong(cell, 2, wide, rnd)) cells.push(part);
|
|
13299
|
+
else cells.push(cell);
|
|
13300
|
+
}
|
|
13266
13301
|
const pieces = [];
|
|
13267
13302
|
for (const cell of cells) {
|
|
13268
|
-
const extra = rnd()
|
|
13303
|
+
const extra = Math.floor(rnd() * 3);
|
|
13269
13304
|
const k = Math.max(1, Math.ceil(dims[g] / maxLen)) + extra;
|
|
13270
|
-
for (const p of
|
|
13305
|
+
for (const p of splitAlong(cell, k, g, rnd)) pieces.push(p);
|
|
13271
13306
|
}
|
|
13272
13307
|
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] }));
|
|
13273
13308
|
};
|
|
13309
|
+
var PLY = 3e-3;
|
|
13310
|
+
var PLY_GAP = 0.6;
|
|
13311
|
+
var PLY_SHEET = 0.012;
|
|
13312
|
+
var plyBreak = (inp, root, limit) => {
|
|
13313
|
+
const { rnd } = inp;
|
|
13314
|
+
const dims = root.s;
|
|
13315
|
+
const sorted = [0, 1, 2].sort((x, y) => dims[x] - dims[y]);
|
|
13316
|
+
const t = sorted[0];
|
|
13317
|
+
const [u, v] = [sorted[1], sorted[2]].sort((x, y) => x - y);
|
|
13318
|
+
const along = dims[u] >= dims[v] ? u : v;
|
|
13319
|
+
const across2 = along === u ? v : u;
|
|
13320
|
+
const layers = clamp(Math.round(dims[t] / PLY / 2), 2, 3);
|
|
13321
|
+
const pitch = dims[t] / layers;
|
|
13322
|
+
const th = Math.min(pitch, PLY_SHEET);
|
|
13323
|
+
const per = Math.max(2, Math.floor(limit / layers));
|
|
13324
|
+
const out = [];
|
|
13325
|
+
for (let k = 0; k < layers; k++) {
|
|
13326
|
+
const layer = { c: [root.c[0], root.c[1], root.c[2]], s: [dims[0], dims[1], dims[2]] };
|
|
13327
|
+
layer.c[t] = root.c[t] + (-dims[t] / 2 + (k + 0.5) * pitch) * (pitch > PLY_SHEET ? 1 : 1 + PLY_GAP);
|
|
13328
|
+
layer.s[t] = th;
|
|
13329
|
+
for (const cell of bsp(layer, per, [u, v], rnd)) {
|
|
13330
|
+
if (out.length >= limit) return out;
|
|
13331
|
+
if (rnd() < 0.35) {
|
|
13332
|
+
const strand = cell.s[across2] * (0.15 + 0.2 * rnd());
|
|
13333
|
+
out.push({ center: cell.c, size: [cell.s[along], strand, th * 0.7], q: frame(along, across2, t), shape: "splinter", weight: cell.s[along] * strand * th });
|
|
13334
|
+
} else {
|
|
13335
|
+
out.push({ center: cell.c, size: [cell.s[u], cell.s[v], th], q: frame(u, v, t, (rnd() - 0.5) * 0.5), shape: "scrap", weight: cell.s[u] * cell.s[v] * th });
|
|
13336
|
+
}
|
|
13337
|
+
}
|
|
13338
|
+
}
|
|
13339
|
+
return out;
|
|
13340
|
+
};
|
|
13341
|
+
var granules = (inp, box4, count) => bsp(box4, count, [0, 1, 2], inp.rnd).map((b) => ({ center: b.c, size: b.s, q: quat.identity(), shape: "chunk", weight: b.s[0] * b.s[1] * b.s[2] }));
|
|
13342
|
+
var CRUMBS = 6;
|
|
13274
13343
|
var severAt = (inp, root, at2, gap) => {
|
|
13275
13344
|
const dims = root.s;
|
|
13276
13345
|
const L = [0, 1, 2].sort((x, y) => dims[y] - dims[x])[0];
|
|
13277
13346
|
const half = dims[L] / 2;
|
|
13278
13347
|
const lo = clamp(at2 - gap / 2, -half, half), hi = clamp(at2 + gap / 2, -half, half);
|
|
13279
13348
|
const out = [];
|
|
13280
|
-
const
|
|
13349
|
+
const fibrous = inp.form === "slivers" || inp.form === "plies";
|
|
13350
|
+
const [a, b] = [0, 1, 2].filter((i) => i !== L);
|
|
13351
|
+
const stub = (from, to, breakAtEnd) => {
|
|
13281
13352
|
if (to - from < 0.02) return;
|
|
13282
13353
|
const c = [root.c[0], root.c[1], root.c[2]], sz = [dims[0], dims[1], dims[2]];
|
|
13283
13354
|
c[L] = (from + to) / 2;
|
|
13284
13355
|
sz[L] = to - from;
|
|
13285
|
-
|
|
13356
|
+
const weight = sz[0] * sz[1] * sz[2];
|
|
13357
|
+
if (fibrous) out.push({ center: c, size: [sz[L], sz[a], sz[b]], q: frame(L, a, b, breakAtEnd ? 0 : Math.PI), shape: "slab", weight });
|
|
13358
|
+
else out.push({ center: c, size: sz, q: quat.identity(), shape: "slab", weight });
|
|
13286
13359
|
};
|
|
13287
|
-
stub(-half, lo);
|
|
13288
|
-
stub(hi, half);
|
|
13360
|
+
stub(-half, lo, true);
|
|
13361
|
+
stub(hi, half, false);
|
|
13289
13362
|
const band = { c: [root.c[0], root.c[1], root.c[2]], s: [dims[0], dims[1], dims[2]] };
|
|
13290
13363
|
band.c[L] = (lo + hi) / 2;
|
|
13291
13364
|
band.s[L] = Math.max(hi - lo, 0.01);
|
|
13292
|
-
|
|
13293
|
-
|
|
13365
|
+
const room = inp.maxFragments - out.length;
|
|
13366
|
+
if (inp.style === "snap" && inp.form === "plies") for (const p of plyBreak(inp, band, Math.max(3, room))) out.push(p);
|
|
13367
|
+
else if (inp.style === "snap" && inp.form === "granules") for (const p of granules(inp, band, clamp(room, 3, 12))) out.push(p);
|
|
13368
|
+
else if (inp.style === "snap") {
|
|
13369
|
+
for (const b2 of bsp(band, Math.max(3, Math.min(6, room)), [0, 1, 2], inp.rnd)) out.push({ center: b2.c, size: b2.s, q: quat.identity(), shape: "chunk", weight: b2.s[0] * b2.s[1] * b2.s[2] });
|
|
13294
13370
|
} else for (const p of splinterBox(inp, band, Math.max(3, inp.maxFragments - out.length))) out.push(p);
|
|
13295
13371
|
return out;
|
|
13296
13372
|
};
|
|
@@ -13323,8 +13399,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
13323
13399
|
const [u, v] = [sorted[1], sorted[2]].sort((a, b) => a - b);
|
|
13324
13400
|
if (style === "snap") {
|
|
13325
13401
|
if (inp.cut) return severAt(inp, root, inp.cut.at, inp.cut.gap);
|
|
13402
|
+
if (inp.form === "plies") return plyBreak(inp, root, maxFragments);
|
|
13326
13403
|
const n2 = Math.min(maxFragments, 2 + Math.floor(rnd() * 3));
|
|
13327
13404
|
for (const b of bsp(root, n2, [0, 1, 2], rnd)) out.push({ center: b.c, size: b.s, q: idq, shape: "slab", weight: b.s[0] * b.s[1] * b.s[2] });
|
|
13405
|
+
if (inp.form !== "granules") return out;
|
|
13406
|
+
const crumbs = Math.min(CRUMBS, maxFragments - out.length);
|
|
13407
|
+
if (crumbs <= 0) return out;
|
|
13408
|
+
const band = { c: [0, 0, 0], s: [0, 0, 0] };
|
|
13409
|
+
for (let i = 0; i < 3; i++) {
|
|
13410
|
+
band.s[i] = Math.min(dims[i], Math.max(fmin, dims[i] * 0.2));
|
|
13411
|
+
band.c[i] = clamp(inp.hit[i], -dims[i] / 2 + band.s[i] / 2, dims[i] / 2 - band.s[i] / 2);
|
|
13412
|
+
}
|
|
13413
|
+
for (const p of granules(inp, band, crumbs)) out.push({ ...p, weight: p.weight * 0.5 });
|
|
13328
13414
|
return out;
|
|
13329
13415
|
}
|
|
13330
13416
|
if (style === "crumble" || style === "none") {
|
|
@@ -13431,6 +13517,88 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
13431
13517
|
}
|
|
13432
13518
|
return marks;
|
|
13433
13519
|
};
|
|
13520
|
+
var JOINT_GAP = 1e-4;
|
|
13521
|
+
var MIN_BEARING_SHARE = 0.25;
|
|
13522
|
+
var unsupportedCells = (cells, thin, dims, standing) => {
|
|
13523
|
+
if (thin === 1) return [];
|
|
13524
|
+
const [u, v] = planeAxes(thin);
|
|
13525
|
+
const bottom = -dims[v] / 2;
|
|
13526
|
+
const rowOf = (y) => Math.round((y - bottom) * 1e4);
|
|
13527
|
+
const rows = /* @__PURE__ */ new Map();
|
|
13528
|
+
for (let i = 0; i < cells.length; i++) {
|
|
13529
|
+
if (!standing(i)) continue;
|
|
13530
|
+
const cell = cells[i];
|
|
13531
|
+
const key2 = rowOf(cell.center[v] - cell.size[v] / 2);
|
|
13532
|
+
const row = rows.get(key2);
|
|
13533
|
+
if (row) row.push(i);
|
|
13534
|
+
else rows.set(key2, [i]);
|
|
13535
|
+
}
|
|
13536
|
+
const held = /* @__PURE__ */ new Set();
|
|
13537
|
+
const queue = [];
|
|
13538
|
+
for (const i of rows.get(0) ?? []) {
|
|
13539
|
+
held.add(i);
|
|
13540
|
+
queue.push(i);
|
|
13541
|
+
}
|
|
13542
|
+
const overlap = (a, b) => Math.min(a.center[u] + a.size[u] / 2, b.center[u] + b.size[u] / 2) - Math.max(a.center[u] - a.size[u] / 2, b.center[u] - b.size[u] / 2);
|
|
13543
|
+
const climb = () => {
|
|
13544
|
+
while (queue.length > 0) {
|
|
13545
|
+
const cell = cells[queue.pop()];
|
|
13546
|
+
for (const j of rows.get(rowOf(cell.center[v] + cell.size[v] / 2)) ?? []) {
|
|
13547
|
+
const other = cells[j];
|
|
13548
|
+
if (held.has(j) || overlap(cell, other) <= Math.max(JOINT_GAP, MIN_BEARING_SHARE * Math.min(cell.size[u], other.size[u]))) continue;
|
|
13549
|
+
held.add(j);
|
|
13550
|
+
queue.push(j);
|
|
13551
|
+
}
|
|
13552
|
+
}
|
|
13553
|
+
};
|
|
13554
|
+
for (const row of rows.values()) row.sort((a, b) => cells[a].center[u] - cells[b].center[u]);
|
|
13555
|
+
const touching = (a, b) => Math.abs(a.center[u] + a.size[u] / 2 - (b.center[u] - b.size[u] / 2)) <= 1e-3;
|
|
13556
|
+
for (let wedged = true; wedged; ) {
|
|
13557
|
+
climb();
|
|
13558
|
+
wedged = false;
|
|
13559
|
+
for (const row of rows.values()) {
|
|
13560
|
+
for (let k = 1; k < row.length - 1; k++) {
|
|
13561
|
+
const i = row[k];
|
|
13562
|
+
if (held.has(i) || !held.has(row[k - 1]) || !held.has(row[k + 1])) continue;
|
|
13563
|
+
if (!touching(cells[row[k - 1]], cells[i]) || !touching(cells[i], cells[row[k + 1]])) continue;
|
|
13564
|
+
held.add(i);
|
|
13565
|
+
queue.push(i);
|
|
13566
|
+
wedged = true;
|
|
13567
|
+
}
|
|
13568
|
+
}
|
|
13569
|
+
}
|
|
13570
|
+
const loose = [];
|
|
13571
|
+
for (const row of rows.values()) for (const i of row) if (!held.has(i)) loose.push(i);
|
|
13572
|
+
return loose;
|
|
13573
|
+
};
|
|
13574
|
+
var clumpCells = (cells, thin, cap) => {
|
|
13575
|
+
if (cells.length <= cap) return [...cells];
|
|
13576
|
+
const [u, v] = planeAxes(thin);
|
|
13577
|
+
let lo0 = Infinity, lo1 = Infinity, hi0 = -Infinity, hi1 = -Infinity;
|
|
13578
|
+
for (const cell of cells) {
|
|
13579
|
+
lo0 = Math.min(lo0, cell.center[u] - cell.size[u] / 2);
|
|
13580
|
+
hi0 = Math.max(hi0, cell.center[u] + cell.size[u] / 2);
|
|
13581
|
+
lo1 = Math.min(lo1, cell.center[v] - cell.size[v] / 2);
|
|
13582
|
+
hi1 = Math.max(hi1, cell.center[v] + cell.size[v] / 2);
|
|
13583
|
+
}
|
|
13584
|
+
let side = Math.sqrt((hi0 - lo0) * (hi1 - lo1) / cap);
|
|
13585
|
+
for (; ; ) {
|
|
13586
|
+
const bins = /* @__PURE__ */ new Map();
|
|
13587
|
+
for (const cell of cells) {
|
|
13588
|
+
const key2 = `${Math.floor((cell.center[u] - lo0) / side)}:${Math.floor((cell.center[v] - lo1) / side)}`;
|
|
13589
|
+
const bin = bins.get(key2) ?? { lo: [Infinity, Infinity, Infinity], hi: [-Infinity, -Infinity, -Infinity] };
|
|
13590
|
+
for (let k = 0; k < 3; k++) {
|
|
13591
|
+
bin.lo[k] = Math.min(bin.lo[k], cell.center[k] - cell.size[k] / 2);
|
|
13592
|
+
bin.hi[k] = Math.max(bin.hi[k], cell.center[k] + cell.size[k] / 2);
|
|
13593
|
+
}
|
|
13594
|
+
bins.set(key2, bin);
|
|
13595
|
+
}
|
|
13596
|
+
if (bins.size <= cap) {
|
|
13597
|
+
return [...bins.values()].map(({ lo, hi }) => ({ center: [(lo[0] + hi[0]) / 2, (lo[1] + hi[1]) / 2, (lo[2] + hi[2]) / 2], size: [hi[0] - lo[0], hi[1] - lo[1], hi[2] - lo[2]] }));
|
|
13598
|
+
}
|
|
13599
|
+
side *= 1.25;
|
|
13600
|
+
}
|
|
13601
|
+
};
|
|
13434
13602
|
var MAX_SPALLS = 64;
|
|
13435
13603
|
var thinAxisOf = (dims) => dims[0] <= dims[1] && dims[0] <= dims[2] ? 0 : dims[1] <= dims[2] ? 1 : 2;
|
|
13436
13604
|
var resolveLayer = (def, index, mat) => ({ index, def, mat, energy: mat.penetration * def.thickness * 1e3 });
|
|
@@ -14410,6 +14578,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14410
14578
|
},
|
|
14411
14579
|
{
|
|
14412
14580
|
id: "wood_soft",
|
|
14581
|
+
splitForm: "slivers",
|
|
14413
14582
|
density: 500,
|
|
14414
14583
|
hpPerKg: 90,
|
|
14415
14584
|
penetration: 9,
|
|
@@ -14455,6 +14624,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14455
14624
|
},
|
|
14456
14625
|
{
|
|
14457
14626
|
id: "wood_hard",
|
|
14627
|
+
splitForm: "slivers",
|
|
14458
14628
|
density: 750,
|
|
14459
14629
|
hpPerKg: 140,
|
|
14460
14630
|
penetration: 14,
|
|
@@ -14499,6 +14669,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14499
14669
|
},
|
|
14500
14670
|
{
|
|
14501
14671
|
id: "plywood",
|
|
14672
|
+
splitForm: "plies",
|
|
14502
14673
|
density: 600,
|
|
14503
14674
|
hpPerKg: 70,
|
|
14504
14675
|
penetration: 7,
|
|
@@ -14546,6 +14717,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
14546
14717
|
},
|
|
14547
14718
|
{
|
|
14548
14719
|
id: "mdf",
|
|
14720
|
+
splitForm: "granules",
|
|
14549
14721
|
density: 750,
|
|
14550
14722
|
hpPerKg: 45,
|
|
14551
14723
|
penetration: 6,
|
|
@@ -15057,6 +15229,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15057
15229
|
},
|
|
15058
15230
|
{
|
|
15059
15231
|
id: "green_wood",
|
|
15232
|
+
splitForm: "slivers",
|
|
15060
15233
|
density: 650,
|
|
15061
15234
|
hpPerKg: 5,
|
|
15062
15235
|
penetration: 10,
|
|
@@ -15337,6 +15510,125 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15337
15510
|
"brittle"
|
|
15338
15511
|
],
|
|
15339
15512
|
compressive: 1e5
|
|
15513
|
+
},
|
|
15514
|
+
{
|
|
15515
|
+
id: "mud",
|
|
15516
|
+
density: 1700,
|
|
15517
|
+
hpPerKg: 1,
|
|
15518
|
+
penetration: 5,
|
|
15519
|
+
ductility: 0.8,
|
|
15520
|
+
fracture: "crumble",
|
|
15521
|
+
fragmentSize: [
|
|
15522
|
+
0.02,
|
|
15523
|
+
0.08
|
|
15524
|
+
],
|
|
15525
|
+
hitDebris: "dust",
|
|
15526
|
+
breakDebris: "dust",
|
|
15527
|
+
thermal: {
|
|
15528
|
+
conductivity: 0.5,
|
|
15529
|
+
heatCapacity: 3.2
|
|
15530
|
+
},
|
|
15531
|
+
tags: [
|
|
15532
|
+
"soil",
|
|
15533
|
+
"wet"
|
|
15534
|
+
],
|
|
15535
|
+
compressive: 5e3
|
|
15536
|
+
},
|
|
15537
|
+
{
|
|
15538
|
+
id: "clay",
|
|
15539
|
+
density: 1800,
|
|
15540
|
+
hpPerKg: 5,
|
|
15541
|
+
penetration: 7,
|
|
15542
|
+
ductility: 0.05,
|
|
15543
|
+
fracture: "crumble",
|
|
15544
|
+
fragmentSize: [
|
|
15545
|
+
0.02,
|
|
15546
|
+
0.1
|
|
15547
|
+
],
|
|
15548
|
+
hitDebris: "chips",
|
|
15549
|
+
breakDebris: "dust",
|
|
15550
|
+
thermal: {
|
|
15551
|
+
conductivity: 0.15,
|
|
15552
|
+
heatCapacity: 2.2
|
|
15553
|
+
},
|
|
15554
|
+
tags: [
|
|
15555
|
+
"soil",
|
|
15556
|
+
"brittle"
|
|
15557
|
+
],
|
|
15558
|
+
compressive: 6e4
|
|
15559
|
+
},
|
|
15560
|
+
{
|
|
15561
|
+
id: "snow",
|
|
15562
|
+
density: 300,
|
|
15563
|
+
hpPerKg: 1,
|
|
15564
|
+
penetration: 3,
|
|
15565
|
+
ductility: 0.6,
|
|
15566
|
+
fracture: "crumble",
|
|
15567
|
+
fragmentSize: [
|
|
15568
|
+
0.01,
|
|
15569
|
+
0.05
|
|
15570
|
+
],
|
|
15571
|
+
hitDebris: "dust",
|
|
15572
|
+
breakDebris: "dust",
|
|
15573
|
+
thermal: {
|
|
15574
|
+
conductivity: 0.1,
|
|
15575
|
+
heatCapacity: 2.1
|
|
15576
|
+
},
|
|
15577
|
+
tags: [
|
|
15578
|
+
"soil",
|
|
15579
|
+
"frozen"
|
|
15580
|
+
],
|
|
15581
|
+
compressive: 1e3
|
|
15582
|
+
},
|
|
15583
|
+
{
|
|
15584
|
+
id: "cobble",
|
|
15585
|
+
density: 2650,
|
|
15586
|
+
hpPerKg: 25,
|
|
15587
|
+
penetration: 25,
|
|
15588
|
+
penetrationClass: "concrete",
|
|
15589
|
+
penetrationScale: 0.9,
|
|
15590
|
+
ductility: 0.03,
|
|
15591
|
+
fracture: "crumble",
|
|
15592
|
+
fragmentSize: [
|
|
15593
|
+
0.05,
|
|
15594
|
+
0.15
|
|
15595
|
+
],
|
|
15596
|
+
hitDebris: "chips",
|
|
15597
|
+
breakDebris: "chips",
|
|
15598
|
+
thermal: {
|
|
15599
|
+
conductivity: 0.2,
|
|
15600
|
+
heatCapacity: 2.5
|
|
15601
|
+
},
|
|
15602
|
+
tags: [
|
|
15603
|
+
"masonry",
|
|
15604
|
+
"brittle"
|
|
15605
|
+
],
|
|
15606
|
+
compressive: 3e5
|
|
15607
|
+
},
|
|
15608
|
+
{
|
|
15609
|
+
id: "paver",
|
|
15610
|
+
density: 2300,
|
|
15611
|
+
hpPerKg: 14,
|
|
15612
|
+
penetration: 18,
|
|
15613
|
+
penetrationClass: "concrete",
|
|
15614
|
+
penetrationScale: 1,
|
|
15615
|
+
ductility: 0.03,
|
|
15616
|
+
fracture: "crumble",
|
|
15617
|
+
fragmentSize: [
|
|
15618
|
+
0.04,
|
|
15619
|
+
0.12
|
|
15620
|
+
],
|
|
15621
|
+
hitDebris: "chips",
|
|
15622
|
+
breakDebris: "chips",
|
|
15623
|
+
thermal: {
|
|
15624
|
+
conductivity: 0.15,
|
|
15625
|
+
heatCapacity: 2.5
|
|
15626
|
+
},
|
|
15627
|
+
tags: [
|
|
15628
|
+
"masonry",
|
|
15629
|
+
"brittle"
|
|
15630
|
+
],
|
|
15631
|
+
compressive: 35e4
|
|
15340
15632
|
}
|
|
15341
15633
|
];
|
|
15342
15634
|
var material_hints_default = {
|
|
@@ -15549,6 +15841,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
15549
15841
|
var BREACH_BLAST_FACTOR = 6;
|
|
15550
15842
|
var BREACH_AREA = 0.25;
|
|
15551
15843
|
var BREACH_BLAST_REACH = 0.12;
|
|
15844
|
+
var MEMBER_CUT_REACH = 0.5;
|
|
15845
|
+
var BLAST_REFERENCE_RESISTANCE = 200 * 1900 * 0.13;
|
|
15846
|
+
var BLAST_EDGE_RAGGED = 0.3;
|
|
15847
|
+
var BLAST_EDGE_LOOSE = 1.35;
|
|
15848
|
+
var BLAST_EDGE_WEAR = 0.6;
|
|
15552
15849
|
var RESIDUAL_CAPACITY = 0.15;
|
|
15553
15850
|
var SEVER_BAND = 0.1;
|
|
15554
15851
|
var SEVER_ASPECT = 3;
|
|
@@ -16801,7 +17098,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16801
17098
|
if (j.st.open) continue;
|
|
16802
17099
|
if (j.spec.kind === "rebar" && (isReinforced(o.parts[j.ia].spec) || isReinforced(o.parts[j.ib].spec))) continue;
|
|
16803
17100
|
if (near && jointReach(o, j, near) > Math.max(radius, jointReachLimit(o, j))) continue;
|
|
16804
|
-
j.st.hp -= span === void 0 ? amount : amount * Math.min(1, span / Math.max(jointLength(o, j), 1e-6));
|
|
17101
|
+
j.st.hp -= span === void 0 ? amount : Math.min(amount, j.st.maxHp) * Math.min(1, span / Math.max(jointLength(o, j), 1e-6));
|
|
16805
17102
|
if (j.st.hp <= 0) {
|
|
16806
17103
|
j.st.hp = 0;
|
|
16807
17104
|
j.st.open = true;
|
|
@@ -16929,6 +17226,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16929
17226
|
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
16930
17227
|
const cut = (_b = p.rt).craters ?? (_b.craters = {});
|
|
16931
17228
|
const out = [];
|
|
17229
|
+
const wholeBefore = Object.values(worn).filter((w) => w === -1).length;
|
|
16932
17230
|
const shot = kind === "ballistic";
|
|
16933
17231
|
for (let i = 0; i < grid.length; i++) {
|
|
16934
17232
|
const cell = grid[i];
|
|
@@ -16987,6 +17285,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
16987
17285
|
emit({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [cell.size[0], cell.size[1], cell.size[2]], rotation: q, fragments });
|
|
16988
17286
|
debris(o, p, p.mat.breakDebris, center, vec.scale(dir ?? [0, 1, 0], -1), 6, 2, src);
|
|
16989
17287
|
}
|
|
17288
|
+
if (Object.values(worn).filter((w) => w === -1).length > wholeBefore) dropUnsupported(o, p, src);
|
|
16990
17289
|
if (p.spec.reinforcement) exposeRebar(o, p, src);
|
|
16991
17290
|
for (const cell of out) addBreach(o, p, toWorld(c, q, cell.center), cell.size[u] * cell.size[v], energy, dir, src);
|
|
16992
17291
|
if (p.structural && !isLost(p)) {
|
|
@@ -17090,10 +17389,122 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17090
17389
|
setStage(o, p, 1, {}, src);
|
|
17091
17390
|
setStage(o, p, 2, { opening: { center: worldCenter, radius }, fragments }, src);
|
|
17092
17391
|
debris(o, p, p.mat.breakDebris, worldCenter, vec.scale(dir ?? [0, 1, 0], -1), 14, 3, src);
|
|
17392
|
+
dropUnsupported(o, p, src);
|
|
17093
17393
|
const reinforcement = p.spec.reinforcement;
|
|
17094
17394
|
if (reinforcement) exposeRebar(o, p, src);
|
|
17095
17395
|
if (p.structural) solveStructure(o);
|
|
17096
17396
|
};
|
|
17397
|
+
const blastReachOf = (p, energy) => {
|
|
17398
|
+
const perKg = p.mat.hits?.blunt?.unitJoules ?? chipEnergy;
|
|
17399
|
+
const resistance = Math.max(1, perKg * p.mat.density * p.thickness);
|
|
17400
|
+
return BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3) * clamp2(Math.cbrt(BLAST_REFERENCE_RESISTANCE / resistance), 0.3, 2);
|
|
17401
|
+
};
|
|
17402
|
+
const blastUnits = (o, p, wp, energy, dist, src) => {
|
|
17403
|
+
var _a, _b;
|
|
17404
|
+
if (!p.staged || p.st.stripped || isLost(p) || chipEnergy <= 0) return false;
|
|
17405
|
+
const reach = blastReachOf(p, energy);
|
|
17406
|
+
if (dist >= reach) return false;
|
|
17407
|
+
const radius = Math.sqrt(reach * reach - dist * dist);
|
|
17408
|
+
const [u, v] = planeAxes(p.thin);
|
|
17409
|
+
const lp = toLocal(p.pos, p.q, objLocal(o, wp));
|
|
17410
|
+
const op = p.st.opening ? toLocal(p.pos, p.q, p.st.opening.center) : null;
|
|
17411
|
+
const grid = gridOf(p);
|
|
17412
|
+
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
17413
|
+
const perKg = p.mat.hits?.blunt?.unitJoules ?? chipEnergy;
|
|
17414
|
+
const lobes = [rnd() * 2 * Math.PI, rnd() * 2 * Math.PI];
|
|
17415
|
+
const out = [];
|
|
17416
|
+
for (let i = 0; i < grid.length; i++) {
|
|
17417
|
+
const cell = grid[i];
|
|
17418
|
+
if (worn[i] === -1) continue;
|
|
17419
|
+
if (op && p.st.opening && Math.hypot(cell.center[u] - op[u], cell.center[v] - op[v]) <= p.st.opening.radius) continue;
|
|
17420
|
+
const du = cell.center[u] - lp[u], dv = cell.center[v] - lp[v];
|
|
17421
|
+
const angle = Math.atan2(dv, du);
|
|
17422
|
+
const edge = radius * (1 + BLAST_EDGE_RAGGED * (0.5 * Math.sin(3 * angle + lobes[0]) + 0.3 * Math.sin(5 * angle + lobes[1]) + 0.4 * (rnd() - 0.5)));
|
|
17423
|
+
const d = Math.hypot(du, dv);
|
|
17424
|
+
if (d <= edge) {
|
|
17425
|
+
worn[i] = -1;
|
|
17426
|
+
out.push(i);
|
|
17427
|
+
} else if (d <= edge * BLAST_EDGE_LOOSE) {
|
|
17428
|
+
const mass = p.mat.density * cell.size[0] * cell.size[1] * cell.size[2];
|
|
17429
|
+
worn[i] = Math.max(worn[i] ?? 0, perKg * mass * BLAST_EDGE_WEAR);
|
|
17430
|
+
}
|
|
17431
|
+
}
|
|
17432
|
+
if (out.length === 0) return false;
|
|
17433
|
+
const loose = unsupportedCells(grid, p.thin, p.dims, (i) => worn[i] !== -1 && !(op && p.st.opening && Math.hypot(grid[i].center[u] - op[u], grid[i].center[v] - op[v]) <= p.st.opening.radius));
|
|
17434
|
+
for (const i of loose) worn[i] = -1;
|
|
17435
|
+
const blown = out.map((i) => grid[i]), fallen = loose.map((i) => grid[i]);
|
|
17436
|
+
const volume = (cells2) => cells2.reduce((sum, cell) => sum + cell.size[0] * cell.size[1] * cell.size[2], 0);
|
|
17437
|
+
const blownMass = Math.min(p.st.mass, p.mat.density * volume(blown));
|
|
17438
|
+
const fallenMass = Math.min(p.st.mass - blownMass, p.mat.density * volume(fallen));
|
|
17439
|
+
const speed = clamp2(Math.sqrt(2 * energy * 0.02 / Math.max(blownMass, 0.05)), 1, 12);
|
|
17440
|
+
const { c, q } = partXf(o, p);
|
|
17441
|
+
const chipped = (_b = p.st).chipped ?? (_b.chipped = []);
|
|
17442
|
+
const tag = `x${chipped.length}_`;
|
|
17443
|
+
const fragments = [
|
|
17444
|
+
...cellFragments(o, p, clumpCells(blown, p.thin, maxFragments), wp, null, speed, blownMass, tag, true),
|
|
17445
|
+
...fallen.length > 0 ? cellFragments(o, p, clumpCells(fallen, p.thin, Math.max(2, Math.round(maxFragments / 4))), wp, null, 0.3, fallenMass, `${tag}f`, true) : []
|
|
17446
|
+
];
|
|
17447
|
+
const cells = [...blown, ...fallen];
|
|
17448
|
+
const holes = localHolesOf(p);
|
|
17449
|
+
p.st.holes = p.st.holes.filter((_, k) => !cells.some((cell) => marksInBox(cell.center, cell.size, void 0, [holes[k]]).length > 0));
|
|
17450
|
+
const lo = [Infinity, Infinity, Infinity], hi = [-Infinity, -Infinity, -Infinity];
|
|
17451
|
+
for (const cell of cells) {
|
|
17452
|
+
chipped.push({ center: [cell.center[0], cell.center[1], cell.center[2]], size: [cell.size[0], cell.size[1], cell.size[2]] });
|
|
17453
|
+
for (let k = 0; k < 3; k++) {
|
|
17454
|
+
lo[k] = Math.min(lo[k], cell.center[k] - cell.size[k] / 2);
|
|
17455
|
+
hi[k] = Math.max(hi[k], cell.center[k] + cell.size[k] / 2);
|
|
17456
|
+
}
|
|
17457
|
+
}
|
|
17458
|
+
p.st.mass = Math.max(0, p.st.mass - blownMass - fallenMass);
|
|
17459
|
+
p.rt.removed = (p.rt.removed ?? 0) + blownMass + fallenMass;
|
|
17460
|
+
markDamaged(p);
|
|
17461
|
+
setStage(o, p, 1, {}, src);
|
|
17462
|
+
const center = toWorld(c, q, [(lo[0] + hi[0]) / 2, (lo[1] + hi[1]) / 2, (lo[2] + hi[2]) / 2]);
|
|
17463
|
+
const units = cells.map((cell) => ({ center: toWorld(c, q, cell.center), size: [cell.size[0], cell.size[1], cell.size[2]] }));
|
|
17464
|
+
emit({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [hi[0] - lo[0], hi[1] - lo[1], hi[2] - lo[2]], rotation: q, fragments, units });
|
|
17465
|
+
debris(o, p, p.mat.breakDebris, center, vec.normalize(vec.sub(center, wp), [0, 1, 0]), 14, 3, src);
|
|
17466
|
+
if (p.spec.reinforcement) exposeRebar(o, p, src);
|
|
17467
|
+
if (p.structural && !isLost(p)) {
|
|
17468
|
+
solveStructure(o);
|
|
17469
|
+
collapseCheck(o, src);
|
|
17470
|
+
}
|
|
17471
|
+
return true;
|
|
17472
|
+
};
|
|
17473
|
+
const dropUnsupported = (o, p, src) => {
|
|
17474
|
+
var _a, _b;
|
|
17475
|
+
if (!p.spec.units || p.spec.units.mortar === p.spec.material || p.st.stripped || isLost(p)) return 0;
|
|
17476
|
+
const [u, v] = planeAxes(p.thin);
|
|
17477
|
+
const grid = gridOf(p);
|
|
17478
|
+
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
17479
|
+
const op = p.st.opening ? toLocal(p.pos, p.q, p.st.opening.center) : null;
|
|
17480
|
+
const opened = (cell) => !!op && !!p.st.opening && Math.hypot(cell.center[u] - op[u], cell.center[v] - op[v]) <= p.st.opening.radius;
|
|
17481
|
+
const loose = unsupportedCells(grid, p.thin, p.dims, (i) => worn[i] !== -1 && !opened(grid[i]));
|
|
17482
|
+
if (loose.length === 0) return 0;
|
|
17483
|
+
for (const i of loose) worn[i] = -1;
|
|
17484
|
+
const fallen = loose.map((i) => grid[i]);
|
|
17485
|
+
const mass = Math.min(p.st.mass, p.mat.density * fallen.reduce((sum, cell) => sum + cell.size[0] * cell.size[1] * cell.size[2], 0));
|
|
17486
|
+
const { c, q } = partXf(o, p);
|
|
17487
|
+
const chipped = (_b = p.st).chipped ?? (_b.chipped = []);
|
|
17488
|
+
const lo = [Infinity, Infinity, Infinity], hi = [-Infinity, -Infinity, -Infinity];
|
|
17489
|
+
for (const cell of fallen) {
|
|
17490
|
+
for (let k = 0; k < 3; k++) {
|
|
17491
|
+
lo[k] = Math.min(lo[k], cell.center[k] - cell.size[k] / 2);
|
|
17492
|
+
hi[k] = Math.max(hi[k], cell.center[k] + cell.size[k] / 2);
|
|
17493
|
+
}
|
|
17494
|
+
}
|
|
17495
|
+
const center = toWorld(c, q, [(lo[0] + hi[0]) / 2, (lo[1] + hi[1]) / 2, (lo[2] + hi[2]) / 2]);
|
|
17496
|
+
const fragments = cellFragments(o, p, clumpCells(fallen, p.thin, Math.max(2, Math.round(maxFragments / 4))), vec.add(center, [0, 1, 0]), null, 0.3, mass, `u${chipped.length}_`, true);
|
|
17497
|
+
const holes = localHolesOf(p);
|
|
17498
|
+
p.st.holes = p.st.holes.filter((_, k) => !fallen.some((cell) => marksInBox(cell.center, cell.size, void 0, [holes[k]]).length > 0));
|
|
17499
|
+
for (const cell of fallen) chipped.push({ center: [cell.center[0], cell.center[1], cell.center[2]], size: [cell.size[0], cell.size[1], cell.size[2]] });
|
|
17500
|
+
p.st.mass = Math.max(0, p.st.mass - mass);
|
|
17501
|
+
p.rt.removed = (p.rt.removed ?? 0) + mass;
|
|
17502
|
+
markDamaged(p);
|
|
17503
|
+
const units = fallen.map((cell) => ({ center: toWorld(c, q, cell.center), size: [cell.size[0], cell.size[1], cell.size[2]] }));
|
|
17504
|
+
emit({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [hi[0] - lo[0], hi[1] - lo[1], hi[2] - lo[2]], rotation: q, fragments, units });
|
|
17505
|
+
debris(o, p, p.mat.breakDebris, center, [0, -1, 0], 6, 1, src);
|
|
17506
|
+
return loose.length;
|
|
17507
|
+
};
|
|
17097
17508
|
const stripPart = (o, p, reinforcement, src) => {
|
|
17098
17509
|
const bars = rebarBars(p.dims, p.thin, reinforcement.spacing);
|
|
17099
17510
|
p.st.stripped = true;
|
|
@@ -17160,6 +17571,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17160
17571
|
const unitPlan = p.spec.units ? unitFragmentPlan(p, maxFragments * UNIT_FRAGMENT_FACTOR) : [];
|
|
17161
17572
|
const axis = style === "splinter" || style === "snap" ? severAxis(p) : -1;
|
|
17162
17573
|
const cutAt2 = axis < 0 ? void 0 : p.rt.cutAt ?? (origin ? hitLocal[axis] : void 0);
|
|
17574
|
+
const planRnd = p.mat.splitForm ? splitStream(o.id, p.spec.id, hitLocal) : rnd;
|
|
17163
17575
|
const plan = unitPlan.length > 0 ? unitPlan : planFragments({
|
|
17164
17576
|
style,
|
|
17165
17577
|
dims: p.dims,
|
|
@@ -17168,8 +17580,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17168
17580
|
hit: hitLocal,
|
|
17169
17581
|
fragmentSize: p.mat.fragmentSize ?? [0.04, 0.2],
|
|
17170
17582
|
maxFragments,
|
|
17171
|
-
rnd,
|
|
17583
|
+
rnd: planRnd,
|
|
17172
17584
|
sheet: p.mat.sheet,
|
|
17585
|
+
...p.mat.splitForm ? { form: p.mat.splitForm } : {},
|
|
17173
17586
|
...cutAt2 !== void 0 ? { cut: { at: cutAt2, gap: SEVER_BAND } } : {}
|
|
17174
17587
|
});
|
|
17175
17588
|
const holes = p.st.holes.length > 0 ? localHolesOf(p) : [];
|
|
@@ -17214,7 +17627,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17214
17627
|
return;
|
|
17215
17628
|
}
|
|
17216
17629
|
if (ex) {
|
|
17217
|
-
emit({ ...base(o, src), type: "explode", part: p.spec.id, point: c, energy: ex.energy, radius: ex.radius, ...ex.lethalRadius !== void 0 ? { lethalRadius: ex.lethalRadius } : {}, ...ex.effect !== void 0 ? { effect: ex.effect } : {} });
|
|
17630
|
+
emit({ ...base(o, src), type: "explode", part: p.spec.id, point: c, energy: ex.energy, radius: ex.radius, ...ex.lethalRadius !== void 0 ? { lethalRadius: ex.lethalRadius } : {}, ...ex.tnt !== void 0 ? { tnt: ex.tnt } : {}, ...ex.effect !== void 0 ? { effect: ex.effect } : {} });
|
|
17218
17631
|
blasts.push({ point: c, energy: ex.energy, radius: ex.radius, ...ex.lethalRadius !== void 0 ? { lethalRadius: ex.lethalRadius } : {}, source: src });
|
|
17219
17632
|
}
|
|
17220
17633
|
partLost(o, p, src);
|
|
@@ -17308,7 +17721,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17308
17721
|
const fragments = [];
|
|
17309
17722
|
for (let i = 0; i < n; i++) {
|
|
17310
17723
|
const back = !exit || i % 3 === 2;
|
|
17311
|
-
const
|
|
17724
|
+
const plies = p.mat.splitForm === "plies";
|
|
17725
|
+
const len = scale * (fibre ? 1.2 + 1.2 * rnd() : 3 + 4 * rnd()), w = scale * (0.8 + 0.8 * rnd()), t = scale * (fibre ? 0.7 + 0.6 * rnd() : plies ? 0.15 + 0.15 * rnd() : 0.4 + 0.4 * rnd());
|
|
17312
17726
|
const size = [w, w, w];
|
|
17313
17727
|
size[along] = len;
|
|
17314
17728
|
size[(along + 1) % 3] = w;
|
|
@@ -17469,7 +17883,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17469
17883
|
checkIgnite(o, p, src);
|
|
17470
17884
|
}
|
|
17471
17885
|
}
|
|
17472
|
-
wearJoints(o, p, Ein * 0.5, void 0, 0, src);
|
|
17886
|
+
wearJoints(o, p, Ein * 0.5, void 0, 0, src, false, 2 * BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3));
|
|
17473
17887
|
const amount = Ein * DMG_PER_J * (mat.damageScale?.explosive ?? 1);
|
|
17474
17888
|
if (blastFrontSpeed > 0 && dist > 0 && mat.tags?.includes("glass")) {
|
|
17475
17889
|
frontQueue.push({ o, p, due: time + dist / blastFrontSpeed, amount, fragEnergy: Ein * 0.3, point, ...src !== void 0 ? { src } : {} });
|
|
@@ -17479,7 +17893,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17479
17893
|
const dealt = applyDamage(o, p, amount, "explosive", point, null, Ein * 0.3, 40, src);
|
|
17480
17894
|
res.damage += dealt;
|
|
17481
17895
|
if (p.bend && flexure.enabled) bendByBlast(o, p, point, energy, radius, reach, src);
|
|
17482
|
-
|
|
17896
|
+
const breachReach = BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3);
|
|
17897
|
+
if (p.spec.units && p.spec.units.mortar !== p.spec.material) blastUnits(o, p, wp, energy, dist, src);
|
|
17898
|
+
else if (p.spec.reinforcement && p.spec.units && dist > MEMBER_CUT_REACH * breachReach) blastUnits(o, p, wp, energy, dist, src);
|
|
17899
|
+
else if (dist <= breachReach) addBreach(o, p, wp, breachAreaOf(p, dealt, true), Ein, null, src);
|
|
17483
17900
|
return reach;
|
|
17484
17901
|
};
|
|
17485
17902
|
const blastProbe = { partsTested: 0, partsNear: 0 };
|
|
@@ -17725,6 +18142,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
17725
18142
|
}
|
|
17726
18143
|
return h | 0;
|
|
17727
18144
|
};
|
|
18145
|
+
const splitStream = (objectId, partId, hit) => {
|
|
18146
|
+
const codes = Array.from(`${objectId}|${partId}`, (char) => char.charCodeAt(0) / 1e3);
|
|
18147
|
+
const stream = createRng(seedOf2(rng3.state() / 1e3, ...codes, hit[0], hit[1], hit[2]));
|
|
18148
|
+
return () => stream.next();
|
|
18149
|
+
};
|
|
17728
18150
|
const throwFragment = (frag, objectId, from, g, centre, index, src, shields, results, reports, mult) => {
|
|
17729
18151
|
const v = frag.velocity;
|
|
17730
18152
|
const speed = Math.hypot(v[0], v[1], v[2]);
|
|
@@ -19020,7 +19442,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19020
19442
|
var DEFAULT_DENSITY = 500;
|
|
19021
19443
|
var densityOf = (material) => DENSITY[material] ?? DEFAULT_DENSITY;
|
|
19022
19444
|
var OPEN_ROOM_TYPES = ["balcony", "terrace", "porch"];
|
|
19445
|
+
var WALL_PILLAR_SIDE = 0.2;
|
|
19446
|
+
var HALF = WALL_PILLAR_SIDE / 2;
|
|
19023
19447
|
var CLOSED_ONLY = [...OPEN_ROOM_TYPES, "void"];
|
|
19448
|
+
var HALF_PILLAR = WALL_PILLAR_SIDE / 2;
|
|
19024
19449
|
var entry = (itemId, min, max, group, pickable, weight) => ({ itemId, min, max, group, pickable, weight });
|
|
19025
19450
|
var FRIDGE = [
|
|
19026
19451
|
entry("water_bottle", 1, 3, "water", true, 3),
|
|
@@ -19755,6 +20180,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19755
20180
|
}
|
|
19756
20181
|
var LINTEL_DEPTH2 = 0.2;
|
|
19757
20182
|
var LINTEL_BEARING2 = 0.2;
|
|
20183
|
+
var SILL_BEAM_DEPTH = 0.1;
|
|
20184
|
+
var LINTEL_SPAN_RATIO = 10;
|
|
19758
20185
|
var MIN_PIECE = 0.05;
|
|
19759
20186
|
var frameOf = (wall) => {
|
|
19760
20187
|
const alongU = wall.aabb[2] - wall.aabb[0] >= wall.aabb[3] - wall.aabb[1];
|
|
@@ -19768,6 +20195,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19768
20195
|
const drafts = [];
|
|
19769
20196
|
const piers = [];
|
|
19770
20197
|
const lintels = [];
|
|
20198
|
+
const sillBeams = [];
|
|
19771
20199
|
const spandrels = [];
|
|
19772
20200
|
const height = wall.y1 - wall.y0;
|
|
19773
20201
|
let cursor = frame2.from;
|
|
@@ -19778,23 +20206,26 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19778
20206
|
};
|
|
19779
20207
|
own.forEach((opening2, k) => {
|
|
19780
20208
|
addPier(Math.max(cursor, opening2.from));
|
|
19781
|
-
const
|
|
20209
|
+
const span = opening2.to - opening2.from;
|
|
20210
|
+
const lintelTop = Math.min(wall.y1, opening2.y1 + Math.max(LINTEL_DEPTH2, style.lintelDepth?.(span) ?? 0, (span + LINTEL_BEARING2) / LINTEL_SPAN_RATIO));
|
|
19782
20211
|
const lintelFrom = Math.max(frame2.from, opening2.from - LINTEL_BEARING2);
|
|
19783
20212
|
const lintelTo = Math.min(frame2.to, opening2.to + LINTEL_BEARING2);
|
|
19784
20213
|
const lintelHeight = lintelTop - opening2.y1;
|
|
19785
|
-
|
|
20214
|
+
const sillTop = style.sillBeam && opening2.y0 - wall.y0 > SILL_BEAM_DEPTH + MIN_PIECE ? opening2.y0 - SILL_BEAM_DEPTH : opening2.y0;
|
|
20215
|
+
if (sillTop - wall.y0 > MIN_PIECE) drafts.push({ id: `${wall.id}_sill_${k}`, role: "partition", material: wall.material, from: opening2.from, to: opening2.to, y0: wall.y0, y1: sillTop, volume: (opening2.to - opening2.from) * (sillTop - wall.y0) });
|
|
20216
|
+
if (sillTop < opening2.y0) sillBeams.push({ id: `${wall.id}_sillbeam_${k}`, role: "beam", material: style.lintelMaterial, from: lintelFrom, to: lintelTo, y0: sillTop, y1: opening2.y0, volume: (lintelTo - lintelFrom) * SILL_BEAM_DEPTH });
|
|
19786
20217
|
lintels.push({ id: `${wall.id}_lintel_${k}`, role: "beam", material: style.lintelMaterial, from: lintelFrom, to: lintelTo, y0: opening2.y1, y1: lintelTop, volume: (lintelTo - lintelFrom) * lintelHeight });
|
|
19787
20218
|
spandrels.push(wall.y1 - lintelTop > MIN_PIECE ? { id: `${wall.id}_spandrel_${k}`, role: roleOf2, material: wall.material, from: opening2.from, to: opening2.to, y0: lintelTop, y1: wall.y1, volume: (opening2.to - opening2.from) * (wall.y1 - lintelTop) } : void 0);
|
|
19788
20219
|
cursor = opening2.to;
|
|
19789
20220
|
});
|
|
19790
20221
|
addPier(frame2.to);
|
|
19791
20222
|
for (const pier of piers) {
|
|
19792
|
-
for (const lintel of lintels) {
|
|
20223
|
+
for (const lintel of [...lintels, ...sillBeams]) {
|
|
19793
20224
|
const overlap = Math.max(0, Math.min(pier.to, lintel.to) - Math.max(pier.from, lintel.from));
|
|
19794
20225
|
pier.volume -= overlap * (lintel.y1 - lintel.y0);
|
|
19795
20226
|
}
|
|
19796
20227
|
}
|
|
19797
|
-
const all = [...piers, ...drafts, ...lintels, ...spandrels.filter((d) => d !== void 0)];
|
|
20228
|
+
const all = [...piers, ...drafts, ...sillBeams, ...lintels, ...spandrels.filter((d) => d !== void 0)];
|
|
19798
20229
|
const total = all.reduce((sum, d) => sum + d.volume, 0);
|
|
19799
20230
|
const pieces = all.map((d) => ({
|
|
19800
20231
|
id: d.id,
|
|
@@ -19809,6 +20240,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19809
20240
|
...d.role === "beam" ? style.lintelAssembly ? { assembly: style.lintelAssembly } : {} : wall.assembly ? { assembly: wall.assembly } : {}
|
|
19810
20241
|
}));
|
|
19811
20242
|
const internal = [];
|
|
20243
|
+
for (const beam of sillBeams) {
|
|
20244
|
+
const sill = drafts.find((d) => d.id === beam.id.replace("_sillbeam_", "_sill_"));
|
|
20245
|
+
if (sill) internal.push({ part: beam.id, on: sill.id, joint: style.lintelJoint });
|
|
20246
|
+
for (const pier of piers) if (Math.min(pier.to, beam.to) - Math.max(pier.from, beam.from) > 0) internal.push({ part: beam.id, on: pier.id, joint: style.lintelJoint });
|
|
20247
|
+
}
|
|
19812
20248
|
lintels.forEach((lintel, k) => {
|
|
19813
20249
|
for (const pier of piers) if (Math.min(pier.to, lintel.to) - Math.max(pier.from, lintel.from) > 0) internal.push({ part: lintel.id, on: pier.id, joint: style.lintelJoint });
|
|
19814
20250
|
const spandrel = spandrels[k];
|
|
@@ -19838,7 +20274,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19838
20274
|
...system.timber ? {} : { lintelAssembly: "reinforced_concrete" },
|
|
19839
20275
|
lintelJoint: system.joints.beam,
|
|
19840
20276
|
wallJoint: system.joints.wall,
|
|
19841
|
-
...lintelDepth && !system.timber ? { lintelDepth } : {}
|
|
20277
|
+
...lintelDepth && !system.timber ? { lintelDepth } : {},
|
|
20278
|
+
...construction.system === "masonry" ? { sillBeam: true } : {}
|
|
19842
20279
|
});
|
|
19843
20280
|
if (split.pieces.length > 1) splits.set(part.id, split);
|
|
19844
20281
|
}
|
|
@@ -19846,7 +20283,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19846
20283
|
}
|
|
19847
20284
|
function applyPanels(input, structure, detail, lintelDepth) {
|
|
19848
20285
|
if (detail === "coarse") return input;
|
|
19849
|
-
return applySplits(input, panelSplits(input, structure, lintelDepth));
|
|
20286
|
+
return onJambPillars(applySplits(input, panelSplits(input, structure, lintelDepth)));
|
|
20287
|
+
}
|
|
20288
|
+
var OPENING_BEAM = /_(lintel|sillbeam)_\d+$/;
|
|
20289
|
+
var overlaps2 = (a, b) => a[0] < b[2] && a[2] > b[0] && a[1] < b[3] && a[3] > b[1];
|
|
20290
|
+
function onJambPillars(split) {
|
|
20291
|
+
const pillars = split.parts.filter((part) => part.role === "column" && part.material === "concrete");
|
|
20292
|
+
const extra = [];
|
|
20293
|
+
for (const beam of split.parts) {
|
|
20294
|
+
if (beam.role !== "beam" || !OPENING_BEAM.test(beam.id)) continue;
|
|
20295
|
+
for (const pillar of pillars) if (pillar.floor === beam.floor && overlaps2(pillar.aabb, beam.aabb) && pillar.y0 <= beam.y0 && pillar.y1 >= beam.y1 - 0.01) extra.push({ part: beam.id, on: pillar.id, joint: "rebar" });
|
|
20296
|
+
}
|
|
20297
|
+
return extra.length ? { parts: split.parts, supports: [...split.supports, ...extra] } : split;
|
|
19850
20298
|
}
|
|
19851
20299
|
function applyUnits(input, structure) {
|
|
19852
20300
|
const splits = /* @__PURE__ */ new Map();
|
|
@@ -19908,21 +20356,35 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19908
20356
|
};
|
|
19909
20357
|
var MEMBER_CAGE = { spacing: 0.1, diameter: 8e-3, unit: 0.1 };
|
|
19910
20358
|
var CAGED_ROLES = /* @__PURE__ */ new Set(["beam", "column"]);
|
|
20359
|
+
var CAGE_COVER = 0.03;
|
|
20360
|
+
var CAGE_BUCKLING_SHARE = 0.5;
|
|
20361
|
+
var DEFAULT_RESIDUAL = 0.15;
|
|
20362
|
+
function cageResidualCapacity(size, reinforcement, capacity) {
|
|
20363
|
+
const [a = 0, b = 0] = [...size].sort((x, y) => x - y);
|
|
20364
|
+
const perSide = (w) => Math.max(2, Math.floor(Math.max(0, w - 2 * CAGE_COVER) / reinforcement.spacing) + 1);
|
|
20365
|
+
const bars = 2 * perSide(a) + 2 * perSide(b) - 4;
|
|
20366
|
+
const steel = MATERIALS2.find((m) => m.id === reinforcement.material)?.compressive ?? 0;
|
|
20367
|
+
const carries2 = bars * Math.PI * (reinforcement.diameter / 2) ** 2 * steel * CAGE_BUCKLING_SHARE;
|
|
20368
|
+
if (!capacity || capacity <= 0 || carries2 <= 0) return DEFAULT_RESIDUAL;
|
|
20369
|
+
return Math.min(1, Math.max(DEFAULT_RESIDUAL, carries2 / capacity));
|
|
20370
|
+
}
|
|
19911
20371
|
var caged = (spec, part, rebar2) => {
|
|
19912
20372
|
if (!rebar2 || part.material !== "concrete" || !CAGED_ROLES.has(part.role) || spec.reinforcement) return spec;
|
|
19913
20373
|
const size = spec.shape.kind === "box" ? spec.shape.size : null;
|
|
19914
20374
|
if (!size) return spec;
|
|
19915
20375
|
const thin = Math.min(...size);
|
|
20376
|
+
const reinforcement = { material: rebar2, spacing: MEMBER_CAGE.spacing, diameter: MEMBER_CAGE.diameter };
|
|
19916
20377
|
return {
|
|
19917
20378
|
...spec,
|
|
19918
|
-
reinforcement: {
|
|
20379
|
+
reinforcement: part.role === "column" ? { ...reinforcement, residualCapacity: cageResidualCapacity(size, reinforcement, spec.structure?.capacity) } : reinforcement,
|
|
19919
20380
|
units: { size: [MEMBER_CAGE.unit, MEMBER_CAGE.unit, thin], bond: "stack", mortar: "concrete" }
|
|
19920
20381
|
};
|
|
19921
20382
|
};
|
|
19922
20383
|
var partSpecOf = (part, capacity, detailed, rebar2) => {
|
|
19923
20384
|
if (detailed && part.assembly) return assemblySpec(part, capacity);
|
|
19924
20385
|
const spec = boxSpec(part, capacity);
|
|
19925
|
-
|
|
20386
|
+
const out = detailed ? caged(spec, part, rebar2) : spec;
|
|
20387
|
+
return part.beamKind === "ground_beam" ? { ...out, anchored: true, structure: { role: "foundation" } } : out;
|
|
19926
20388
|
};
|
|
19927
20389
|
function toDestructibleSpec(structure, options = {}) {
|
|
19928
20390
|
const { safety = 0.65, redundancy = 0.97, safetyOthers = 0.45 } = options;
|
|
@@ -19938,7 +20400,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19938
20400
|
const walled = applyPanels(slabbed, structure, detail, slabOptions && structure.construction.frame.rebar ? (span) => beamDepthFor(span, slabOptions) : void 0);
|
|
19939
20401
|
const panels = slabOptions && detail !== "coarse" ? deepenBondBeams(walled, structure, slabOptions) : walled;
|
|
19940
20402
|
const sizing = { safety, redundancy, safetyOthers };
|
|
19941
|
-
const
|
|
20403
|
+
const foundation = new Set(panels.parts.filter((part) => part.beamKind === "ground_beam").map((part) => part.id));
|
|
20404
|
+
const onFoundation = foundation.size ? panels.supports.filter((s) => !foundation.has(s.part)).map((s) => foundation.has(s.on) ? { ...s, on: GROUND } : s) : panels.supports;
|
|
20405
|
+
const sized = { ...panels, capacities: options.sized === false ? /* @__PURE__ */ new Map() : sizeCapacities(panels.parts.filter((part) => !foundation.has(part.id)), onFoundation, sizing) };
|
|
19942
20406
|
const { parts, supports, capacities } = detail === "units" ? applyUnits(sized, structure) : sized;
|
|
19943
20407
|
const specs = parts.map((part) => partSpecOf(part, capacities.get(part.id), detail !== "coarse", structure.construction.frame.rebar));
|
|
19944
20408
|
const margin = options.terrainMargin ?? TERRAIN_MARGIN;
|
|
@@ -20003,6 +20467,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20003
20467
|
out.parts = out.parts.map((p, i) => i === ground ? raft2 : p);
|
|
20004
20468
|
return out;
|
|
20005
20469
|
}
|
|
20470
|
+
var LOW_WINDOW = SILL_BEAM_DEPTH + 0.05;
|
|
20006
20471
|
var slabId = (g, f) => f === g.floors - 1 && g.roof ? "roof" : `slab_${f}`;
|
|
20007
20472
|
var storeyBase = (g, f) => f * (g.height + g.slab);
|
|
20008
20473
|
var slabHalf = (g) => [(g.spanX + g.columnSize + 0.2) / 2, (g.spanZ + g.columnSize + 0.2) / 2];
|
|
@@ -20161,7 +20626,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20161
20626
|
parts.push({ id, material: c.material, shape: box3(size), position, structure: { role: "partition" }, tags: ["infill"] });
|
|
20162
20627
|
for (const o of on) rests(joints, id, o, "mortar");
|
|
20163
20628
|
};
|
|
20164
|
-
const bay = (side, k, along,
|
|
20629
|
+
const bay = (side, k, along, centre2, fixed, length, c1, c2) => {
|
|
20165
20630
|
const clear = length - g.columnSize;
|
|
20166
20631
|
const win = clear * c.window;
|
|
20167
20632
|
const pier = (clear - win) / 2;
|
|
@@ -20172,11 +20637,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20172
20637
|
wall(`infill_${f}_${side}_${k}_${name}`, size(u, h), [p[0], y, p[2]], on);
|
|
20173
20638
|
};
|
|
20174
20639
|
const id = (name) => `infill_${f}_${side}_${k}_${name}`;
|
|
20175
|
-
put("sill", clear, sill, yb + sill / 2,
|
|
20176
|
-
put("pl", pier, head - sill, yb + sill + (head - sill) / 2,
|
|
20177
|
-
put("pr", pier, head - sill, yb + sill + (head - sill) / 2,
|
|
20178
|
-
put("head", clear, room - head, yb + head + (room - head) / 2,
|
|
20179
|
-
const gp = at2(
|
|
20640
|
+
put("sill", clear, sill, yb + sill / 2, centre2, [c1, c2]);
|
|
20641
|
+
put("pl", pier, head - sill, yb + sill + (head - sill) / 2, centre2 - clear / 2 + pier / 2, [c1, id("sill")]);
|
|
20642
|
+
put("pr", pier, head - sill, yb + sill + (head - sill) / 2, centre2 + clear / 2 - pier / 2, [c2, id("sill")]);
|
|
20643
|
+
put("head", clear, room - head, yb + head + (room - head) / 2, centre2, [c1, c2]);
|
|
20644
|
+
const gp = at2(centre2);
|
|
20180
20645
|
const gid = `glass_${f}_${side}_${k}`;
|
|
20181
20646
|
parts.push({
|
|
20182
20647
|
id: gid,
|
|
@@ -20643,7 +21108,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20643
21108
|
}
|
|
20644
21109
|
var towerLocales = { en: { labels: en_default.labels }, "pt-BR": { labels: pt_BR_default.labels } };
|
|
20645
21110
|
|
|
20646
|
-
// ../game-floorplan-three/dist/chunk-
|
|
21111
|
+
// ../game-floorplan-three/dist/chunk-7XVCZF6H.js
|
|
20647
21112
|
var en2 = {
|
|
20648
21113
|
"prompt.open": "E: open {what}",
|
|
20649
21114
|
"prompt.close": "E: close {what}",
|
|
@@ -21385,6 +21850,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21385
21850
|
}
|
|
21386
21851
|
function installHouseWalls(K, shared2) {
|
|
21387
21852
|
const { EPS: EPS3, Y0, boxC, bx, cursor, effectiveHeight, pieceRecord, structurePiece, wallColor } = K;
|
|
21853
|
+
const sh = (color2, factor) => K.sh(color2, factor);
|
|
21388
21854
|
function wallBox(alongU, L, a, b, ya, yb, th, cL, cH, mL, mH) {
|
|
21389
21855
|
if (yb - ya < 1e-4 || b - a < 1e-4) return;
|
|
21390
21856
|
if (alongU) {
|
|
@@ -21428,6 +21894,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21428
21894
|
function walls() {
|
|
21429
21895
|
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)));
|
|
21430
21896
|
const corners = /* @__PURE__ */ new Map();
|
|
21897
|
+
const looks = /* @__PURE__ */ new Map();
|
|
21431
21898
|
for (const w of R.walls) {
|
|
21432
21899
|
const f = w.floor;
|
|
21433
21900
|
cursor.group = "f" + f;
|
|
@@ -21437,6 +21904,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21437
21904
|
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);
|
|
21438
21905
|
const front = alongU && Math.abs(L - vMin) < 0.05;
|
|
21439
21906
|
const sideL = sideOf(w.sides[0], front), sideH = sideOf(w.sides[1], front);
|
|
21907
|
+
if (w.id) {
|
|
21908
|
+
const face = sideL.exterior ? sideL : sideH;
|
|
21909
|
+
looks.set(w.id, { mat: face.mat, color: face.color, top: y0 + hh });
|
|
21910
|
+
}
|
|
21440
21911
|
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 });
|
|
21441
21912
|
if (w.type === "railing") {
|
|
21442
21913
|
const c0 = shared2.ctx.colors.metal != null ? shared2.ctx.colors.metal : 9080466;
|
|
@@ -21483,8 +21954,27 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21483
21954
|
cursor.group = "f" + e.f;
|
|
21484
21955
|
bx(e.color.mat, e.pu - e.th / 2, e.y0, e.pv - e.th / 2, e.pu + e.th / 2, e.y0 + e.hh, e.pv + e.th / 2, e.color.color);
|
|
21485
21956
|
}
|
|
21957
|
+
if (shared2.ctx.showPillars) wallPillars(looks);
|
|
21486
21958
|
}
|
|
21487
|
-
|
|
21959
|
+
const PILLAR_IN_WALL = /^(wall_column_|column_\d|jamb_column_)/;
|
|
21960
|
+
const wallOf = (pillar, parts) => {
|
|
21961
|
+
const u = (pillar.aabb[0] + pillar.aabb[2]) / 2, v = (pillar.aabb[1] + pillar.aabb[3]) / 2;
|
|
21962
|
+
return parts.find((q) => (q.role === "wall" || q.role === "partition") && q.assembly !== void 0 && q.floor === pillar.floor && u >= q.aabb[0] - 1e-3 && u <= q.aabb[2] + 1e-3 && v >= q.aabb[1] - 1e-3 && v <= q.aabb[3] + 1e-3);
|
|
21963
|
+
};
|
|
21964
|
+
function wallPillars(looks) {
|
|
21965
|
+
const parts = Object.values(shared2.ctx.structureIndex);
|
|
21966
|
+
for (const e of parts) {
|
|
21967
|
+
if (e.role !== "column" || !PILLAR_IN_WALL.test(e.id)) continue;
|
|
21968
|
+
const host = wallOf(e, parts);
|
|
21969
|
+
const look = host && looks.get(host.id);
|
|
21970
|
+
if (!host || !look) continue;
|
|
21971
|
+
cursor.group = "f" + e.floor;
|
|
21972
|
+
cursor.pc = structurePiece(host.id);
|
|
21973
|
+
bx(look.mat, e.aabb[0], e.y0, e.aabb[1], e.aabb[2], Math.min(e.y1, look.top), e.aabb[3], sh(look.color != null ? look.color : 15262420, 0.93));
|
|
21974
|
+
}
|
|
21975
|
+
cursor.pc = null;
|
|
21976
|
+
}
|
|
21977
|
+
Object.assign(K, { wallBox, sideOf, pieceOf, nearestWall, walls, wallPillars });
|
|
21488
21978
|
}
|
|
21489
21979
|
function installHouseDoors(K, shared2) {
|
|
21490
21980
|
const seedKey = (id) => K.seedKey(id);
|
|
@@ -26856,7 +27346,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26856
27346
|
if (!pc || pc.unit) return sp;
|
|
26857
27347
|
if (pc.role !== "wall" && pc.role !== "partition") {
|
|
26858
27348
|
const def = getAssembly(pc.assembly || (pc.material === "concrete" && ["slab", "beam", "column", "stair"].includes(pc.role) ? "reinforced_concrete" : ""));
|
|
26859
|
-
const
|
|
27349
|
+
const cage = def && def.reinforcement ? pc.role === "column" && sp.shape.kind === "box" ? { ...def.reinforcement, residualCapacity: cageResidualCapacity(sp.shape.size, def.reinforcement, sp.structure?.capacity) } : { ...def.reinforcement } : null;
|
|
27350
|
+
const out = cage && !sp.reinforcement ? { ...sp, reinforcement: cage } : sp;
|
|
26860
27351
|
if (out.reinforcement && !out.units && pc.material === "concrete" && (pc.role === "beam" || pc.role === "column") && sp.shape.kind === "box") {
|
|
26861
27352
|
return { ...out, units: { size: [MEMBER_CAGE.unit, MEMBER_CAGE.unit, Math.min(...sp.shape.size)], bond: "stack", mortar: "concrete" } };
|
|
26862
27353
|
}
|
|
@@ -26882,6 +27373,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26882
27373
|
const a = pos.array;
|
|
26883
27374
|
const u = mesh2.userData;
|
|
26884
27375
|
if (!u._p0) u._p0 = a.slice();
|
|
27376
|
+
if (!u.plainPositions) Object.defineProperty(u, "plainPositions", { value: u._p0, enumerable: false, configurable: true, writable: true });
|
|
26885
27377
|
const list2 = u.collapsedRanges ?? (u.collapsedRanges = []);
|
|
26886
27378
|
if (!list2.some((r) => r[0] === v0 && r[1] === v1)) list2.push([v0, v1]);
|
|
26887
27379
|
const saved = a.slice(v0 * 3, v1 * 3);
|
|
@@ -26965,10 +27457,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26965
27457
|
const v = house.worldToLocal(tmp.p.set(p[0], p[1], p[2]));
|
|
26966
27458
|
return [v.x, v.y, v.z];
|
|
26967
27459
|
};
|
|
26968
|
-
function cells(part, units) {
|
|
27460
|
+
function cells(part, units, mask) {
|
|
26969
27461
|
const [u0, v0, u1, v1] = part.aabb;
|
|
26970
|
-
const alongU =
|
|
27462
|
+
const alongU = mask.alongU;
|
|
26971
27463
|
const len = alongU ? u1 - u0 : v1 - v0;
|
|
27464
|
+
const offset = (alongU ? u0 : v0) - mask.start;
|
|
26972
27465
|
const [ul, uh] = units.size;
|
|
26973
27466
|
const rows = Math.max(1, Math.round((part.y1 - part.y0) / uh));
|
|
26974
27467
|
const rowH = (part.y1 - part.y0) / rows;
|
|
@@ -26979,7 +27472,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26979
27472
|
const shift = units.bond === "running" && r & 1 ? w / 2 : 0;
|
|
26980
27473
|
for (let i = 0; i < per + (shift ? 1 : 0); i++) {
|
|
26981
27474
|
const a = Math.max(0, i * w - shift), b = Math.min(len, i * w - shift + w);
|
|
26982
|
-
if (b - a > 1e-3) out.push({ a, b, y0: part.y0 + r * rowH, y1: part.y0 + (r + 1) * rowH, r, i });
|
|
27475
|
+
if (b - a > 1e-3) out.push({ a: offset + a, b: offset + b, y0: part.y0 + r * rowH, y1: part.y0 + (r + 1) * rowH, r, i });
|
|
26983
27476
|
}
|
|
26984
27477
|
}
|
|
26985
27478
|
return out;
|
|
@@ -26993,8 +27486,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
26993
27486
|
for (const q of structure.parts) {
|
|
26994
27487
|
if (q.id !== partId && same(q.aabb, part.aabb) && Math.abs(q.y1 - part.y0) < 0.01 && structure.meshesOf(q.id).some((it) => it.mesh)) return q.id;
|
|
26995
27488
|
}
|
|
27489
|
+
return part.role === "column" ? wallAround(part) : null;
|
|
27490
|
+
}
|
|
27491
|
+
function wallAround(part) {
|
|
27492
|
+
const cu = (part.aabb[0] + part.aabb[2]) / 2, cv = (part.aabb[1] + part.aabb[3]) / 2;
|
|
27493
|
+
for (const q of structure.parts) {
|
|
27494
|
+
if (q.id === part.id || q.role !== "wall" && q.role !== "partition" || !structure.meshesOf(q.id).some((it) => it.mesh)) continue;
|
|
27495
|
+
const inside2 = cu >= q.aabb[0] - 1e-3 && cu <= q.aabb[2] + 1e-3 && cv >= q.aabb[1] - 1e-3 && cv <= q.aabb[3] + 1e-3;
|
|
27496
|
+
if (inside2 && Math.min(q.y1, part.y1) - Math.max(q.y0, part.y0) > 0.5) return q.id;
|
|
27497
|
+
}
|
|
26996
27498
|
return null;
|
|
26997
27499
|
}
|
|
27500
|
+
const pillarSpans = (view) => structure.parts.filter((q) => q.role === "column" && wallAround(q) === view.host).map((q) => {
|
|
27501
|
+
const a = (view.mask.alongU ? q.aabb[0] : q.aabb[1]) - view.mask.start, b = (view.mask.alongU ? q.aabb[2] : q.aabb[3]) - view.mask.start;
|
|
27502
|
+
return { a, b, y0: q.y0, y1: q.y1 };
|
|
27503
|
+
});
|
|
26998
27504
|
const riders = (hostId) => structure.parts.filter((q) => q.id !== hostId && specOf(q.id)?.units && hostOf(q.id) === hostId && !structure.meshesOf(q.id).some((it) => it.mesh)).map((q) => q.id);
|
|
26999
27505
|
function shell(it, mask) {
|
|
27000
27506
|
const g0 = it.mesh.geometry, g = new THREE.BufferGeometry();
|
|
@@ -27083,6 +27589,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27083
27589
|
texture.needsUpdate = true;
|
|
27084
27590
|
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) };
|
|
27085
27591
|
}
|
|
27592
|
+
function besidePillars(c, pillars) {
|
|
27593
|
+
let { a, b } = c;
|
|
27594
|
+
for (const k of pillars) {
|
|
27595
|
+
if (c.y1 <= k.y0 || c.y0 >= k.y1 || b <= k.a || a >= k.b) continue;
|
|
27596
|
+
const centre = (a + b) / 2;
|
|
27597
|
+
if (centre > k.a && centre < k.b) return [];
|
|
27598
|
+
if (centre <= k.a) b = Math.min(b, k.a);
|
|
27599
|
+
else a = Math.max(a, k.b);
|
|
27600
|
+
}
|
|
27601
|
+
return b - a > 1e-3 ? [{ ...c, a, b }] : [];
|
|
27602
|
+
}
|
|
27086
27603
|
const boxDistance = (s, y, a, b, c, d) => Math.hypot(Math.max(a - s, 0, s - b), Math.max(c - y, 0, y - d));
|
|
27087
27604
|
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);
|
|
27088
27605
|
function covered(c, boxes) {
|
|
@@ -27105,9 +27622,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27105
27622
|
const discs = [];
|
|
27106
27623
|
const flakes = [];
|
|
27107
27624
|
const shown = [];
|
|
27625
|
+
const pillars = pillarSpans(view);
|
|
27108
27626
|
for (const id of view.parts) {
|
|
27109
27627
|
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);
|
|
27110
|
-
const
|
|
27628
|
+
const own = cells(part, units2, mask);
|
|
27629
|
+
const all = id === view.host ? own.flatMap((c) => besidePillars(c, pillars)) : own;
|
|
27630
|
+
if (view.fallen.has(id)) {
|
|
27631
|
+
holes.push(...all);
|
|
27632
|
+
continue;
|
|
27633
|
+
}
|
|
27111
27634
|
const thick = mask.alongU ? part.aabb[3] - part.aabb[1] : part.aabb[2] - part.aabb[0];
|
|
27112
27635
|
const mid = mask.alongU ? (part.aabb[1] + part.aabb[3]) / 2 : (part.aabb[0] + part.aabb[2]) / 2;
|
|
27113
27636
|
if (opening) discs.push({ s: along(opening.center), y: opening.center[1], r: opening.radius });
|
|
@@ -27203,52 +27726,55 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27203
27726
|
}
|
|
27204
27727
|
return { center: local(chip.center), along: a, up: u };
|
|
27205
27728
|
}
|
|
27729
|
+
function newView(hostId) {
|
|
27730
|
+
const items = structure.meshesOf(hostId).filter((it) => it.mesh);
|
|
27731
|
+
if (!items.length) return null;
|
|
27732
|
+
const parts = [hostId, ...riders(hostId)].filter((id) => structure.byId.get(id) && specOf(id)?.units);
|
|
27733
|
+
const mask = maskOf(hostId, parts), core = maskOf(hostId, parts);
|
|
27734
|
+
return {
|
|
27735
|
+
host: hostId,
|
|
27736
|
+
parts,
|
|
27737
|
+
items,
|
|
27738
|
+
mask,
|
|
27739
|
+
core,
|
|
27740
|
+
unitMaterial: unitsMaterial(core),
|
|
27741
|
+
shells: [],
|
|
27742
|
+
saved: null,
|
|
27743
|
+
units: null,
|
|
27744
|
+
gone: 0,
|
|
27745
|
+
pits: 0,
|
|
27746
|
+
bounds: drawnBounds(items),
|
|
27747
|
+
chips: new Map(parts.map((id) => [id, []])),
|
|
27748
|
+
spalls: new Map(parts.map((id) => [id, []])),
|
|
27749
|
+
openings: /* @__PURE__ */ new Map(),
|
|
27750
|
+
flakes: 0,
|
|
27751
|
+
fallen: /* @__PURE__ */ new Set()
|
|
27752
|
+
};
|
|
27753
|
+
}
|
|
27754
|
+
function cut(view) {
|
|
27755
|
+
if (view.saved) return;
|
|
27756
|
+
view.shells = view.items.map((it) => shell(it, view.mask));
|
|
27757
|
+
for (const m of view.shells) m.userData.behind = () => view.units;
|
|
27758
|
+
view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
27759
|
+
}
|
|
27206
27760
|
function draw(partId, change) {
|
|
27207
27761
|
if (lod !== 0) return false;
|
|
27208
27762
|
const hostId = hostOf(partId);
|
|
27209
27763
|
if (!hostId || !specOf(partId)?.units) return false;
|
|
27210
|
-
|
|
27211
|
-
if (!view)
|
|
27212
|
-
const items = structure.meshesOf(hostId).filter((it) => it.mesh);
|
|
27213
|
-
if (!items.length) return false;
|
|
27214
|
-
const parts = [hostId, ...riders(hostId)].filter((id) => structure.byId.get(id) && specOf(id)?.units);
|
|
27215
|
-
if (!parts.includes(partId)) return false;
|
|
27216
|
-
const mask = maskOf(hostId, parts), core = maskOf(hostId, parts);
|
|
27217
|
-
view = {
|
|
27218
|
-
host: hostId,
|
|
27219
|
-
parts,
|
|
27220
|
-
items,
|
|
27221
|
-
mask,
|
|
27222
|
-
core,
|
|
27223
|
-
unitMaterial: unitsMaterial(core),
|
|
27224
|
-
shells: [],
|
|
27225
|
-
saved: null,
|
|
27226
|
-
units: null,
|
|
27227
|
-
gone: 0,
|
|
27228
|
-
pits: 0,
|
|
27229
|
-
bounds: drawnBounds(items),
|
|
27230
|
-
chips: new Map(parts.map((id) => [id, []])),
|
|
27231
|
-
spalls: new Map(parts.map((id) => [id, []])),
|
|
27232
|
-
openings: /* @__PURE__ */ new Map(),
|
|
27233
|
-
flakes: 0
|
|
27234
|
-
};
|
|
27235
|
-
}
|
|
27236
|
-
if (!view.chips.has(partId)) return false;
|
|
27764
|
+
const view = views.get(hostId) ?? newView(hostId);
|
|
27765
|
+
if (!view || !view.chips.has(partId)) return false;
|
|
27237
27766
|
if (change.opening) {
|
|
27238
27767
|
if (view.openings.has(partId)) return false;
|
|
27239
27768
|
view.openings.set(partId, { center: local(change.opening.center), radius: change.opening.radius });
|
|
27240
27769
|
}
|
|
27241
27770
|
if (change.chip) view.chips.get(partId).push(chipBox(change.chip, view.mask.alongU));
|
|
27771
|
+
for (const chip of change.chips ?? []) view.chips.get(partId).push(chipBox(chip, view.mask.alongU));
|
|
27242
27772
|
if (change.spall) {
|
|
27243
27773
|
const list2 = view.spalls.get(partId);
|
|
27244
27774
|
list2.push({ center: local(change.spall.center), radius: change.spall.radius });
|
|
27245
27775
|
if (list2.length > MAX_FLAKES) list2.shift();
|
|
27246
27776
|
}
|
|
27247
|
-
|
|
27248
|
-
view.shells = view.items.map((it) => shell(it, view.mask));
|
|
27249
|
-
for (const m of view.shells) m.userData.behind = () => view.units;
|
|
27250
|
-
view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
27251
|
-
}
|
|
27777
|
+
cut(view);
|
|
27252
27778
|
views.set(hostId, view);
|
|
27253
27779
|
if (opts.deferPaint && change.spall) dirty.add(view);
|
|
27254
27780
|
else {
|
|
@@ -27359,14 +27885,32 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27359
27885
|
*/
|
|
27360
27886
|
chip(event) {
|
|
27361
27887
|
if (event.torn) return false;
|
|
27362
|
-
|
|
27888
|
+
const rotation = event.rotation ?? [0, 0, 0, 1];
|
|
27889
|
+
if (event.units?.length) return draw(event.part, { chips: event.units.map((unit) => ({ center: unit.center, size: unit.size, rotation })) });
|
|
27890
|
+
return draw(event.part, { chip: { center: event.center, size: event.size ?? [0, 0, 0], rotation } });
|
|
27363
27891
|
},
|
|
27364
27892
|
/** The part broke or fell: its damage goes (the plain range stays collapsed, the renderer hides the part). */
|
|
27365
27893
|
drop(partId) {
|
|
27366
|
-
|
|
27367
|
-
if (!
|
|
27894
|
+
let host = views.get(partId) ?? [...views.values()].find((view) => view.parts.includes(partId));
|
|
27895
|
+
if (!host && lod === 0 && riders(partId).length > 0) {
|
|
27896
|
+
host = newView(partId);
|
|
27897
|
+
if (host) {
|
|
27898
|
+
cut(host);
|
|
27899
|
+
views.set(partId, host);
|
|
27900
|
+
}
|
|
27901
|
+
}
|
|
27902
|
+
if (!host) return;
|
|
27903
|
+
host.fallen.add(partId);
|
|
27904
|
+
if (host.parts.some((id) => !host.fallen.has(id))) {
|
|
27905
|
+
dirty.delete(host);
|
|
27906
|
+
paint(host);
|
|
27907
|
+
invalidate();
|
|
27908
|
+
invalidateShadow();
|
|
27909
|
+
return;
|
|
27910
|
+
}
|
|
27911
|
+
const v = host;
|
|
27368
27912
|
dispose(v);
|
|
27369
|
-
views.delete(
|
|
27913
|
+
views.delete(v.host);
|
|
27370
27914
|
if (v.saved) dropped.push(v);
|
|
27371
27915
|
},
|
|
27372
27916
|
/** LOD 0 draws the cut wall; LOD 1 and 2 give the wall its box back. */
|
|
@@ -27841,6 +28385,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
27841
28385
|
shared2.ctx.noPiece = false;
|
|
27842
28386
|
cursor.separate = opts.pieces === "meshes";
|
|
27843
28387
|
cursor.pc = null;
|
|
28388
|
+
shared2.ctx.showPillars = opts.pillars !== "hidden";
|
|
27844
28389
|
shared2.ctx.apartment = r.template === "apartment_modern";
|
|
27845
28390
|
shared2.ctx.pa = Math.max(3, Math.min(20, pr.floors != null ? pr.floors : 5));
|
|
27846
28391
|
shared2.ctx.pf = Math.max(1, Math.min(shared2.ctx.pa, pr.floor != null ? pr.floor : 3));
|