@adatechnology/game-weapons-three 0.10.0 → 0.10.2
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 +791 -99
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
package/dist/index.global.js
CHANGED
|
@@ -19681,6 +19681,47 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19681
19681
|
return angle === 0 ? q : quat.mul(q, quat.fromAxisAngle([0, 0, 1], angle));
|
|
19682
19682
|
};
|
|
19683
19683
|
var clamp = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
19684
|
+
var splinterBox = (inp, box5, limit = inp.maxFragments) => {
|
|
19685
|
+
const { rnd: rnd2 } = inp;
|
|
19686
|
+
const dims = box5.s;
|
|
19687
|
+
const [fmin, fmax] = inp.fragmentSize;
|
|
19688
|
+
const g = inp.grain ?? [0, 1, 2].sort((a2, b2) => dims[b2] - dims[a2])[0];
|
|
19689
|
+
const [a, b] = [0, 1, 2].filter((i) => i !== g);
|
|
19690
|
+
const w = Math.max(fmin * 1.5, 0.01);
|
|
19691
|
+
const c = clamp(Math.round(dims[a] * dims[b] / (w * w)), 3, Math.max(3, Math.floor(limit / 2)));
|
|
19692
|
+
const maxLen = fmax * 4;
|
|
19693
|
+
const cells = bsp(box5, c, [a, b], rnd2);
|
|
19694
|
+
const pieces = [];
|
|
19695
|
+
for (const cell of cells) {
|
|
19696
|
+
const extra = rnd2() < 0.4 ? 1 : 0;
|
|
19697
|
+
const k = Math.max(1, Math.ceil(dims[g] / maxLen)) + extra;
|
|
19698
|
+
for (const p of bsp(cell, k, [g], rnd2)) pieces.push(p);
|
|
19699
|
+
}
|
|
19700
|
+
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] }));
|
|
19701
|
+
};
|
|
19702
|
+
var severAt = (inp, root, at3, gap) => {
|
|
19703
|
+
const dims = root.s;
|
|
19704
|
+
const L = [0, 1, 2].sort((x, y) => dims[y] - dims[x])[0];
|
|
19705
|
+
const half = dims[L] / 2;
|
|
19706
|
+
const lo = clamp(at3 - gap / 2, -half, half), hi = clamp(at3 + gap / 2, -half, half);
|
|
19707
|
+
const out = [];
|
|
19708
|
+
const stub = (from, to) => {
|
|
19709
|
+
if (to - from < 0.02) return;
|
|
19710
|
+
const c = [root.c[0], root.c[1], root.c[2]], sz = [dims[0], dims[1], dims[2]];
|
|
19711
|
+
c[L] = (from + to) / 2;
|
|
19712
|
+
sz[L] = to - from;
|
|
19713
|
+
out.push({ center: c, size: sz, q: quat.identity(), shape: "slab", weight: sz[0] * sz[1] * sz[2] });
|
|
19714
|
+
};
|
|
19715
|
+
stub(-half, lo);
|
|
19716
|
+
stub(hi, half);
|
|
19717
|
+
const band = { c: [root.c[0], root.c[1], root.c[2]], s: [dims[0], dims[1], dims[2]] };
|
|
19718
|
+
band.c[L] = (lo + hi) / 2;
|
|
19719
|
+
band.s[L] = Math.max(hi - lo, 0.01);
|
|
19720
|
+
if (inp.style === "snap") {
|
|
19721
|
+
for (const b of bsp(band, Math.max(3, Math.min(6, inp.maxFragments - out.length)), [0, 1, 2], inp.rnd)) out.push({ center: b.c, size: b.s, q: quat.identity(), shape: "chunk", weight: b.s[0] * b.s[1] * b.s[2] });
|
|
19722
|
+
} else for (const p of splinterBox(inp, band, Math.max(3, inp.maxFragments - out.length))) out.push(p);
|
|
19723
|
+
return out;
|
|
19724
|
+
};
|
|
19684
19725
|
var tearStack = (inp, root, t, u, v, n, sheet) => {
|
|
19685
19726
|
const { dims, rnd: rnd2, maxFragments } = inp;
|
|
19686
19727
|
const layers = clamp(Math.ceil(dims[t] / STACK_LAYER), 2, 4);
|
|
@@ -19709,6 +19750,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19709
19750
|
const t = sorted[0];
|
|
19710
19751
|
const [u, v] = [sorted[1], sorted[2]].sort((a, b) => a - b);
|
|
19711
19752
|
if (style === "snap") {
|
|
19753
|
+
if (inp.cut) return severAt(inp, root, inp.cut.at, inp.cut.gap);
|
|
19712
19754
|
const n2 = Math.min(maxFragments, 2 + Math.floor(rnd2() * 3));
|
|
19713
19755
|
for (const b of bsp(root, n2, [0, 1, 2], rnd2)) out.push({ center: b.c, size: b.s, q: idq, shape: "slab", weight: b.s[0] * b.s[1] * b.s[2] });
|
|
19714
19756
|
return out;
|
|
@@ -19719,23 +19761,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19719
19761
|
return out;
|
|
19720
19762
|
}
|
|
19721
19763
|
if (style === "splinter") {
|
|
19722
|
-
|
|
19723
|
-
const
|
|
19724
|
-
const w = Math.max(fmin * 1.5, 0.01);
|
|
19725
|
-
const c = clamp(Math.round(dims[a] * dims[b] / (w * w)), 3, Math.max(3, Math.floor(maxFragments / 2)));
|
|
19726
|
-
const maxLen = fmax * 4;
|
|
19727
|
-
const cells = bsp(root, c, [a, b], rnd2);
|
|
19728
|
-
const pieces = [];
|
|
19729
|
-
for (const cell of cells) {
|
|
19730
|
-
let list2 = [cell];
|
|
19731
|
-
const extra = rnd2() < 0.4 ? 1 : 0;
|
|
19732
|
-
const k = Math.max(1, Math.ceil(dims[g] / maxLen)) + extra;
|
|
19733
|
-
list2 = bsp(cell, k, [g], rnd2);
|
|
19734
|
-
for (const p of list2) pieces.push(p);
|
|
19735
|
-
}
|
|
19736
|
-
for (const p of pieces.slice(0, maxFragments)) {
|
|
19737
|
-
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] });
|
|
19738
|
-
}
|
|
19764
|
+
if (inp.cut) return severAt(inp, root, inp.cut.at, inp.cut.gap);
|
|
19765
|
+
for (const p of splinterBox(inp, root)) out.push(p);
|
|
19739
19766
|
return out;
|
|
19740
19767
|
}
|
|
19741
19768
|
if (style === "tear") {
|
|
@@ -19897,6 +19924,27 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19897
19924
|
for (const x of spread(dims[u], COVER, spacing, MAX_BARS_PER_DIRECTION)) out.push(bar(v, dims[v] / 2 - 0.02, [[u, x], [thin, 0]]));
|
|
19898
19925
|
return out;
|
|
19899
19926
|
};
|
|
19927
|
+
var clipBarsToBox = (bars, u, v, center, size) => {
|
|
19928
|
+
const out = [];
|
|
19929
|
+
for (const [a, b] of bars) {
|
|
19930
|
+
const axis2 = a[u] !== b[u] ? u : v;
|
|
19931
|
+
const other = axis2 === u ? v : u;
|
|
19932
|
+
if (Math.abs(a[other] - center[other]) > size[other] / 2) continue;
|
|
19933
|
+
const lo = Math.max(Math.min(a[axis2], b[axis2]), center[axis2] - size[axis2] / 2), hi = Math.min(Math.max(a[axis2], b[axis2]), center[axis2] + size[axis2] / 2);
|
|
19934
|
+
if (hi - lo < 1e-6) continue;
|
|
19935
|
+
const p = [a[0], a[1], a[2]], q = [b[0], b[1], b[2]];
|
|
19936
|
+
p[axis2] = lo;
|
|
19937
|
+
q[axis2] = hi;
|
|
19938
|
+
out.push([p, q]);
|
|
19939
|
+
}
|
|
19940
|
+
return out;
|
|
19941
|
+
};
|
|
19942
|
+
var bendBar = ([a, b], thin, bow, i) => {
|
|
19943
|
+
const length2 = Math.hypot(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
|
|
19944
|
+
const m = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2, (a[2] + b[2]) / 2];
|
|
19945
|
+
m[thin] += (i % 2 === 0 ? 1 : -1) * bow * length2;
|
|
19946
|
+
return [[a, m], [m, b]];
|
|
19947
|
+
};
|
|
19900
19948
|
var clipBarsToDisc = (bars, u, v, center, radius) => {
|
|
19901
19949
|
const out = [];
|
|
19902
19950
|
for (const [a, b] of bars) {
|
|
@@ -20817,14 +20865,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20817
20865
|
smoke: "grey"
|
|
20818
20866
|
},
|
|
20819
20867
|
visual: {
|
|
20820
|
-
charColor: 1709072
|
|
20868
|
+
charColor: 1709072,
|
|
20869
|
+
innerColor: 14730131
|
|
20821
20870
|
},
|
|
20822
20871
|
tags: [
|
|
20823
20872
|
"wood",
|
|
20824
20873
|
"organic",
|
|
20825
20874
|
"flammable"
|
|
20826
20875
|
],
|
|
20827
|
-
compressive: 1e5
|
|
20876
|
+
compressive: 1e5,
|
|
20877
|
+
hits: {
|
|
20878
|
+
blunt: {
|
|
20879
|
+
tear: "splinters",
|
|
20880
|
+
tearJoules: 60
|
|
20881
|
+
}
|
|
20882
|
+
}
|
|
20828
20883
|
},
|
|
20829
20884
|
{
|
|
20830
20885
|
id: "wood_hard",
|
|
@@ -20854,14 +20909,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20854
20909
|
smoke: "grey"
|
|
20855
20910
|
},
|
|
20856
20911
|
visual: {
|
|
20857
|
-
charColor: 1709072
|
|
20912
|
+
charColor: 1709072,
|
|
20913
|
+
innerColor: 13213802
|
|
20858
20914
|
},
|
|
20859
20915
|
tags: [
|
|
20860
20916
|
"wood",
|
|
20861
20917
|
"organic",
|
|
20862
20918
|
"flammable"
|
|
20863
20919
|
],
|
|
20864
|
-
compressive: 15e4
|
|
20920
|
+
compressive: 15e4,
|
|
20921
|
+
hits: {
|
|
20922
|
+
blunt: {
|
|
20923
|
+
tear: "splinters",
|
|
20924
|
+
tearJoules: 150
|
|
20925
|
+
}
|
|
20926
|
+
}
|
|
20865
20927
|
},
|
|
20866
20928
|
{
|
|
20867
20929
|
id: "plywood",
|
|
@@ -20891,14 +20953,24 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20891
20953
|
smoke: "grey"
|
|
20892
20954
|
},
|
|
20893
20955
|
visual: {
|
|
20894
|
-
charColor: 1709072
|
|
20956
|
+
charColor: 1709072,
|
|
20957
|
+
innerColor: 14862234
|
|
20895
20958
|
},
|
|
20896
20959
|
tags: [
|
|
20897
20960
|
"wood",
|
|
20898
20961
|
"organic",
|
|
20899
20962
|
"flammable"
|
|
20900
20963
|
],
|
|
20901
|
-
compressive: 6e4
|
|
20964
|
+
compressive: 6e4,
|
|
20965
|
+
hits: {
|
|
20966
|
+
ballistic: {
|
|
20967
|
+
tear: "splinters"
|
|
20968
|
+
},
|
|
20969
|
+
blunt: {
|
|
20970
|
+
tear: "splinters",
|
|
20971
|
+
tearJoules: 80
|
|
20972
|
+
}
|
|
20973
|
+
}
|
|
20902
20974
|
},
|
|
20903
20975
|
{
|
|
20904
20976
|
id: "mdf",
|
|
@@ -20925,14 +20997,25 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20925
20997
|
smoke: "grey"
|
|
20926
20998
|
},
|
|
20927
20999
|
visual: {
|
|
20928
|
-
charColor: 1709072
|
|
21000
|
+
charColor: 1709072,
|
|
21001
|
+
innerColor: 12096362
|
|
20929
21002
|
},
|
|
20930
21003
|
tags: [
|
|
20931
21004
|
"wood",
|
|
20932
21005
|
"organic",
|
|
20933
21006
|
"flammable"
|
|
20934
21007
|
],
|
|
20935
|
-
compressive: 3e4
|
|
21008
|
+
compressive: 3e4,
|
|
21009
|
+
hits: {
|
|
21010
|
+
ballistic: {
|
|
21011
|
+
tear: "lumps",
|
|
21012
|
+
tearJoules: 120
|
|
21013
|
+
},
|
|
21014
|
+
blunt: {
|
|
21015
|
+
tear: "lumps",
|
|
21016
|
+
tearJoules: 20
|
|
21017
|
+
}
|
|
21018
|
+
}
|
|
20936
21019
|
},
|
|
20937
21020
|
{
|
|
20938
21021
|
id: "glass",
|
|
@@ -21046,6 +21129,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21046
21129
|
damageScale: {
|
|
21047
21130
|
explosive: 1.2
|
|
21048
21131
|
},
|
|
21132
|
+
hits: {
|
|
21133
|
+
ballistic: {
|
|
21134
|
+
unitJoules: 500,
|
|
21135
|
+
floor: 900,
|
|
21136
|
+
crater: true
|
|
21137
|
+
},
|
|
21138
|
+
blunt: {
|
|
21139
|
+
unitJoules: 1500,
|
|
21140
|
+
floor: 60
|
|
21141
|
+
}
|
|
21142
|
+
},
|
|
21049
21143
|
hitDebris: "chips",
|
|
21050
21144
|
breakDebris: "dust",
|
|
21051
21145
|
thermal: {
|
|
@@ -21414,7 +21508,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21414
21508
|
smoke: "white"
|
|
21415
21509
|
},
|
|
21416
21510
|
visual: {
|
|
21417
|
-
charColor: 1709072
|
|
21511
|
+
charColor: 1709072,
|
|
21512
|
+
innerColor: 14207126
|
|
21418
21513
|
},
|
|
21419
21514
|
tags: [
|
|
21420
21515
|
"plant",
|
|
@@ -21422,7 +21517,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21422
21517
|
"organic",
|
|
21423
21518
|
"flammable"
|
|
21424
21519
|
],
|
|
21425
|
-
compressive: 6e4
|
|
21520
|
+
compressive: 6e4,
|
|
21521
|
+
hits: {
|
|
21522
|
+
blunt: {
|
|
21523
|
+
tear: "none"
|
|
21524
|
+
}
|
|
21525
|
+
}
|
|
21426
21526
|
},
|
|
21427
21527
|
{
|
|
21428
21528
|
id: "cactus",
|
|
@@ -21537,6 +21637,130 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21537
21637
|
"masonry"
|
|
21538
21638
|
],
|
|
21539
21639
|
compressive: 2e4
|
|
21640
|
+
},
|
|
21641
|
+
{
|
|
21642
|
+
id: "asphalt",
|
|
21643
|
+
density: 2350,
|
|
21644
|
+
hpPerKg: 10,
|
|
21645
|
+
penetration: 14,
|
|
21646
|
+
penetrationClass: "concrete",
|
|
21647
|
+
penetrationScale: 0.8,
|
|
21648
|
+
ductility: 0.1,
|
|
21649
|
+
fracture: "crumble",
|
|
21650
|
+
fragmentSize: [
|
|
21651
|
+
0.03,
|
|
21652
|
+
0.15
|
|
21653
|
+
],
|
|
21654
|
+
hitDebris: "chips",
|
|
21655
|
+
breakDebris: "dust",
|
|
21656
|
+
thermal: {
|
|
21657
|
+
conductivity: 0.1,
|
|
21658
|
+
heatCapacity: 2,
|
|
21659
|
+
ignitionC: 400,
|
|
21660
|
+
burnRate: 2e-3,
|
|
21661
|
+
smoke: "black"
|
|
21662
|
+
},
|
|
21663
|
+
tags: [
|
|
21664
|
+
"masonry",
|
|
21665
|
+
"brittle"
|
|
21666
|
+
],
|
|
21667
|
+
compressive: 3e4
|
|
21668
|
+
},
|
|
21669
|
+
{
|
|
21670
|
+
id: "sand",
|
|
21671
|
+
density: 1600,
|
|
21672
|
+
hpPerKg: 2,
|
|
21673
|
+
penetration: 6,
|
|
21674
|
+
ductility: 0.4,
|
|
21675
|
+
fracture: "crumble",
|
|
21676
|
+
fragmentSize: [
|
|
21677
|
+
0.01,
|
|
21678
|
+
0.04
|
|
21679
|
+
],
|
|
21680
|
+
hitDebris: "dust",
|
|
21681
|
+
breakDebris: "dust",
|
|
21682
|
+
thermal: {
|
|
21683
|
+
conductivity: 0.1,
|
|
21684
|
+
heatCapacity: 2
|
|
21685
|
+
},
|
|
21686
|
+
tags: [
|
|
21687
|
+
"soil"
|
|
21688
|
+
],
|
|
21689
|
+
compressive: 1e4
|
|
21690
|
+
},
|
|
21691
|
+
{
|
|
21692
|
+
id: "gravel",
|
|
21693
|
+
density: 1800,
|
|
21694
|
+
hpPerKg: 3,
|
|
21695
|
+
penetration: 8,
|
|
21696
|
+
ductility: 0.3,
|
|
21697
|
+
fracture: "crumble",
|
|
21698
|
+
fragmentSize: [
|
|
21699
|
+
0.02,
|
|
21700
|
+
0.06
|
|
21701
|
+
],
|
|
21702
|
+
hitDebris: "chips",
|
|
21703
|
+
breakDebris: "dust",
|
|
21704
|
+
thermal: {
|
|
21705
|
+
conductivity: 0.1,
|
|
21706
|
+
heatCapacity: 2
|
|
21707
|
+
},
|
|
21708
|
+
tags: [
|
|
21709
|
+
"soil",
|
|
21710
|
+
"masonry"
|
|
21711
|
+
],
|
|
21712
|
+
compressive: 2e4
|
|
21713
|
+
},
|
|
21714
|
+
{
|
|
21715
|
+
id: "turf",
|
|
21716
|
+
density: 900,
|
|
21717
|
+
hpPerKg: 3,
|
|
21718
|
+
penetration: 4,
|
|
21719
|
+
ductility: 0.5,
|
|
21720
|
+
fracture: "crumble",
|
|
21721
|
+
fragmentSize: [
|
|
21722
|
+
0.03,
|
|
21723
|
+
0.1
|
|
21724
|
+
],
|
|
21725
|
+
hitDebris: "dust",
|
|
21726
|
+
breakDebris: "dust",
|
|
21727
|
+
thermal: {
|
|
21728
|
+
conductivity: 0.1,
|
|
21729
|
+
heatCapacity: 1.5,
|
|
21730
|
+
ignitionC: 250,
|
|
21731
|
+
burnRate: 0.03,
|
|
21732
|
+
smoke: "white"
|
|
21733
|
+
},
|
|
21734
|
+
tags: [
|
|
21735
|
+
"soil",
|
|
21736
|
+
"organic"
|
|
21737
|
+
],
|
|
21738
|
+
compressive: 15e3
|
|
21739
|
+
},
|
|
21740
|
+
{
|
|
21741
|
+
id: "mortar",
|
|
21742
|
+
density: 1900,
|
|
21743
|
+
hpPerKg: 10,
|
|
21744
|
+
penetration: 12,
|
|
21745
|
+
penetrationClass: "concrete",
|
|
21746
|
+
penetrationScale: 1.2,
|
|
21747
|
+
ductility: 0.03,
|
|
21748
|
+
fracture: "crumble",
|
|
21749
|
+
fragmentSize: [
|
|
21750
|
+
0.02,
|
|
21751
|
+
0.08
|
|
21752
|
+
],
|
|
21753
|
+
hitDebris: "chips",
|
|
21754
|
+
breakDebris: "dust",
|
|
21755
|
+
thermal: {
|
|
21756
|
+
conductivity: 0.15,
|
|
21757
|
+
heatCapacity: 2.5
|
|
21758
|
+
},
|
|
21759
|
+
tags: [
|
|
21760
|
+
"masonry",
|
|
21761
|
+
"brittle"
|
|
21762
|
+
],
|
|
21763
|
+
compressive: 1e5
|
|
21540
21764
|
}
|
|
21541
21765
|
];
|
|
21542
21766
|
var material_hints_default = {
|
|
@@ -21710,6 +21934,32 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21710
21934
|
return (1 + 4 * (0.3 - ductility) / 0.3) * Math.min(25, Math.max(1, (0.02 / Math.max(thickness, 1e-4)) ** 2));
|
|
21711
21935
|
};
|
|
21712
21936
|
var THIN_SHEET_DISHING = 5e-3;
|
|
21937
|
+
var SWEEP_BACK = 0.01;
|
|
21938
|
+
function sweepOrigins(box5, d, spacing) {
|
|
21939
|
+
const origins = [];
|
|
21940
|
+
const line = (from, to) => {
|
|
21941
|
+
const n = Math.max(1, Math.ceil((to - from) / spacing));
|
|
21942
|
+
return Array.from({ length: n + 1 }, (_, i) => from + (to - from) * i / n);
|
|
21943
|
+
};
|
|
21944
|
+
for (const axis2 of [0, 1, 2]) {
|
|
21945
|
+
if (Math.abs(d[axis2]) < 1e-3) continue;
|
|
21946
|
+
const lead = d[axis2] > 0 ? box5.max[axis2] - SWEEP_BACK : box5.min[axis2] + SWEEP_BACK;
|
|
21947
|
+
const u = (axis2 + 1) % 3;
|
|
21948
|
+
const v = (axis2 + 2) % 3;
|
|
21949
|
+
for (const a of line(box5.min[u], box5.max[u])) {
|
|
21950
|
+
for (const b of line(box5.min[v], box5.max[v])) {
|
|
21951
|
+
const point = [0, 0, 0];
|
|
21952
|
+
point[axis2] = lead;
|
|
21953
|
+
point[u] = a;
|
|
21954
|
+
point[v] = b;
|
|
21955
|
+
origins.push(point);
|
|
21956
|
+
}
|
|
21957
|
+
}
|
|
21958
|
+
}
|
|
21959
|
+
return origins;
|
|
21960
|
+
}
|
|
21961
|
+
var THIN_SHEET_CRUSH = 5e-4;
|
|
21962
|
+
var THIN_SHEET_CONTACT = 0.025;
|
|
21713
21963
|
var DMG_PER_J = 0.02;
|
|
21714
21964
|
var BLAST_COUPLING = 0.1;
|
|
21715
21965
|
var SHELTER_DEFAULTS = { k: 2800, brokenTransmission: 0.5, minPath: 5e-3 };
|
|
@@ -21723,9 +21973,17 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21723
21973
|
var BREACH_AREA = 0.25;
|
|
21724
21974
|
var BREACH_BLAST_REACH = 0.12;
|
|
21725
21975
|
var RESIDUAL_CAPACITY = 0.15;
|
|
21976
|
+
var SEVER_BAND = 0.1;
|
|
21977
|
+
var SEVER_ASPECT = 3;
|
|
21978
|
+
var SEVER_BALLISTIC = 2;
|
|
21979
|
+
var TEAR_JOULES = 150;
|
|
21980
|
+
var tears = 0;
|
|
21726
21981
|
var SUPPORT_TOLERANCE = 0.05;
|
|
21727
21982
|
var UNIT_FRAGMENT_FACTOR = 4;
|
|
21728
21983
|
var BREACH_GRID_CAP = 4096;
|
|
21984
|
+
var CHIP_ENERGY = 200;
|
|
21985
|
+
var CHIP_SPLASH = 0.5;
|
|
21986
|
+
var BAR_BOW = 0.08;
|
|
21729
21987
|
var CUT_SLICE = 1;
|
|
21730
21988
|
var cutFactorOf = (shape) => clamp2(Math.max(...shapeDims(shape)) / CUT_SLICE, 1, 50);
|
|
21731
21989
|
var clamp2 = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
@@ -21735,8 +21993,24 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21735
21993
|
return v === void 0 ? void 0 : v * (mat.penetrationScale ?? 1);
|
|
21736
21994
|
};
|
|
21737
21995
|
var capacityScale = (p) => {
|
|
21738
|
-
|
|
21739
|
-
|
|
21996
|
+
const residual = p.spec.reinforcement?.residualCapacity ?? RESIDUAL_CAPACITY;
|
|
21997
|
+
if (p.st.stripped) return residual;
|
|
21998
|
+
const kept = Math.min(p.rt.removed ? 1 - p.rt.removed / p.mass0 : 1, 1 - sectionLoss(p));
|
|
21999
|
+
return Math.max(p.spec.reinforcement ? residual : 0.05, kept);
|
|
22000
|
+
};
|
|
22001
|
+
var sectionLoss = (p) => {
|
|
22002
|
+
const cells = p.st.chipped;
|
|
22003
|
+
if (!cells?.length) return 0;
|
|
22004
|
+
const [u, v] = planeAxes(p.thin);
|
|
22005
|
+
const along = p.dims[u] >= p.dims[v] ? u : v;
|
|
22006
|
+
const across2 = along === u ? v : u;
|
|
22007
|
+
let worst = 0;
|
|
22008
|
+
for (const c of cells) {
|
|
22009
|
+
let gone = 0;
|
|
22010
|
+
for (const d of cells) if (Math.abs(d.center[along] - c.center[along]) < d.size[along] / 2 + 1e-6) gone += d.size[across2];
|
|
22011
|
+
worst = Math.max(worst, gone / Math.max(p.dims[across2], 1e-6));
|
|
22012
|
+
}
|
|
22013
|
+
return Math.min(1, worst);
|
|
21740
22014
|
};
|
|
21741
22015
|
var isLost = (p) => p.st.status === "broken" || p.st.status === "melted" || p.st.status === "ashes";
|
|
21742
22016
|
var clone = (v) => structuredClone(v);
|
|
@@ -21769,6 +22043,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21769
22043
|
let windCfg = windOpts ? resolveWind(windOpts) : null;
|
|
21770
22044
|
const ignitionRules = resolveIgnitionRules(options.ignition);
|
|
21771
22045
|
const breachBlastFactor = options.breach?.blastFactor ?? BREACH_BLAST_FACTOR;
|
|
22046
|
+
const chipEnergy = options.breach?.chipEnergy ?? CHIP_ENERGY;
|
|
21772
22047
|
const rng2 = createRng2(options.seed ?? 1);
|
|
21773
22048
|
const rnd2 = () => rng2.next();
|
|
21774
22049
|
let time = 0;
|
|
@@ -22142,41 +22417,68 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22142
22417
|
markDamaged(p);
|
|
22143
22418
|
if (p.rt.hinge >= flexure.failRotationDeg * Math.PI / 180) hingeDrop(o, p, src);
|
|
22144
22419
|
};
|
|
22420
|
+
const freeSpan = (p, supports) => {
|
|
22421
|
+
if (supports.length === 0) return Infinity;
|
|
22422
|
+
const d = p.dims;
|
|
22423
|
+
const L = [0, 1, 2].sort((a, b) => d[b] - d[a])[0];
|
|
22424
|
+
const spans = supports.map((k) => contactBox(p, k)).map(([lo, hi]) => [lo[L], hi[L]]);
|
|
22425
|
+
let far = 0;
|
|
22426
|
+
for (let i = 0; i <= 16; i++) {
|
|
22427
|
+
const x = (i / 16 - 0.5) * d[L];
|
|
22428
|
+
let near = Infinity;
|
|
22429
|
+
for (const [lo, hi] of spans) near = Math.min(near, Math.max(lo - x, x - hi, 0));
|
|
22430
|
+
far = Math.max(far, near);
|
|
22431
|
+
}
|
|
22432
|
+
return 2 * far;
|
|
22433
|
+
};
|
|
22145
22434
|
const solveStructure = (o) => {
|
|
22146
22435
|
o.maxStress = 0;
|
|
22147
22436
|
if (!o.hasStructure) return;
|
|
22148
22437
|
const parts = o.parts;
|
|
22149
22438
|
const n = parts.length;
|
|
22150
22439
|
const dist2 = new Array(n).fill(-1);
|
|
22151
|
-
const queue = [];
|
|
22152
22440
|
const ok = (i) => parts[i].structural && !isLost(parts[i]);
|
|
22153
22441
|
const isPartition = (i) => parts[i].spec.structure?.role === "partition";
|
|
22154
|
-
|
|
22155
|
-
|
|
22156
|
-
|
|
22157
|
-
|
|
22158
|
-
|
|
22159
|
-
|
|
22160
|
-
if (
|
|
22161
|
-
|
|
22162
|
-
|
|
22163
|
-
|
|
22164
|
-
|
|
22165
|
-
|
|
22166
|
-
|
|
22442
|
+
const out = /* @__PURE__ */ new Set();
|
|
22443
|
+
let queue = [];
|
|
22444
|
+
let lowerOf = /* @__PURE__ */ new Map();
|
|
22445
|
+
for (; ; ) {
|
|
22446
|
+
dist2.fill(-1);
|
|
22447
|
+
queue = [];
|
|
22448
|
+
for (let i = 0; i < n; i++) if (ok(i) && !out.has(i) && parts[i].anchored) {
|
|
22449
|
+
dist2[i] = 0;
|
|
22450
|
+
queue.push(i);
|
|
22451
|
+
}
|
|
22452
|
+
for (let h = 0; h < queue.length; h++) {
|
|
22453
|
+
const s = queue[h];
|
|
22454
|
+
if (isPartition(s)) continue;
|
|
22455
|
+
for (const j of o.byPart.get(parts[s].spec.id)) {
|
|
22456
|
+
if (j.st.open || !j.bears) continue;
|
|
22457
|
+
const r = j.ia === s ? j.ib : j.ia;
|
|
22458
|
+
if (dist2[r] >= 0 || !ok(r) || out.has(r) || restsOn(o, j, r) !== s) continue;
|
|
22459
|
+
dist2[r] = dist2[s] + 1;
|
|
22460
|
+
queue.push(r);
|
|
22461
|
+
}
|
|
22167
22462
|
}
|
|
22168
|
-
|
|
22169
|
-
|
|
22170
|
-
|
|
22171
|
-
|
|
22172
|
-
|
|
22173
|
-
|
|
22174
|
-
|
|
22175
|
-
|
|
22176
|
-
|
|
22463
|
+
lowerOf = /* @__PURE__ */ new Map();
|
|
22464
|
+
let dropped = false;
|
|
22465
|
+
for (const i of queue) {
|
|
22466
|
+
const lower = [];
|
|
22467
|
+
for (const j of o.byPart.get(parts[i].spec.id)) {
|
|
22468
|
+
if (j.st.open || !j.bears) continue;
|
|
22469
|
+
const k = restsOn(o, j, i);
|
|
22470
|
+
if (k >= 0 && dist2[k] >= 0 && dist2[k] < dist2[i] && !isPartition(k)) lower.push(k);
|
|
22471
|
+
}
|
|
22472
|
+
lowerOf.set(i, lower);
|
|
22473
|
+
const max2 = parts[i].spec.structure?.maxSpan;
|
|
22474
|
+
if (max2 !== void 0 && !parts[i].anchored && freeSpan(parts[i], lower.map((k) => parts[k])) > max2) {
|
|
22475
|
+
out.add(i);
|
|
22476
|
+
dropped = true;
|
|
22477
|
+
}
|
|
22177
22478
|
}
|
|
22178
|
-
|
|
22479
|
+
if (!dropped) break;
|
|
22179
22480
|
}
|
|
22481
|
+
const incoming = new Array(n).fill(0);
|
|
22180
22482
|
const bending = new Array(n).fill(0);
|
|
22181
22483
|
const through = parts.map(() => []);
|
|
22182
22484
|
const pass = (k, at3, mass) => {
|
|
@@ -22688,6 +22990,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22688
22990
|
const r = rayPart(o, p, origin, d);
|
|
22689
22991
|
if (!r || r.t0 < 0 || r.t0 > maxDist) continue;
|
|
22690
22992
|
if (p.st.opening && insideOpening(o, p, vec.madd(origin, d, r.t0))) continue;
|
|
22993
|
+
if (p.st.chipped && insideChip(p, objLocal(o, vec.madd(origin, d, r.t0)))) continue;
|
|
22691
22994
|
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 };
|
|
22692
22995
|
}
|
|
22693
22996
|
}
|
|
@@ -22888,6 +23191,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22888
23191
|
debris2(o, p, layer2.mat.hitDebris, wp, normal, 5, 2, src);
|
|
22889
23192
|
setStage(o, p, 1, {}, src);
|
|
22890
23193
|
};
|
|
23194
|
+
const crater = (o, p, wp, normal, radius, src) => {
|
|
23195
|
+
markDamaged(p);
|
|
23196
|
+
emit2({ ...base(o, src), type: "spall", part: p.spec.id, layer: -1, point: wp, area: Math.PI * radius * radius });
|
|
23197
|
+
debris2(o, p, p.mat.breakDebris, wp, normal, 6, 1.5, src);
|
|
23198
|
+
setStage(o, p, 1, {}, src);
|
|
23199
|
+
};
|
|
22891
23200
|
const insideOpening = (o, p, objectPoint) => {
|
|
22892
23201
|
const op = p.st.opening;
|
|
22893
23202
|
if (!op) return false;
|
|
@@ -22951,6 +23260,91 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22951
23260
|
if (total < (p.spec.breach?.area ?? BREACH_AREA)) return;
|
|
22952
23261
|
openBreach(o, p, [sum2[0] / total, sum2[1] / total, sum2[2] / total], total, energy, dir, src);
|
|
22953
23262
|
};
|
|
23263
|
+
const unitGrids = /* @__PURE__ */ new WeakMap();
|
|
23264
|
+
const gridOf = (p) => {
|
|
23265
|
+
let grid = unitGrids.get(p);
|
|
23266
|
+
if (!grid) unitGrids.set(p, grid = unitGrid(p.dims, p.thin, unitsOf2(p), BREACH_GRID_CAP));
|
|
23267
|
+
return grid;
|
|
23268
|
+
};
|
|
23269
|
+
const insideChip = (p, objectPoint) => {
|
|
23270
|
+
const cells = p.st.chipped;
|
|
23271
|
+
if (!cells?.length) return false;
|
|
23272
|
+
const [u, v] = planeAxes(p.thin);
|
|
23273
|
+
const lp = toLocal(p.pos, p.q, objectPoint);
|
|
23274
|
+
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);
|
|
23275
|
+
};
|
|
23276
|
+
const chipUnits = (o, p, kind, wp, hitEnergy, dir, radius, src) => {
|
|
23277
|
+
var _a, _b;
|
|
23278
|
+
if (!p.spec.units || !p.staged || chipEnergy <= 0 || p.st.stripped || isLost(p) || (p.st.stage ?? 0) >= 2) return;
|
|
23279
|
+
const rule = p.mat.hits?.[kind];
|
|
23280
|
+
const perKg = rule?.unitJoules ?? chipEnergy;
|
|
23281
|
+
const energy = hitEnergy - (rule?.floor ?? 0);
|
|
23282
|
+
if (perKg <= 0 || energy <= 0) return;
|
|
23283
|
+
const [u, v] = planeAxes(p.thin);
|
|
23284
|
+
const lp = toLocal(p.pos, p.q, objLocal(o, wp));
|
|
23285
|
+
const grid = gridOf(p);
|
|
23286
|
+
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
23287
|
+
const out = [];
|
|
23288
|
+
for (let i = 0; i < grid.length; i++) {
|
|
23289
|
+
const cell = grid[i];
|
|
23290
|
+
if (worn[i] === -1) continue;
|
|
23291
|
+
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));
|
|
23292
|
+
if (gap > radius) continue;
|
|
23293
|
+
const share = gap === 0 ? 1 : CHIP_SPLASH * (1 - gap / radius);
|
|
23294
|
+
const total = (worn[i] ?? 0) + energy * share;
|
|
23295
|
+
const mass = p.mat.density * cell.size[0] * cell.size[1] * cell.size[2];
|
|
23296
|
+
if (total < perKg * mass) {
|
|
23297
|
+
worn[i] = total;
|
|
23298
|
+
continue;
|
|
23299
|
+
}
|
|
23300
|
+
worn[i] = -1;
|
|
23301
|
+
out.push(cell);
|
|
23302
|
+
}
|
|
23303
|
+
if (out.length === 0) return;
|
|
23304
|
+
const { c, q } = partXf(o, p);
|
|
23305
|
+
const chipped = (_b = p.st).chipped ?? (_b.chipped = []);
|
|
23306
|
+
const holes = localHolesOf(p);
|
|
23307
|
+
for (const cell of out) {
|
|
23308
|
+
const mass = Math.min(p.st.mass, p.mat.density * cell.size[0] * cell.size[1] * cell.size[2]);
|
|
23309
|
+
const center = toWorld(c, q, cell.center);
|
|
23310
|
+
const speed = clamp2(Math.sqrt(2 * energy * 0.05 / Math.max(mass, 0.05)), 0.5, 6);
|
|
23311
|
+
const fragments = cellFragments(o, p, [cell], wp, dir, speed, mass, `c${chipped.length}_`);
|
|
23312
|
+
p.st.holes = p.st.holes.filter((_, k) => marksInBox(cell.center, cell.size, void 0, [holes[k]]).length === 0);
|
|
23313
|
+
chipped.push({ center: [cell.center[0], cell.center[1], cell.center[2]], size: [cell.size[0], cell.size[1], cell.size[2]] });
|
|
23314
|
+
p.st.mass = Math.max(0, p.st.mass - mass);
|
|
23315
|
+
p.rt.removed = (p.rt.removed ?? 0) + mass;
|
|
23316
|
+
markDamaged(p);
|
|
23317
|
+
setStage(o, p, 1, {}, src);
|
|
23318
|
+
emit2({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [cell.size[0], cell.size[1], cell.size[2]], rotation: q, fragments });
|
|
23319
|
+
debris2(o, p, p.mat.breakDebris, center, vec.scale(dir ?? [0, 1, 0], -1), 6, 2, src);
|
|
23320
|
+
}
|
|
23321
|
+
if (p.spec.reinforcement) exposeRebar(o, p, src);
|
|
23322
|
+
for (const cell of out) addBreach(o, p, toWorld(c, q, cell.center), cell.size[u] * cell.size[v], energy, dir, src);
|
|
23323
|
+
if (p.structural && !isLost(p)) {
|
|
23324
|
+
solveStructure(o);
|
|
23325
|
+
collapseCheck(o, src);
|
|
23326
|
+
}
|
|
23327
|
+
};
|
|
23328
|
+
const exposeRebar = (o, p, src) => {
|
|
23329
|
+
const r = p.spec.reinforcement;
|
|
23330
|
+
if (!r) return;
|
|
23331
|
+
const [u, v] = planeAxes(p.thin);
|
|
23332
|
+
const all = rebarBars(p.dims, p.thin, r.spacing);
|
|
23333
|
+
let bars;
|
|
23334
|
+
if (p.st.stripped) bars = all;
|
|
23335
|
+
else {
|
|
23336
|
+
bars = [];
|
|
23337
|
+
for (const cell of p.st.chipped ?? []) bars.push(...clipBarsToBox(all, u, v, cell.center, cell.size));
|
|
23338
|
+
const op = p.st.opening;
|
|
23339
|
+
if (op) {
|
|
23340
|
+
const lc = toLocal(p.pos, p.q, op.center);
|
|
23341
|
+
bars.push(...clipBarsToDisc(all, u, v, [lc[u], lc[v]], op.radius + 0.05));
|
|
23342
|
+
}
|
|
23343
|
+
}
|
|
23344
|
+
const bow = clamp2(((p.st.stress ?? 0) - 1) / 0.5, 0, 1);
|
|
23345
|
+
if (bow > 0) bars = bars.flatMap((bar2, i) => bendBar(bar2, p.thin, bow * BAR_BOW, i));
|
|
23346
|
+
emit2({ ...base(o, src), type: "expose", part: p.spec.id, bars: worldBars(o, p, bars) });
|
|
23347
|
+
};
|
|
22954
23348
|
const openBreach = (o, p, center, total, energy, dir, src) => {
|
|
22955
23349
|
const [u, v] = planeAxes(p.thin);
|
|
22956
23350
|
const radius = clamp2(Math.sqrt(total / Math.PI), Math.sqrt((p.spec.breach?.area ?? BREACH_AREA) / Math.PI), breachRadius);
|
|
@@ -22962,7 +23356,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22962
23356
|
failPart(o, p, worldCenter, dir, energy, 12, src);
|
|
22963
23357
|
return;
|
|
22964
23358
|
}
|
|
22965
|
-
const
|
|
23359
|
+
const worn = p.rt.chips;
|
|
23360
|
+
const cells = cellsWithin(gridOf(p).filter((_, i) => worn?.[i] !== -1), p.thin, lc, radius);
|
|
22966
23361
|
const removed = p.st.mass * cells.reduce((sum2, cell) => sum2 + cell.size[u] * cell.size[v], 0) / (p.dims[u] * p.dims[v]);
|
|
22967
23362
|
const speed = clamp2(Math.sqrt(2 * energy * 0.1 / Math.max(removed, 0.05)), 0.5, 8);
|
|
22968
23363
|
const fragments = cellFragments(o, p, cells, worldCenter, dir, speed, removed, "b");
|
|
@@ -22976,10 +23371,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22976
23371
|
setStage(o, p, 2, { opening: { center: worldCenter, radius }, fragments }, src);
|
|
22977
23372
|
debris2(o, p, p.mat.breakDebris, worldCenter, vec.scale(dir ?? [0, 1, 0], -1), 14, 3, src);
|
|
22978
23373
|
const reinforcement = p.spec.reinforcement;
|
|
22979
|
-
if (reinforcement)
|
|
22980
|
-
const bars = worldBars(o, p, clipBarsToDisc(rebarBars(p.dims, p.thin, reinforcement.spacing), u, v, [lc[u], lc[v]], radius + 0.05));
|
|
22981
|
-
if (bars.length > 0) emit2({ ...base(o, src), type: "expose", part: p.spec.id, bars });
|
|
22982
|
-
}
|
|
23374
|
+
if (reinforcement) exposeRebar(o, p, src);
|
|
22983
23375
|
if (p.structural) solveStructure(o);
|
|
22984
23376
|
};
|
|
22985
23377
|
const stripPart = (o, p, reinforcement, src) => {
|
|
@@ -22991,8 +23383,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22991
23383
|
p.st.burning = false;
|
|
22992
23384
|
p.rt.jet = false;
|
|
22993
23385
|
markDamaged(p);
|
|
22994
|
-
emit2({ ...base(o, src), type: "expose", part: p.spec.id, bars: worldBars(o, p, bars) });
|
|
22995
23386
|
solveStructure(o);
|
|
23387
|
+
exposeRebar(o, p, src);
|
|
22996
23388
|
collapseCheck(o, src);
|
|
22997
23389
|
};
|
|
22998
23390
|
const unitFragmentPlan = (p, cap) => {
|
|
@@ -23046,6 +23438,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23046
23438
|
const grain = p.spec.grain ? AXIS[p.spec.grain] : void 0;
|
|
23047
23439
|
const hitLocal = toLocal(c, q, hitW);
|
|
23048
23440
|
const unitPlan = p.spec.units ? unitFragmentPlan(p, maxFragments * UNIT_FRAGMENT_FACTOR) : [];
|
|
23441
|
+
const axis2 = style === "splinter" || style === "snap" ? severAxis(p) : -1;
|
|
23442
|
+
const cutAt2 = axis2 < 0 ? void 0 : p.rt.cutAt ?? (origin ? hitLocal[axis2] : void 0);
|
|
23049
23443
|
const plan = unitPlan.length > 0 ? unitPlan : planFragments({
|
|
23050
23444
|
style,
|
|
23051
23445
|
dims: p.dims,
|
|
@@ -23055,7 +23449,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23055
23449
|
fragmentSize: p.mat.fragmentSize ?? [0.04, 0.2],
|
|
23056
23450
|
maxFragments,
|
|
23057
23451
|
rnd: rnd2,
|
|
23058
|
-
sheet: p.mat.sheet
|
|
23452
|
+
sheet: p.mat.sheet,
|
|
23453
|
+
...cutAt2 !== void 0 ? { cut: { at: cutAt2, gap: SEVER_BAND } } : {}
|
|
23059
23454
|
});
|
|
23060
23455
|
const holes = p.st.holes.length > 0 ? localHolesOf(p) : [];
|
|
23061
23456
|
const mass = p.st.mass;
|
|
@@ -23114,10 +23509,33 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23114
23509
|
emit2({ ...base(o, src), type: "primed", part: p.spec.id, point: partXf(o, p).c, trigger, delay });
|
|
23115
23510
|
};
|
|
23116
23511
|
const CHAIN_TRIGGER_OF = { ballistic: "shot", explosive: "explosion" };
|
|
23512
|
+
const severAxis = (p) => {
|
|
23513
|
+
if (p.mat.fracture !== "splinter" && p.mat.fracture !== "snap" || p.spec.shape.kind !== "box") return -1;
|
|
23514
|
+
const d = p.dims;
|
|
23515
|
+
const order = [0, 1, 2].sort((a, b) => d[b] - d[a]);
|
|
23516
|
+
return d[order[0]] >= SEVER_ASPECT * d[order[1]] && d[order[0]] >= 3 * SEVER_BAND ? order[0] : -1;
|
|
23517
|
+
};
|
|
23518
|
+
const bandOf = (o, p, axis2, origin) => {
|
|
23519
|
+
const { c, q } = partXf(o, p);
|
|
23520
|
+
const along = toLocal(c, q, origin)[axis2];
|
|
23521
|
+
const L = p.dims[axis2];
|
|
23522
|
+
return clamp2(Math.floor((along + L / 2) / SEVER_BAND), 0, Math.ceil(L / SEVER_BAND) - 1);
|
|
23523
|
+
};
|
|
23117
23524
|
const applyDamage = (o, p, amount, type, origin, dir, fragEnergy, cap, src) => {
|
|
23525
|
+
var _a;
|
|
23118
23526
|
if (isLost(p) || amount <= 0) return 0;
|
|
23119
23527
|
const prev = p.st.hp;
|
|
23120
23528
|
p.st.hp -= amount;
|
|
23529
|
+
const axis2 = origin && type !== "fire" && type !== "heat" ? severAxis(p) : -1;
|
|
23530
|
+
if (axis2 >= 0 && p.st.hp > 0) {
|
|
23531
|
+
const band = bandOf(o, p, axis2, origin);
|
|
23532
|
+
const cuts = (_a = p.rt).cuts ?? (_a.cuts = {});
|
|
23533
|
+
cuts[band] = (cuts[band] ?? 0) + amount * (type === "ballistic" ? SEVER_BALLISTIC : 1);
|
|
23534
|
+
if (cuts[band] >= p.st.maxHp * SEVER_BAND / p.dims[axis2]) {
|
|
23535
|
+
p.rt.cutAt = -p.dims[axis2] / 2 + (band + 0.5) * SEVER_BAND;
|
|
23536
|
+
p.st.hp = 0;
|
|
23537
|
+
}
|
|
23538
|
+
}
|
|
23121
23539
|
markDamaged(p);
|
|
23122
23540
|
const trigger = CHAIN_TRIGGER_OF[type];
|
|
23123
23541
|
const chained = trigger !== void 0 && chainDelayOf(p.spec, trigger) !== void 0;
|
|
@@ -23153,10 +23571,53 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23153
23571
|
}
|
|
23154
23572
|
}
|
|
23155
23573
|
};
|
|
23574
|
+
const tearOf = (mat, kind) => {
|
|
23575
|
+
const h = mat.hits?.[kind];
|
|
23576
|
+
const tear = h?.tear ?? (kind === "ballistic" && mat.penetrationClass === "wood" ? "splinters" : "none");
|
|
23577
|
+
return { tear, joules: h?.tearJoules ?? TEAR_JOULES };
|
|
23578
|
+
};
|
|
23579
|
+
const tearAt = (o, p, kind, entry2, exit, d, E, scale, src) => {
|
|
23580
|
+
const { tear, joules } = tearOf(p.mat, kind);
|
|
23581
|
+
if (tear === "none") return;
|
|
23582
|
+
const shot = kind === "ballistic";
|
|
23583
|
+
const n = shot ? exit ? clamp2(Math.round(E / joules), 1, 7) : 1 : clamp2(Math.floor(E / joules), 0, 5);
|
|
23584
|
+
if (n === 0) return;
|
|
23585
|
+
const fibre = tear === "lumps";
|
|
23586
|
+
const { q } = partXf(o, p);
|
|
23587
|
+
const along = (p.spec.grain ? AXIS[p.spec.grain] : void 0) ?? [0, 1, 2].sort((a, b) => p.dims[b] - p.dims[a])[0];
|
|
23588
|
+
const fragments = [];
|
|
23589
|
+
for (let i = 0; i < n; i++) {
|
|
23590
|
+
const back = !exit || i % 3 === 2;
|
|
23591
|
+
const len = scale * (fibre ? 1.2 + 1.2 * rnd2() : 3 + 4 * rnd2()), w = scale * (0.8 + 0.8 * rnd2()), t = scale * (fibre ? 0.7 + 0.6 * rnd2() : 0.4 + 0.4 * rnd2());
|
|
23592
|
+
const size = [w, w, w];
|
|
23593
|
+
size[along] = len;
|
|
23594
|
+
size[(along + 1) % 3] = w;
|
|
23595
|
+
size[(along + 2) % 3] = t;
|
|
23596
|
+
const spread3 = [(rnd2() - 0.5) * 0.8, (rnd2() - 0.2) * 0.8, (rnd2() - 0.5) * 0.8];
|
|
23597
|
+
const speed = shot ? back ? 1.5 + 2 * rnd2() : 2 + 4 * rnd2() : 0.8 + 1.2 * rnd2();
|
|
23598
|
+
const v = vec.scale(vec.normalize(vec.add(back ? vec.scale(d, -1) : d, spread3)), speed);
|
|
23599
|
+
const mass = size[0] * size[1] * size[2] * p.mat.density;
|
|
23600
|
+
fragments.push({
|
|
23601
|
+
id: `${p.spec.id}#t${tears++}-${i}`,
|
|
23602
|
+
part: p.spec.id,
|
|
23603
|
+
material: p.spec.material,
|
|
23604
|
+
shape: fibre ? "chunk" : "splinter",
|
|
23605
|
+
center: back || !exit ? vec.madd(entry2, d, -0.01) : vec.madd(exit, d, 0.01),
|
|
23606
|
+
size,
|
|
23607
|
+
rotation: q,
|
|
23608
|
+
velocity: v,
|
|
23609
|
+
inner: true,
|
|
23610
|
+
angularVelocity: [(rnd2() - 0.5) * 30, (rnd2() - 0.5) * 30, (rnd2() - 0.5) * 30],
|
|
23611
|
+
mass
|
|
23612
|
+
});
|
|
23613
|
+
}
|
|
23614
|
+
const patch = [scale * 4, scale * 4, scale * 4];
|
|
23615
|
+
emit2({ ...base(o, src), type: "chip", part: p.spec.id, center: exit ?? entry2, size: patch, rotation: q, fragments });
|
|
23616
|
+
};
|
|
23156
23617
|
const ballistic = (o, p, entry2, n, d, E, caliber, pathLen, src, round5 = {}) => {
|
|
23157
23618
|
const mat = p.mat;
|
|
23158
23619
|
const piercing = round5.piercing ?? 1;
|
|
23159
|
-
if (p.st.stripped || p.st.opening && insideOpening(o, p, objLocal(o, entry2))) {
|
|
23620
|
+
if (p.st.stripped || p.st.opening && insideOpening(o, p, objLocal(o, entry2)) || insideChip(p, objLocal(o, entry2))) {
|
|
23160
23621
|
return { penetrated: true, exitEnergy: E, exitPoint: vec.madd(entry2, d, Math.min(pathLen, p.thickness)), damage: 0 };
|
|
23161
23622
|
}
|
|
23162
23623
|
const sin2 = Math.min(1, Math.abs(vec.dot(d, n)));
|
|
@@ -23181,6 +23642,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23181
23642
|
return { penetrated: false, exitEnergy: 0, damage: dmg2 };
|
|
23182
23643
|
}
|
|
23183
23644
|
if (p.layers.length > 0) spallOuter(o, p, entry2, face, n, Math.max(0.03, caliber / 1e3 * 4), src);
|
|
23645
|
+
else if (mat.hits?.ballistic?.crater) crater(o, p, entry2, n, clamp2(0.02 + Math.sqrt(E) * 15e-4, 0.02, 0.15), src);
|
|
23184
23646
|
const brittle = mat.ductility < 0.3;
|
|
23185
23647
|
const ratio = Ep / Math.max(thr, 1e-6);
|
|
23186
23648
|
const crackLen = clamp2(0.03 + ratio * 0.2, 0.03, 0.8);
|
|
@@ -23214,7 +23676,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23214
23676
|
} else addHole(o, p, entry2, n, caliber / 1e3, false, void 0, src);
|
|
23215
23677
|
debris2(o, p, mat.hitDebris, entry2, n, clamp2(Math.round(E / 60) + 2, 2, 14), clamp2(Math.sqrt(E) / 6, 1, 8), src);
|
|
23216
23678
|
wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true);
|
|
23217
|
-
const
|
|
23679
|
+
const absorbed = penetrated && mat.ductility >= 0.5 && mat.fracture !== "tear" ? Math.min(E, thr) : E;
|
|
23680
|
+
const dmg = applyDamage(o, p, absorbed * DMG_PER_J * scale, "ballistic", entry2, d, absorbed * 0.1, 12, src);
|
|
23681
|
+
if (!isLost(p)) tearAt(o, p, "ballistic", entry2, penetrated ? exitPoint : void 0, d, E, caliber / 1e3, src);
|
|
23682
|
+
chipUnits(o, p, "ballistic", entry2, penetrated ? Math.min(E, Math.max(thr, E * 0.5)) : E, d, Math.max(0.05, caliber / 1e3 * 8), src);
|
|
23218
23683
|
return { penetrated, exitEnergy: penetrated ? penMm !== void 0 ? E * (1 - thr / Ep) : E - thr / (hard ? piercing : 1) : 0, exitPoint, damage: dmg };
|
|
23219
23684
|
};
|
|
23220
23685
|
const melee = (o, p, kind, E, point, n, d, contactR, src) => {
|
|
@@ -23222,14 +23687,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23222
23687
|
const thrMm = mat.penetration * p.thickness * 1e3;
|
|
23223
23688
|
const fragile = kind === "blunt" ? fragility(mat.ductility, p.thickness) : 1;
|
|
23224
23689
|
const Ec = E * fragile;
|
|
23690
|
+
const sheet = mat.ductility >= 0.5 && p.thickness <= THIN_SHEET_CRUSH;
|
|
23691
|
+
const fold = sheet ? Math.min(4, Math.sqrt(1e-3 / p.thickness)) : 1;
|
|
23692
|
+
const patch = sheet ? Math.min(contactR, THIN_SHEET_CONTACT) : contactR;
|
|
23225
23693
|
if (E > 0) {
|
|
23226
23694
|
if (kind === "blunt") {
|
|
23227
|
-
if (mat.ductility >= 0.5) addDent(o, p, point, n, Math.max(
|
|
23695
|
+
if (mat.ductility >= 0.5) addDent(o, p, point, n, Math.max(patch, 0.015), clamp2(E * 1e-4 * fold, 1e-3, sheet ? Math.min(0.06, Math.min(...p.dims) * 0.45) : 0.06), src);
|
|
23228
23696
|
else if (mat.ductility < 0.3) {
|
|
23229
23697
|
if (Ec >= 5) addCrack(o, p, point, n, clamp2(0.04 + Math.min(Ec, E * 6) * 8e-4, 0.04, 0.6), src);
|
|
23230
23698
|
} else if (E >= thrMm * 0.2) addDent(o, p, point, n, Math.max(contactR, 0.015), clamp2(E * 6e-5, 1e-3, 0.04), src);
|
|
23231
23699
|
} else if (mat.fracture === "tear") {
|
|
23232
23700
|
addHole(o, p, point, n, clamp2(0.02 + E * 5e-4, 0.02, 0.3), true, void 0, src);
|
|
23701
|
+
} else if (mat.ductility >= 0.3 && E >= thrMm) {
|
|
23702
|
+
addHole(o, p, point, n, clamp2(contactR, 0.01, 0.08), true, void 0, src);
|
|
23703
|
+
if (sheet) addDent(o, p, point, n, Math.max(patch * 0.6, 0.01), clamp2(E * 4e-5 * fold, 5e-4, 0.02), src);
|
|
23233
23704
|
} else if (mat.ductility >= 0.5) {
|
|
23234
23705
|
addDent(o, p, point, n, Math.max(contactR, 0.01), clamp2(E * 4e-5, 5e-4, 0.02), src);
|
|
23235
23706
|
}
|
|
@@ -23242,6 +23713,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23242
23713
|
const scale = mat.damageScale?.[kind] ?? 1;
|
|
23243
23714
|
const done = applyDamage(o, p, Ec * DMG_PER_J * scale * (kind === "slash" ? p.cutFactor : 1), kind, point, d, E * 0.1, 12, src);
|
|
23244
23715
|
addBreach(o, p, point, breachAreaOf(p, done, false), E, d, src);
|
|
23716
|
+
if (kind === "blunt") chipUnits(o, p, "blunt", point, E, d, Math.max(contactR, 0.03), src);
|
|
23717
|
+
if (E > 0 && !isLost(p)) tearAt(o, p, kind, point, void 0, d, E, clamp2(contactR * 0.2, 6e-3, 0.02), src);
|
|
23245
23718
|
return done;
|
|
23246
23719
|
};
|
|
23247
23720
|
const blastPart = (o, p, point, energy, radius, src, res, reachAt) => {
|
|
@@ -23820,6 +24293,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23820
24293
|
if (p.rt.stressT <= 0) {
|
|
23821
24294
|
p.rt.stressT = 0.5;
|
|
23822
24295
|
emit2({ ...base(o), type: "stress", part: p.spec.id, stress, load: p.st.load ?? 0 });
|
|
24296
|
+
if (p.spec.reinforcement && (p.st.stripped || p.st.chipped?.length || p.st.opening)) exposeRebar(o, p);
|
|
23823
24297
|
}
|
|
23824
24298
|
applyDamage(o, p, overloadRate(stress) * p.st.maxHp * dt, "blunt", null, null, 5, 3);
|
|
23825
24299
|
} else if (stress > 0.8 && p.mat.ductility < 0.3 && p.rt.stressT <= 0 && p.st.cracks.length < 6) {
|
|
@@ -24036,6 +24510,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
24036
24510
|
const r = raycastInternal(origin, direction, maxDistance);
|
|
24037
24511
|
return r ? { object: r.object, part: r.part, point: r.point, normal: r.normal, distance: r.distance } : null;
|
|
24038
24512
|
},
|
|
24513
|
+
sweepBox(box5, direction, distance3, options2 = {}) {
|
|
24514
|
+
const d = vec.normalize(direction);
|
|
24515
|
+
const ignored = options2.ignore === void 0 ? void 0 : objects.get(options2.ignore);
|
|
24516
|
+
const ignore = ignored ? new Set(ignored.parts.map((p) => `${ignored.id}\0${p.spec.id}`)) : void 0;
|
|
24517
|
+
let best = null;
|
|
24518
|
+
for (const origin of sweepOrigins(box5, d, options2.spacing ?? 0.2)) {
|
|
24519
|
+
const r = raycastInternal(origin, d, distance3 + SWEEP_BACK, ignore);
|
|
24520
|
+
if (!r || best && r.distance >= best.distance) continue;
|
|
24521
|
+
best = { object: r.object, part: r.part, point: r.point, normal: r.normal, distance: Math.max(0, r.distance - SWEEP_BACK) };
|
|
24522
|
+
}
|
|
24523
|
+
return best;
|
|
24524
|
+
},
|
|
24039
24525
|
shoot(origin, direction, energy, caliber, source, round5) {
|
|
24040
24526
|
const extras = typeof round5 === "number" ? { piercing: round5 } : round5 ?? {};
|
|
24041
24527
|
return withCollapses(run(() => {
|
|
@@ -25607,7 +26093,24 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
25607
26093
|
}
|
|
25608
26094
|
return spec;
|
|
25609
26095
|
};
|
|
25610
|
-
var
|
|
26096
|
+
var MEMBER_CAGE = { spacing: 0.1, diameter: 8e-3, unit: 0.1 };
|
|
26097
|
+
var CAGED_ROLES = /* @__PURE__ */ new Set(["beam", "column"]);
|
|
26098
|
+
var caged = (spec, part, rebar2) => {
|
|
26099
|
+
if (!rebar2 || part.material !== "concrete" || !CAGED_ROLES.has(part.role) || spec.reinforcement) return spec;
|
|
26100
|
+
const size = spec.shape.kind === "box" ? spec.shape.size : null;
|
|
26101
|
+
if (!size) return spec;
|
|
26102
|
+
const thin = Math.min(...size);
|
|
26103
|
+
return {
|
|
26104
|
+
...spec,
|
|
26105
|
+
reinforcement: { material: rebar2, spacing: MEMBER_CAGE.spacing, diameter: MEMBER_CAGE.diameter },
|
|
26106
|
+
units: { size: [MEMBER_CAGE.unit, MEMBER_CAGE.unit, thin], bond: "stack", mortar: "concrete" }
|
|
26107
|
+
};
|
|
26108
|
+
};
|
|
26109
|
+
var partSpecOf = (part, capacity, detailed, rebar2) => {
|
|
26110
|
+
if (detailed && part.assembly) return assemblySpec(part, capacity);
|
|
26111
|
+
const spec = boxSpec(part, capacity);
|
|
26112
|
+
return detailed ? caged(spec, part, rebar2) : spec;
|
|
26113
|
+
};
|
|
25611
26114
|
function toDestructibleSpec(structure, options = {}) {
|
|
25612
26115
|
const { safety = 0.65, redundancy = 0.97, safetyOthers = 0.45 } = options;
|
|
25613
26116
|
const kept = structure.parts.filter((part) => !options.filter || options.filter(part));
|
|
@@ -25624,7 +26127,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
25624
26127
|
const sizing = { safety, redundancy, safetyOthers };
|
|
25625
26128
|
const sized = { ...panels, capacities: options.sized === false ? /* @__PURE__ */ new Map() : sizeCapacities(panels.parts, panels.supports, sizing) };
|
|
25626
26129
|
const { parts, supports, capacities } = detail === "units" ? applyUnits(sized, structure) : sized;
|
|
25627
|
-
const specs = parts.map((part) => partSpecOf(part, capacities.get(part.id), detail !== "coarse"));
|
|
26130
|
+
const specs = parts.map((part) => partSpecOf(part, capacities.get(part.id), detail !== "coarse", structure.construction.frame.rebar));
|
|
25628
26131
|
const margin = options.terrainMargin ?? TERRAIN_MARGIN;
|
|
25629
26132
|
const x0 = Math.min(...parts.map((part) => part.aabb[0]));
|
|
25630
26133
|
const z0 = Math.min(...parts.map((part) => part.aabb[1]));
|
|
@@ -33260,12 +33763,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33260
33763
|
A.invalidate = () => {
|
|
33261
33764
|
for (let i = 0; i < NS; i++) PL[i].shadow.needsUpdate = true;
|
|
33262
33765
|
};
|
|
33263
|
-
A.update = function(
|
|
33766
|
+
A.update = function(houses2, focus, op) {
|
|
33264
33767
|
op = op || {};
|
|
33265
|
-
|
|
33768
|
+
houses2 = (Array.isArray(houses2) ? houses2 : [houses2]).filter(Boolean);
|
|
33266
33769
|
_f.set(focus.x, focus.y, focus.z);
|
|
33267
33770
|
const rooms = [], exterior = [];
|
|
33268
|
-
for (const house of
|
|
33771
|
+
for (const house of houses2) {
|
|
33269
33772
|
if (house.group && !house.group.visible) continue;
|
|
33270
33773
|
house.house.updateMatrixWorld(true);
|
|
33271
33774
|
const M = house.house.matrixWorld, by = /* @__PURE__ */ new Map();
|
|
@@ -33589,7 +34092,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33589
34092
|
if (!pc || pc.unit) return sp;
|
|
33590
34093
|
if (pc.role !== "wall" && pc.role !== "partition") {
|
|
33591
34094
|
const def = getAssembly(pc.assembly || (pc.material === "concrete" && ["slab", "beam", "column", "stair"].includes(pc.role) ? "reinforced_concrete" : ""));
|
|
33592
|
-
|
|
34095
|
+
const out = def && def.reinforcement && !sp.reinforcement ? { ...sp, reinforcement: { ...def.reinforcement } } : sp;
|
|
34096
|
+
if (out.reinforcement && !out.units && pc.material === "concrete" && (pc.role === "beam" || pc.role === "column") && sp.shape.kind === "box") {
|
|
34097
|
+
return { ...out, units: { size: [MEMBER_CAGE.unit, MEMBER_CAGE.unit, Math.min(...sp.shape.size)], bond: "stack", mortar: "concrete" } };
|
|
34098
|
+
}
|
|
34099
|
+
return out;
|
|
33593
34100
|
}
|
|
33594
34101
|
if (!pc.assembly) return sp;
|
|
33595
34102
|
const [u0, v0, u1, v1] = pc.aabb, alongU = u1 - u0 >= v1 - v0;
|
|
@@ -33644,7 +34151,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33644
34151
|
}
|
|
33645
34152
|
return null;
|
|
33646
34153
|
};
|
|
33647
|
-
|
|
34154
|
+
const local2 = (p) => {
|
|
34155
|
+
house.updateMatrixWorld(true);
|
|
34156
|
+
const v = house.worldToLocal(tmp.p.set(p[0], p[1], p[2]));
|
|
34157
|
+
return [v.x, v.y, v.z];
|
|
34158
|
+
};
|
|
34159
|
+
function courses(part, units, opening, chips2, paint2) {
|
|
33648
34160
|
const [u0, v0, u1, v1] = part.aabb;
|
|
33649
34161
|
const alongU = u1 - u0 >= v1 - v0;
|
|
33650
34162
|
const len = alongU ? u1 - u0 : v1 - v0;
|
|
@@ -33668,23 +34180,54 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33668
34180
|
const x = alongU ? u0 + mid : (u0 + u1) / 2;
|
|
33669
34181
|
const z = alongU ? (v0 + v1) / 2 : v0 + mid;
|
|
33670
34182
|
const y = part.y0 + (r + 0.5) * rowH;
|
|
33671
|
-
const d = Math.hypot(x - opening.center[0], y - opening.center[1], z - opening.center[2]);
|
|
33672
|
-
if (d < opening.radius) continue;
|
|
33673
|
-
|
|
34183
|
+
const d = opening ? Math.hypot(x - opening.center[0], y - opening.center[1], z - opening.center[2]) : Infinity;
|
|
34184
|
+
if (opening && d < opening.radius) continue;
|
|
34185
|
+
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);
|
|
34186
|
+
if (chips2.some(gone)) continue;
|
|
34187
|
+
const near = opening && d < opening.radius + 0.25 || chips2.some((c) => Math.hypot(c[0] - x, c[1] - y, c[2] - z) < 0.15);
|
|
34188
|
+
list2.push({ x, y, z, sx: alongU ? b - a : thick, sy: rowH, sz: alongU ? thick : b - a, colour: near || paint2 === null ? edge : paint2 });
|
|
33674
34189
|
}
|
|
33675
34190
|
}
|
|
33676
34191
|
return list2;
|
|
33677
34192
|
}
|
|
33678
|
-
|
|
33679
|
-
|
|
33680
|
-
|
|
33681
|
-
|
|
33682
|
-
|
|
33683
|
-
|
|
33684
|
-
|
|
33685
|
-
|
|
34193
|
+
const specOf = (id) => opts.spec()?.parts?.find((q) => q.id === id);
|
|
34194
|
+
const same = (a, b) => a.every((x, k) => Math.abs(x - b[k]) < 1e-3);
|
|
34195
|
+
function hostOf(partId) {
|
|
34196
|
+
if (structure.meshesOf(partId).some((it) => it.mesh)) return partId;
|
|
34197
|
+
const part = structure.byId.get(partId);
|
|
34198
|
+
if (!part) return null;
|
|
34199
|
+
for (const q of structure.parts) {
|
|
34200
|
+
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;
|
|
34201
|
+
}
|
|
34202
|
+
return null;
|
|
34203
|
+
}
|
|
34204
|
+
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);
|
|
34205
|
+
function draw2(partId, change) {
|
|
34206
|
+
if (lod !== 0) return false;
|
|
34207
|
+
const hostId = hostOf(partId);
|
|
34208
|
+
if (!hostId || !specOf(partId)?.units) return false;
|
|
34209
|
+
let view = views.get(hostId);
|
|
34210
|
+
if (!view) {
|
|
34211
|
+
const items = structure.meshesOf(hostId).filter((it) => it.mesh);
|
|
34212
|
+
if (!items.length) return false;
|
|
34213
|
+
const parts = [hostId, ...riders(hostId)].filter((id) => structure.byId.get(id) && specOf(id)?.units);
|
|
34214
|
+
view = { mesh: null, saved: null, items, paint: wallColour(items), units: 0, opening: null, chips: new Map(parts.map((id) => [id, []])), openings: /* @__PURE__ */ new Map() };
|
|
34215
|
+
}
|
|
34216
|
+
if (!view.chips.has(partId)) return false;
|
|
34217
|
+
if (change.opening) {
|
|
34218
|
+
if (view.openings.has(partId)) return false;
|
|
34219
|
+
view.openings.set(partId, { center: local2(change.opening.center), radius: change.opening.radius });
|
|
34220
|
+
if (partId === hostId) view.opening = view.openings.get(partId);
|
|
34221
|
+
}
|
|
34222
|
+
if (change.chip) view.chips.get(partId).push(local2(change.chip));
|
|
34223
|
+
const list2 = [];
|
|
34224
|
+
for (const [id, chips2] of view.chips) list2.push(...courses(structure.byId.get(id), specOf(id).units, view.openings.get(id) ?? null, chips2, view.paint));
|
|
34225
|
+
if (view.mesh) {
|
|
34226
|
+
view.mesh.removeFromParent();
|
|
34227
|
+
view.mesh.dispose();
|
|
34228
|
+
}
|
|
33686
34229
|
const mesh3 = new THREE.InstancedMesh(unitGeometry, unitMaterial, Math.max(1, list2.length));
|
|
33687
|
-
mesh3.name = "breach:" +
|
|
34230
|
+
mesh3.name = "breach:" + hostId;
|
|
33688
34231
|
list2.forEach((u, i) => {
|
|
33689
34232
|
tmp.m.compose(tmp.p.set(u.x, u.y, u.z), tmp.q.identity(), tmp.s.set(u.sx, u.sy, u.sz));
|
|
33690
34233
|
mesh3.setMatrixAt(i, tmp.m);
|
|
@@ -33696,8 +34239,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33696
34239
|
mesh3.castShadow = true;
|
|
33697
34240
|
mesh3.receiveShadow = true;
|
|
33698
34241
|
house.add(mesh3);
|
|
33699
|
-
|
|
33700
|
-
|
|
34242
|
+
if (!view.saved) view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
34243
|
+
view.mesh = mesh3;
|
|
34244
|
+
view.units = list2.length;
|
|
34245
|
+
views.set(hostId, view);
|
|
33701
34246
|
invalidate();
|
|
33702
34247
|
invalidateShadow();
|
|
33703
34248
|
return true;
|
|
@@ -33711,7 +34256,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33711
34256
|
return {
|
|
33712
34257
|
/** Handles a `stage` event of the house's object. Returns true when the wall was redrawn as courses. */
|
|
33713
34258
|
stage(event) {
|
|
33714
|
-
return event.stage === 2 ?
|
|
34259
|
+
return event.stage === 2 && !!event.opening ? draw2(event.part, { opening: event.opening }) : false;
|
|
34260
|
+
},
|
|
34261
|
+
/** Handles a `chip` event: the unit that came out leaves a gap in the courses. Returns true when the wall was redrawn. */
|
|
34262
|
+
chip(event) {
|
|
34263
|
+
return draw2(event.part, { chip: event.center });
|
|
33715
34264
|
},
|
|
33716
34265
|
/** The part broke or fell: the courses go (the plain range stays collapsed, the renderer hides the part). */
|
|
33717
34266
|
drop(partId) {
|
|
@@ -33941,6 +34490,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33941
34490
|
case "stage":
|
|
33942
34491
|
breach.stage(e);
|
|
33943
34492
|
break;
|
|
34493
|
+
case "chip":
|
|
34494
|
+
breach.chip(e);
|
|
34495
|
+
break;
|
|
33944
34496
|
case "collapse":
|
|
33945
34497
|
for (const id of e.parts) {
|
|
33946
34498
|
breach.drop(id);
|
|
@@ -33995,6 +34547,32 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33995
34547
|
if (D.active && D.world.has(D.id)) D.world.remove(D.id);
|
|
33996
34548
|
D.active = false;
|
|
33997
34549
|
};
|
|
34550
|
+
D.follow = (world, id, spec) => {
|
|
34551
|
+
D.spec = spec;
|
|
34552
|
+
const offFollow = world.on("*", (e) => {
|
|
34553
|
+
if (e.object !== id) return;
|
|
34554
|
+
switch (e.type) {
|
|
34555
|
+
case "stage":
|
|
34556
|
+
breach.stage(e);
|
|
34557
|
+
break;
|
|
34558
|
+
case "chip":
|
|
34559
|
+
breach.chip(e);
|
|
34560
|
+
break;
|
|
34561
|
+
case "fracture":
|
|
34562
|
+
breach.drop(e.part);
|
|
34563
|
+
break;
|
|
34564
|
+
case "collapse":
|
|
34565
|
+
for (const p of e.parts) breach.drop(p);
|
|
34566
|
+
break;
|
|
34567
|
+
default:
|
|
34568
|
+
break;
|
|
34569
|
+
}
|
|
34570
|
+
});
|
|
34571
|
+
return { restore: () => breach.restore(), dispose: () => {
|
|
34572
|
+
offFollow();
|
|
34573
|
+
breach.restore();
|
|
34574
|
+
} };
|
|
34575
|
+
};
|
|
33998
34576
|
D.piece = (id) => D.active ? D.world.part(D.id, id) : null;
|
|
33999
34577
|
D.state = () => D.active ? D.world.state(D.id) : null;
|
|
34000
34578
|
D.reset = () => {
|
|
@@ -34717,6 +35295,56 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34717
35295
|
return buildApi(K, shared);
|
|
34718
35296
|
}
|
|
34719
35297
|
var WOOD_THIN = 0.035;
|
|
35298
|
+
var BOARD_TOP_THICK = 0.07;
|
|
35299
|
+
var BOARD_TOP_WIDTH = 0.5;
|
|
35300
|
+
var BOARD_WIDTH = 0.16;
|
|
35301
|
+
var SHELF_SPAN = 1.5;
|
|
35302
|
+
var SHELVING = /shelf|bookcase|rack/;
|
|
35303
|
+
function carcass(parts, drawn) {
|
|
35304
|
+
const all = [...drawn.values()];
|
|
35305
|
+
const width = Math.max(...all.map((p) => p.max[0])) - Math.min(...all.map((p) => p.min[0]));
|
|
35306
|
+
for (const part of parts) {
|
|
35307
|
+
if (LOOSE.has(part.material) || part.shape.kind !== "box" || part.rotation) continue;
|
|
35308
|
+
const [x, y, z] = part.shape.size;
|
|
35309
|
+
if (y >= x && y >= z) {
|
|
35310
|
+
if (z < x && x >= 0.6 * width) continue;
|
|
35311
|
+
part.structure = { role: "column" };
|
|
35312
|
+
} else if (y <= x && y <= z) part.structure = { role: "beam", maxSpan: SHELF_SPAN * Math.max(x, z) };
|
|
35313
|
+
}
|
|
35314
|
+
}
|
|
35315
|
+
function splitTopsIntoBoards(drawn, materialOf2, carcassed) {
|
|
35316
|
+
const tops = /* @__PURE__ */ new Map();
|
|
35317
|
+
if (carcassed) return tops;
|
|
35318
|
+
for (let i = drawn.length - 1; i >= 0; i--) {
|
|
35319
|
+
const p = drawn[i];
|
|
35320
|
+
if (p.key !== "wood" || materialOf2.wood !== "wood_hard" || p.shape.kind !== "box" || p.rotation) continue;
|
|
35321
|
+
const [sx, sy, sz] = p.shape.size;
|
|
35322
|
+
const across2 = sx < sz ? 0 : 2;
|
|
35323
|
+
const width = Math.min(sx, sz);
|
|
35324
|
+
if (sy < WOOD_THIN || sy > BOARD_TOP_THICK || sy >= width || width < BOARD_TOP_WIDTH) continue;
|
|
35325
|
+
const count = Math.round(width / BOARD_WIDTH);
|
|
35326
|
+
const boards = [];
|
|
35327
|
+
for (let b = 0; b < count; b++) {
|
|
35328
|
+
const size = [sx, sy, sz];
|
|
35329
|
+
size[across2] = width / count;
|
|
35330
|
+
const position = [...p.position];
|
|
35331
|
+
position[across2] += (b + 0.5) * size[across2] - width / 2;
|
|
35332
|
+
const min2 = [...p.min];
|
|
35333
|
+
const max2 = [...p.max];
|
|
35334
|
+
min2[across2] = position[across2] - size[across2] / 2;
|
|
35335
|
+
max2[across2] = position[across2] + size[across2] / 2;
|
|
35336
|
+
boards.push({ ...p, id: `${p.id}_b${b}`, shape: { kind: "box", size }, position, min: min2, max: max2, color: shadeBoard(p.color, b) });
|
|
35337
|
+
}
|
|
35338
|
+
drawn.splice(i, 1, ...boards);
|
|
35339
|
+
tops.set(p.id, boards);
|
|
35340
|
+
}
|
|
35341
|
+
return tops;
|
|
35342
|
+
}
|
|
35343
|
+
function shadeBoard(color2, board) {
|
|
35344
|
+
const k = [1, 0.94, 1.05, 0.97, 1.03][board % 5];
|
|
35345
|
+
const channel = (shift) => Math.min(255, Math.round((color2 >> shift & 255) * k)) << shift;
|
|
35346
|
+
return channel(16) | channel(8) | channel(0);
|
|
35347
|
+
}
|
|
34720
35348
|
var FLOOR_TOUCH = 5e-3;
|
|
34721
35349
|
var LOOSE = /* @__PURE__ */ new Set(["paper"]);
|
|
34722
35350
|
var BASE_MATERIAL = {
|
|
@@ -34794,10 +35422,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34794
35422
|
};
|
|
34795
35423
|
run(A);
|
|
34796
35424
|
if (!drawn.length) throw new Error(`game-floorplan-three: the builder of "${name}" drew no box or cylinder`);
|
|
35425
|
+
const boardsOf = splitTopsIntoBoards(drawn, materialOf2, Boolean(opts.carcass));
|
|
34797
35426
|
const parts = drawn.map((p) => {
|
|
34798
35427
|
const thin = Math.min(...p.shape.kind === "box" ? p.shape.size : p.shape.kind === "cylinder" ? [p.shape.radius * 2, p.shape.height] : [p.shape.radius * 2]);
|
|
34799
35428
|
let material = materialOf2[p.key] ?? "plastic";
|
|
34800
|
-
if (p.key === "wood" && material === "wood_hard" &&
|
|
35429
|
+
if (p.key === "wood" && material === "wood_hard" && opts.carcass && !opts.materials?.wood) material = "mdf";
|
|
35430
|
+
else if (p.key === "wood" && material === "wood_hard" && thin < WOOD_THIN) material = "wood_soft";
|
|
34801
35431
|
const part = { id: p.id, material, shape: p.shape, position: p.position };
|
|
34802
35432
|
if (p.rotation) part.rotation = p.rotation;
|
|
34803
35433
|
if (!LOOSE.has(material) && p.min[1] <= FLOOR_TOUCH) part.anchored = true;
|
|
@@ -34832,6 +35462,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34832
35462
|
if (area3 < 0.6 * footprint || p.max[1] < 0.2) continue;
|
|
34833
35463
|
if (!top || p.max[1] > top.y + 1e-6) top = { part: p.id, y: p.max[1] };
|
|
34834
35464
|
}
|
|
35465
|
+
for (const boards of boardsOf.values()) {
|
|
35466
|
+
if (top && boards[0].max[1] <= top.y - 1e-6) continue;
|
|
35467
|
+
const mid = boards[boards.length >> 1];
|
|
35468
|
+
const min2 = [Math.min(...boards.map((b) => b.min[0])), Math.min(...boards.map((b) => b.min[2]))];
|
|
35469
|
+
const max2 = [Math.max(...boards.map((b) => b.max[0])), Math.max(...boards.map((b) => b.max[2]))];
|
|
35470
|
+
if ((max2[0] - min2[0]) * (max2[1] - min2[1]) >= 0.6 * footprint && mid.max[1] >= 0.2) top = { part: mid.id, y: mid.max[1], parts: boards.map((b) => b.id) };
|
|
35471
|
+
}
|
|
35472
|
+
if (opts.carcass) carcass(parts, byId);
|
|
34835
35473
|
const spec = { name, parts, joints, tags: ["furniture"] };
|
|
34836
35474
|
const colors = new Map(drawn.map((p) => [p.id, p.color]));
|
|
34837
35475
|
const build = (T3) => {
|
|
@@ -34875,7 +35513,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34875
35513
|
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`);
|
|
34876
35514
|
const o = opts.options ?? {};
|
|
34877
35515
|
const seed = Math.round(opts.seed ?? 1);
|
|
34878
|
-
const plain2 =
|
|
35516
|
+
const plain2 = SHELVING.test(type) ? "paper" : "plastic";
|
|
34879
35517
|
const root = { x: seed, z: 0, ry: 0, w, d, h, y: 0, base: 0, palette: o.palette, seed: `furniture_${type}_${seed}` };
|
|
34880
35518
|
const { K, shared } = renderer.internals;
|
|
34881
35519
|
const before = K.PARTS.length;
|
|
@@ -34894,7 +35532,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34894
35532
|
shared.ctx = saved.ctx;
|
|
34895
35533
|
}
|
|
34896
35534
|
},
|
|
34897
|
-
{ materials: { plain: plain2, ...o.materials }, chairs: o.chairs }
|
|
35535
|
+
{ materials: { plain: plain2, ...o.materials }, chairs: o.chairs, carcass: SHELVING.test(type) }
|
|
34898
35536
|
);
|
|
34899
35537
|
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]);
|
|
34900
35538
|
K.PARTS.length = before;
|
|
@@ -38885,14 +39523,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38885
39523
|
},
|
|
38886
39524
|
tessellate: {
|
|
38887
39525
|
cylinder: {
|
|
38888
|
-
heightSegments:
|
|
38889
|
-
radialSegments:
|
|
39526
|
+
heightSegments: 24,
|
|
39527
|
+
radialSegments: 40,
|
|
39528
|
+
capRings: 6
|
|
38890
39529
|
},
|
|
38891
39530
|
box: {
|
|
38892
39531
|
widthSegments: 6,
|
|
38893
39532
|
heightSegments: 1,
|
|
38894
39533
|
depthSegments: 4
|
|
38895
39534
|
}
|
|
39535
|
+
},
|
|
39536
|
+
wall: {
|
|
39537
|
+
body: 1e-4,
|
|
39538
|
+
ends: 25e-5
|
|
38896
39539
|
}
|
|
38897
39540
|
}
|
|
38898
39541
|
},
|
|
@@ -38916,14 +39559,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38916
39559
|
},
|
|
38917
39560
|
tessellate: {
|
|
38918
39561
|
cylinder: {
|
|
38919
|
-
heightSegments:
|
|
38920
|
-
radialSegments:
|
|
39562
|
+
heightSegments: 24,
|
|
39563
|
+
radialSegments: 40,
|
|
39564
|
+
capRings: 6
|
|
38921
39565
|
},
|
|
38922
39566
|
box: {
|
|
38923
39567
|
widthSegments: 6,
|
|
38924
39568
|
heightSegments: 1,
|
|
38925
39569
|
depthSegments: 4
|
|
38926
39570
|
}
|
|
39571
|
+
},
|
|
39572
|
+
wall: {
|
|
39573
|
+
body: 18e-5,
|
|
39574
|
+
ends: 22e-5
|
|
38927
39575
|
}
|
|
38928
39576
|
}
|
|
38929
39577
|
}
|
|
@@ -39013,12 +39661,53 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39013
39661
|
if (!box22) return 0;
|
|
39014
39662
|
return (box22.max.x - box22.min.x) * (box22.max.y - box22.min.y) * (box22.max.z - box22.min.z);
|
|
39015
39663
|
}
|
|
39016
|
-
function
|
|
39664
|
+
function ringedCylinder(T2, p, radial, maxRows, rings) {
|
|
39665
|
+
const half = p.height / 2;
|
|
39666
|
+
const column = 2 * Math.PI * Math.max(p.radiusTop, p.radiusBottom, 1e-6) / radial;
|
|
39667
|
+
const rows = Math.max(1, Math.min(maxRows, Math.round(p.height / column)));
|
|
39668
|
+
const points = [];
|
|
39669
|
+
if (!p.openEnded) for (let i = 0; i <= rings; i++) points.push(new T2.Vector2(p.radiusBottom * i / rings, -half));
|
|
39670
|
+
for (let j = 0; j <= rows; j++) points.push(new T2.Vector2(p.radiusBottom + (p.radiusTop - p.radiusBottom) * j / rows, -half + p.height * j / rows));
|
|
39671
|
+
if (!p.openEnded) for (let i = rings; i >= 0; i--) points.push(new T2.Vector2(p.radiusTop * i / rings, half));
|
|
39672
|
+
return lathed(T2, points, radial, p.thetaStart, p.thetaLength);
|
|
39673
|
+
}
|
|
39674
|
+
function lathed(T2, points, radial, phiStart, phiLength) {
|
|
39675
|
+
const geometry = new T2.LatheGeometry([...points], radial, phiStart, phiLength);
|
|
39676
|
+
geometry.computeVertexNormals();
|
|
39677
|
+
const position = geometry.getAttribute("position");
|
|
39678
|
+
const normal = geometry.getAttribute("normal");
|
|
39679
|
+
const middle = (Math.min(...points.map((point) => point.y)) + Math.max(...points.map((point) => point.y))) / 2;
|
|
39680
|
+
for (let i = 0; i < normal.count; i++) {
|
|
39681
|
+
if (Math.hypot(normal.getX(i), normal.getY(i), normal.getZ(i)) > 0.5) continue;
|
|
39682
|
+
normal.setXYZ(i, 0, position.getY(i) >= middle ? 1 : -1, 0);
|
|
39683
|
+
}
|
|
39684
|
+
return geometry;
|
|
39685
|
+
}
|
|
39686
|
+
function finerProfile(T2, points, step) {
|
|
39687
|
+
const out = [];
|
|
39688
|
+
points.forEach((point, index) => {
|
|
39689
|
+
const next = points[index + 1];
|
|
39690
|
+
out.push(point.clone());
|
|
39691
|
+
if (!next) return;
|
|
39692
|
+
const pieces = Math.max(1, Math.round(point.distanceTo(next) / step));
|
|
39693
|
+
for (let k = 1; k < pieces; k++) out.push(point.clone().lerp(next, k / pieces));
|
|
39694
|
+
});
|
|
39695
|
+
return out;
|
|
39696
|
+
}
|
|
39697
|
+
function tessellated(geometry, rule, T2) {
|
|
39017
39698
|
const Shape = geometry.constructor;
|
|
39018
39699
|
if (geometry.type === "CylinderGeometry" && rule.cylinder) {
|
|
39019
|
-
const
|
|
39700
|
+
const parameters = geometry.parameters;
|
|
39701
|
+
const { radiusTop, radiusBottom, height, openEnded, thetaStart, thetaLength } = parameters;
|
|
39702
|
+
if (T2 && rule.cylinder.capRings !== void 0) return ringedCylinder(T2, parameters, rule.cylinder.radialSegments, rule.cylinder.heightSegments, rule.cylinder.capRings);
|
|
39020
39703
|
return new Shape(radiusTop, radiusBottom, height, rule.cylinder.radialSegments, rule.cylinder.heightSegments, openEnded, thetaStart, thetaLength);
|
|
39021
39704
|
}
|
|
39705
|
+
if (geometry.type === "LatheGeometry" && rule.cylinder && T2 && rule.cylinder.capRings !== void 0) {
|
|
39706
|
+
const { points, segments, phiStart, phiLength } = geometry.parameters;
|
|
39707
|
+
if (segments >= rule.cylinder.radialSegments) return void 0;
|
|
39708
|
+
const widest = Math.max(...points.map((point) => point.x), 1e-6);
|
|
39709
|
+
return lathed(T2, finerProfile(T2, points, 2 * Math.PI * widest / rule.cylinder.radialSegments), rule.cylinder.radialSegments, phiStart, phiLength);
|
|
39710
|
+
}
|
|
39022
39711
|
if (geometry.type === "BoxGeometry" && rule.box) {
|
|
39023
39712
|
const { width, height, depth } = geometry.parameters;
|
|
39024
39713
|
return new Shape(width, height, depth, rule.box.widthSegments, rule.box.heightSegments, rule.box.depthSegments);
|
|
@@ -39026,14 +39715,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39026
39715
|
return void 0;
|
|
39027
39716
|
}
|
|
39028
39717
|
var triangleCount = (geometry) => (geometry.index ? geometry.index.count : geometry.getAttribute("position").count) / 3;
|
|
39029
|
-
function tessellateShapes(root, rule) {
|
|
39718
|
+
function tessellateShapes(root, rule, T2) {
|
|
39030
39719
|
const rebuilt = /* @__PURE__ */ new Map();
|
|
39031
39720
|
root.traverse((object2) => {
|
|
39032
39721
|
const mesh3 = object2;
|
|
39033
39722
|
if (!mesh3.isMesh) return;
|
|
39034
39723
|
let fresh = rebuilt.get(mesh3.geometry);
|
|
39035
39724
|
if (!fresh) {
|
|
39036
|
-
fresh = tessellated(mesh3.geometry, rule);
|
|
39725
|
+
fresh = tessellated(mesh3.geometry, rule, T2);
|
|
39037
39726
|
if (!fresh) return;
|
|
39038
39727
|
rebuilt.set(mesh3.geometry, fresh);
|
|
39039
39728
|
}
|
|
@@ -39047,10 +39736,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39047
39736
|
root.userData.tessellationTriangles = added;
|
|
39048
39737
|
}
|
|
39049
39738
|
function tagForDestruction(root, options = {}) {
|
|
39050
|
-
const { modelId, weight, size } = options;
|
|
39739
|
+
const { modelId, weight, size, three } = options;
|
|
39051
39740
|
if (weight !== void 0 && weight > 0) root.userData.destructionMass = weight;
|
|
39052
39741
|
const rule = modelId === void 0 ? void 0 : itemDestruction(modelId);
|
|
39053
|
-
if (rule?.tessellate) tessellateShapes(root, rule.tessellate);
|
|
39742
|
+
if (rule?.tessellate) tessellateShapes(root, rule.tessellate, three);
|
|
39054
39743
|
const solid2 = [];
|
|
39055
39744
|
root.traverse((object2) => {
|
|
39056
39745
|
const mesh3 = object2;
|
|
@@ -39070,6 +39759,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39070
39759
|
const anchor = solid2.reduce((largest, mesh3) => volumeOf(mesh3) > volumeOf(largest) ? mesh3 : largest);
|
|
39071
39760
|
solid2.forEach((mesh3, index) => {
|
|
39072
39761
|
mesh3.userData.destructionPart = mesh3 === anchor ? { id: SHELL_PART_ID } : { id: `shell_${index}`, parent: SHELL_PART_ID, kind: "weld" };
|
|
39762
|
+
if (rule.wall) mesh3.userData.destructionThickness = mesh3 === anchor ? rule.wall.body : rule.wall.ends;
|
|
39073
39763
|
});
|
|
39074
39764
|
const contents = size === void 0 ? void 0 : itemContents({ ...modelId === void 0 ? {} : { model: modelId }, size, ...weight === void 0 ? {} : { weight } });
|
|
39075
39765
|
if (contents) anchor.userData.destructionContains = { fluid: contents.liquid, liters: contents.liters };
|
|
@@ -44681,7 +45371,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
44681
45371
|
const materials = kit.materials.slice(first);
|
|
44682
45372
|
if (options.wear) setWear(materials, options.wear);
|
|
44683
45373
|
root.userData.wear = options.wear ?? 0;
|
|
44684
|
-
if (options.destructible) tagForDestruction(root, { ...kind === "model" && item.model !== void 0 ? { modelId: item.model } : {}, ...item.weight === void 0 ? {} : { weight: item.weight }, size: item.size });
|
|
45374
|
+
if (options.destructible) tagForDestruction(root, { ...kind === "model" && item.model !== void 0 ? { modelId: item.model } : {}, ...item.weight === void 0 ? {} : { weight: item.weight }, size: item.size, three: T2 });
|
|
44685
45375
|
markKitOrigin(root, { owner: "game-items-three", kind: "item", id: item.id, ...kind === "shape" ? { standIn: true } : {} });
|
|
44686
45376
|
return { root, kind, ...shape ? { shape } : {}, size: item.size, materials };
|
|
44687
45377
|
}
|
|
@@ -60161,6 +60851,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
60161
60851
|
return {
|
|
60162
60852
|
id: "weapons_area",
|
|
60163
60853
|
name: text.name,
|
|
60854
|
+
ground: { surface: "concrete_slab" },
|
|
60164
60855
|
group: text.group,
|
|
60165
60856
|
get audio() {
|
|
60166
60857
|
return audio;
|
|
@@ -61223,6 +61914,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
61223
61914
|
return {
|
|
61224
61915
|
id: EXPLOSIVES_AREA_ID,
|
|
61225
61916
|
name: text.name,
|
|
61917
|
+
ground: { surface: "concrete_slab" },
|
|
61226
61918
|
group: text.group,
|
|
61227
61919
|
bench,
|
|
61228
61920
|
// the cylinder of this area is the world explosive of the weapons module with the bench's strength: the same id, the same model, the same part
|