@adatechnology/game-weapons-three 0.10.1 → 0.10.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 +745 -122
- 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
|
@@ -19717,7 +19717,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19717
19717
|
const band = { c: [root.c[0], root.c[1], root.c[2]], s: [dims[0], dims[1], dims[2]] };
|
|
19718
19718
|
band.c[L] = (lo + hi) / 2;
|
|
19719
19719
|
band.s[L] = Math.max(hi - lo, 0.01);
|
|
19720
|
-
|
|
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);
|
|
19721
19723
|
return out;
|
|
19722
19724
|
};
|
|
19723
19725
|
var tearStack = (inp, root, t, u, v, n, sheet) => {
|
|
@@ -19748,6 +19750,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19748
19750
|
const t = sorted[0];
|
|
19749
19751
|
const [u, v] = [sorted[1], sorted[2]].sort((a, b) => a - b);
|
|
19750
19752
|
if (style === "snap") {
|
|
19753
|
+
if (inp.cut) return severAt(inp, root, inp.cut.at, inp.cut.gap);
|
|
19751
19754
|
const n2 = Math.min(maxFragments, 2 + Math.floor(rnd2() * 3));
|
|
19752
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] });
|
|
19753
19756
|
return out;
|
|
@@ -19921,6 +19924,27 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
19921
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]]));
|
|
19922
19925
|
return out;
|
|
19923
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
|
+
};
|
|
19924
19948
|
var clipBarsToDisc = (bars, u, v, center, radius) => {
|
|
19925
19949
|
const out = [];
|
|
19926
19950
|
for (const [a, b] of bars) {
|
|
@@ -20841,14 +20865,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20841
20865
|
smoke: "grey"
|
|
20842
20866
|
},
|
|
20843
20867
|
visual: {
|
|
20844
|
-
charColor: 1709072
|
|
20868
|
+
charColor: 1709072,
|
|
20869
|
+
innerColor: 14730131
|
|
20845
20870
|
},
|
|
20846
20871
|
tags: [
|
|
20847
20872
|
"wood",
|
|
20848
20873
|
"organic",
|
|
20849
20874
|
"flammable"
|
|
20850
20875
|
],
|
|
20851
|
-
compressive: 1e5
|
|
20876
|
+
compressive: 1e5,
|
|
20877
|
+
hits: {
|
|
20878
|
+
blunt: {
|
|
20879
|
+
tear: "splinters",
|
|
20880
|
+
tearJoules: 60
|
|
20881
|
+
}
|
|
20882
|
+
}
|
|
20852
20883
|
},
|
|
20853
20884
|
{
|
|
20854
20885
|
id: "wood_hard",
|
|
@@ -20878,14 +20909,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20878
20909
|
smoke: "grey"
|
|
20879
20910
|
},
|
|
20880
20911
|
visual: {
|
|
20881
|
-
charColor: 1709072
|
|
20912
|
+
charColor: 1709072,
|
|
20913
|
+
innerColor: 13213802
|
|
20882
20914
|
},
|
|
20883
20915
|
tags: [
|
|
20884
20916
|
"wood",
|
|
20885
20917
|
"organic",
|
|
20886
20918
|
"flammable"
|
|
20887
20919
|
],
|
|
20888
|
-
compressive: 15e4
|
|
20920
|
+
compressive: 15e4,
|
|
20921
|
+
hits: {
|
|
20922
|
+
blunt: {
|
|
20923
|
+
tear: "splinters",
|
|
20924
|
+
tearJoules: 150
|
|
20925
|
+
}
|
|
20926
|
+
}
|
|
20889
20927
|
},
|
|
20890
20928
|
{
|
|
20891
20929
|
id: "plywood",
|
|
@@ -20915,14 +20953,24 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20915
20953
|
smoke: "grey"
|
|
20916
20954
|
},
|
|
20917
20955
|
visual: {
|
|
20918
|
-
charColor: 1709072
|
|
20956
|
+
charColor: 1709072,
|
|
20957
|
+
innerColor: 14862234
|
|
20919
20958
|
},
|
|
20920
20959
|
tags: [
|
|
20921
20960
|
"wood",
|
|
20922
20961
|
"organic",
|
|
20923
20962
|
"flammable"
|
|
20924
20963
|
],
|
|
20925
|
-
compressive: 6e4
|
|
20964
|
+
compressive: 6e4,
|
|
20965
|
+
hits: {
|
|
20966
|
+
ballistic: {
|
|
20967
|
+
tear: "splinters"
|
|
20968
|
+
},
|
|
20969
|
+
blunt: {
|
|
20970
|
+
tear: "splinters",
|
|
20971
|
+
tearJoules: 80
|
|
20972
|
+
}
|
|
20973
|
+
}
|
|
20926
20974
|
},
|
|
20927
20975
|
{
|
|
20928
20976
|
id: "mdf",
|
|
@@ -20949,14 +20997,25 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
20949
20997
|
smoke: "grey"
|
|
20950
20998
|
},
|
|
20951
20999
|
visual: {
|
|
20952
|
-
charColor: 1709072
|
|
21000
|
+
charColor: 1709072,
|
|
21001
|
+
innerColor: 12096362
|
|
20953
21002
|
},
|
|
20954
21003
|
tags: [
|
|
20955
21004
|
"wood",
|
|
20956
21005
|
"organic",
|
|
20957
21006
|
"flammable"
|
|
20958
21007
|
],
|
|
20959
|
-
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
|
+
}
|
|
20960
21019
|
},
|
|
20961
21020
|
{
|
|
20962
21021
|
id: "glass",
|
|
@@ -21070,8 +21129,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21070
21129
|
damageScale: {
|
|
21071
21130
|
explosive: 1.2
|
|
21072
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
|
+
},
|
|
21073
21143
|
hitDebris: "chips",
|
|
21074
21144
|
breakDebris: "dust",
|
|
21145
|
+
visual: { innerColor: 10197652 },
|
|
21075
21146
|
thermal: {
|
|
21076
21147
|
conductivity: 0.15,
|
|
21077
21148
|
heatCapacity: 2.5
|
|
@@ -21102,6 +21173,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21102
21173
|
],
|
|
21103
21174
|
hitDebris: "chips",
|
|
21104
21175
|
breakDebris: "dust",
|
|
21176
|
+
visual: { innerColor: 12085567 },
|
|
21105
21177
|
thermal: {
|
|
21106
21178
|
conductivity: 0.15,
|
|
21107
21179
|
heatCapacity: 2.5
|
|
@@ -21132,6 +21204,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21132
21204
|
],
|
|
21133
21205
|
hitDebris: "dust",
|
|
21134
21206
|
breakDebris: "dust",
|
|
21207
|
+
visual: { innerColor: 14999507 },
|
|
21135
21208
|
thermal: {
|
|
21136
21209
|
conductivity: 0.1,
|
|
21137
21210
|
heatCapacity: 1.5
|
|
@@ -21157,6 +21230,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21157
21230
|
],
|
|
21158
21231
|
hitDebris: "chips",
|
|
21159
21232
|
breakDebris: "dust",
|
|
21233
|
+
visual: { innerColor: 9407364 },
|
|
21160
21234
|
thermal: {
|
|
21161
21235
|
conductivity: 0.2,
|
|
21162
21236
|
heatCapacity: 2.5
|
|
@@ -21438,7 +21512,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21438
21512
|
smoke: "white"
|
|
21439
21513
|
},
|
|
21440
21514
|
visual: {
|
|
21441
|
-
charColor: 1709072
|
|
21515
|
+
charColor: 1709072,
|
|
21516
|
+
innerColor: 14207126
|
|
21442
21517
|
},
|
|
21443
21518
|
tags: [
|
|
21444
21519
|
"plant",
|
|
@@ -21446,7 +21521,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21446
21521
|
"organic",
|
|
21447
21522
|
"flammable"
|
|
21448
21523
|
],
|
|
21449
|
-
compressive: 6e4
|
|
21524
|
+
compressive: 6e4,
|
|
21525
|
+
hits: {
|
|
21526
|
+
blunt: {
|
|
21527
|
+
tear: "none"
|
|
21528
|
+
}
|
|
21529
|
+
}
|
|
21450
21530
|
},
|
|
21451
21531
|
{
|
|
21452
21532
|
id: "cactus",
|
|
@@ -21561,6 +21641,130 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21561
21641
|
"masonry"
|
|
21562
21642
|
],
|
|
21563
21643
|
compressive: 2e4
|
|
21644
|
+
},
|
|
21645
|
+
{
|
|
21646
|
+
id: "asphalt",
|
|
21647
|
+
density: 2350,
|
|
21648
|
+
hpPerKg: 10,
|
|
21649
|
+
penetration: 14,
|
|
21650
|
+
penetrationClass: "concrete",
|
|
21651
|
+
penetrationScale: 0.8,
|
|
21652
|
+
ductility: 0.1,
|
|
21653
|
+
fracture: "crumble",
|
|
21654
|
+
fragmentSize: [
|
|
21655
|
+
0.03,
|
|
21656
|
+
0.15
|
|
21657
|
+
],
|
|
21658
|
+
hitDebris: "chips",
|
|
21659
|
+
breakDebris: "dust",
|
|
21660
|
+
thermal: {
|
|
21661
|
+
conductivity: 0.1,
|
|
21662
|
+
heatCapacity: 2,
|
|
21663
|
+
ignitionC: 400,
|
|
21664
|
+
burnRate: 2e-3,
|
|
21665
|
+
smoke: "black"
|
|
21666
|
+
},
|
|
21667
|
+
tags: [
|
|
21668
|
+
"masonry",
|
|
21669
|
+
"brittle"
|
|
21670
|
+
],
|
|
21671
|
+
compressive: 3e4
|
|
21672
|
+
},
|
|
21673
|
+
{
|
|
21674
|
+
id: "sand",
|
|
21675
|
+
density: 1600,
|
|
21676
|
+
hpPerKg: 2,
|
|
21677
|
+
penetration: 6,
|
|
21678
|
+
ductility: 0.4,
|
|
21679
|
+
fracture: "crumble",
|
|
21680
|
+
fragmentSize: [
|
|
21681
|
+
0.01,
|
|
21682
|
+
0.04
|
|
21683
|
+
],
|
|
21684
|
+
hitDebris: "dust",
|
|
21685
|
+
breakDebris: "dust",
|
|
21686
|
+
thermal: {
|
|
21687
|
+
conductivity: 0.1,
|
|
21688
|
+
heatCapacity: 2
|
|
21689
|
+
},
|
|
21690
|
+
tags: [
|
|
21691
|
+
"soil"
|
|
21692
|
+
],
|
|
21693
|
+
compressive: 1e4
|
|
21694
|
+
},
|
|
21695
|
+
{
|
|
21696
|
+
id: "gravel",
|
|
21697
|
+
density: 1800,
|
|
21698
|
+
hpPerKg: 3,
|
|
21699
|
+
penetration: 8,
|
|
21700
|
+
ductility: 0.3,
|
|
21701
|
+
fracture: "crumble",
|
|
21702
|
+
fragmentSize: [
|
|
21703
|
+
0.02,
|
|
21704
|
+
0.06
|
|
21705
|
+
],
|
|
21706
|
+
hitDebris: "chips",
|
|
21707
|
+
breakDebris: "dust",
|
|
21708
|
+
thermal: {
|
|
21709
|
+
conductivity: 0.1,
|
|
21710
|
+
heatCapacity: 2
|
|
21711
|
+
},
|
|
21712
|
+
tags: [
|
|
21713
|
+
"soil",
|
|
21714
|
+
"masonry"
|
|
21715
|
+
],
|
|
21716
|
+
compressive: 2e4
|
|
21717
|
+
},
|
|
21718
|
+
{
|
|
21719
|
+
id: "turf",
|
|
21720
|
+
density: 900,
|
|
21721
|
+
hpPerKg: 3,
|
|
21722
|
+
penetration: 4,
|
|
21723
|
+
ductility: 0.5,
|
|
21724
|
+
fracture: "crumble",
|
|
21725
|
+
fragmentSize: [
|
|
21726
|
+
0.03,
|
|
21727
|
+
0.1
|
|
21728
|
+
],
|
|
21729
|
+
hitDebris: "dust",
|
|
21730
|
+
breakDebris: "dust",
|
|
21731
|
+
thermal: {
|
|
21732
|
+
conductivity: 0.1,
|
|
21733
|
+
heatCapacity: 1.5,
|
|
21734
|
+
ignitionC: 250,
|
|
21735
|
+
burnRate: 0.03,
|
|
21736
|
+
smoke: "white"
|
|
21737
|
+
},
|
|
21738
|
+
tags: [
|
|
21739
|
+
"soil",
|
|
21740
|
+
"organic"
|
|
21741
|
+
],
|
|
21742
|
+
compressive: 15e3
|
|
21743
|
+
},
|
|
21744
|
+
{
|
|
21745
|
+
id: "mortar",
|
|
21746
|
+
density: 1900,
|
|
21747
|
+
hpPerKg: 10,
|
|
21748
|
+
penetration: 12,
|
|
21749
|
+
penetrationClass: "concrete",
|
|
21750
|
+
penetrationScale: 1.2,
|
|
21751
|
+
ductility: 0.03,
|
|
21752
|
+
fracture: "crumble",
|
|
21753
|
+
fragmentSize: [
|
|
21754
|
+
0.02,
|
|
21755
|
+
0.08
|
|
21756
|
+
],
|
|
21757
|
+
hitDebris: "chips",
|
|
21758
|
+
breakDebris: "dust",
|
|
21759
|
+
thermal: {
|
|
21760
|
+
conductivity: 0.15,
|
|
21761
|
+
heatCapacity: 2.5
|
|
21762
|
+
},
|
|
21763
|
+
tags: [
|
|
21764
|
+
"masonry",
|
|
21765
|
+
"brittle"
|
|
21766
|
+
],
|
|
21767
|
+
compressive: 1e5
|
|
21564
21768
|
}
|
|
21565
21769
|
];
|
|
21566
21770
|
var material_hints_default = {
|
|
@@ -21734,6 +21938,32 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21734
21938
|
return (1 + 4 * (0.3 - ductility) / 0.3) * Math.min(25, Math.max(1, (0.02 / Math.max(thickness, 1e-4)) ** 2));
|
|
21735
21939
|
};
|
|
21736
21940
|
var THIN_SHEET_DISHING = 5e-3;
|
|
21941
|
+
var SWEEP_BACK = 0.01;
|
|
21942
|
+
function sweepOrigins(box5, d, spacing) {
|
|
21943
|
+
const origins = [];
|
|
21944
|
+
const line = (from, to) => {
|
|
21945
|
+
const n = Math.max(1, Math.ceil((to - from) / spacing));
|
|
21946
|
+
return Array.from({ length: n + 1 }, (_, i) => from + (to - from) * i / n);
|
|
21947
|
+
};
|
|
21948
|
+
for (const axis2 of [0, 1, 2]) {
|
|
21949
|
+
if (Math.abs(d[axis2]) < 1e-3) continue;
|
|
21950
|
+
const lead = d[axis2] > 0 ? box5.max[axis2] - SWEEP_BACK : box5.min[axis2] + SWEEP_BACK;
|
|
21951
|
+
const u = (axis2 + 1) % 3;
|
|
21952
|
+
const v = (axis2 + 2) % 3;
|
|
21953
|
+
for (const a of line(box5.min[u], box5.max[u])) {
|
|
21954
|
+
for (const b of line(box5.min[v], box5.max[v])) {
|
|
21955
|
+
const point = [0, 0, 0];
|
|
21956
|
+
point[axis2] = lead;
|
|
21957
|
+
point[u] = a;
|
|
21958
|
+
point[v] = b;
|
|
21959
|
+
origins.push(point);
|
|
21960
|
+
}
|
|
21961
|
+
}
|
|
21962
|
+
}
|
|
21963
|
+
return origins;
|
|
21964
|
+
}
|
|
21965
|
+
var THIN_SHEET_CRUSH = 5e-4;
|
|
21966
|
+
var THIN_SHEET_CONTACT = 0.025;
|
|
21737
21967
|
var DMG_PER_J = 0.02;
|
|
21738
21968
|
var BLAST_COUPLING = 0.1;
|
|
21739
21969
|
var SHELTER_DEFAULTS = { k: 2800, brokenTransmission: 0.5, minPath: 5e-3 };
|
|
@@ -21750,11 +21980,15 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21750
21980
|
var SEVER_BAND = 0.1;
|
|
21751
21981
|
var SEVER_ASPECT = 3;
|
|
21752
21982
|
var SEVER_BALLISTIC = 2;
|
|
21983
|
+
var TEAR_JOULES = 150;
|
|
21984
|
+
var tears = 0;
|
|
21753
21985
|
var SUPPORT_TOLERANCE = 0.05;
|
|
21754
21986
|
var UNIT_FRAGMENT_FACTOR = 4;
|
|
21755
21987
|
var BREACH_GRID_CAP = 4096;
|
|
21756
21988
|
var CHIP_ENERGY = 200;
|
|
21757
21989
|
var CHIP_SPLASH = 0.5;
|
|
21990
|
+
var BAR_BOW = 0.08;
|
|
21991
|
+
var BULLET_JOINT_SPAN = 0.3;
|
|
21758
21992
|
var CUT_SLICE = 1;
|
|
21759
21993
|
var cutFactorOf = (shape) => clamp2(Math.max(...shapeDims(shape)) / CUT_SLICE, 1, 50);
|
|
21760
21994
|
var clamp2 = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
@@ -21764,8 +21998,24 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21764
21998
|
return v === void 0 ? void 0 : v * (mat.penetrationScale ?? 1);
|
|
21765
21999
|
};
|
|
21766
22000
|
var capacityScale = (p) => {
|
|
21767
|
-
|
|
21768
|
-
|
|
22001
|
+
const residual = p.spec.reinforcement?.residualCapacity ?? RESIDUAL_CAPACITY;
|
|
22002
|
+
if (p.st.stripped) return residual;
|
|
22003
|
+
const kept = Math.min(p.rt.removed ? 1 - p.rt.removed / p.mass0 : 1, 1 - sectionLoss(p));
|
|
22004
|
+
return Math.max(p.spec.reinforcement ? residual : 0.05, kept);
|
|
22005
|
+
};
|
|
22006
|
+
var sectionLoss = (p) => {
|
|
22007
|
+
const cells = p.st.chipped;
|
|
22008
|
+
if (!cells?.length) return 0;
|
|
22009
|
+
const [u, v] = planeAxes(p.thin);
|
|
22010
|
+
const along = p.dims[u] >= p.dims[v] ? u : v;
|
|
22011
|
+
const across2 = along === u ? v : u;
|
|
22012
|
+
let worst = 0;
|
|
22013
|
+
for (const c of cells) {
|
|
22014
|
+
let gone = 0;
|
|
22015
|
+
for (const d of cells) if (Math.abs(d.center[along] - c.center[along]) < d.size[along] / 2 + 1e-6) gone += d.size[across2];
|
|
22016
|
+
worst = Math.max(worst, gone / Math.max(p.dims[across2], 1e-6));
|
|
22017
|
+
}
|
|
22018
|
+
return Math.min(1, worst);
|
|
21769
22019
|
};
|
|
21770
22020
|
var isLost = (p) => p.st.status === "broken" || p.st.status === "melted" || p.st.status === "ashes";
|
|
21771
22021
|
var clone = (v) => structuredClone(v);
|
|
@@ -22865,7 +23115,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22865
23115
|
emit2({ ...base(o, src), type: "crack", part: p.spec.id, crack, worldPoint: wp });
|
|
22866
23116
|
setStage(o, p, 1, {}, src);
|
|
22867
23117
|
};
|
|
22868
|
-
const debris2 = (o, p, kind, point, normal, count, speed, src) => emit2({ ...base(o, src), type: "debris", part: p.spec.id, kind, point, normal, count, speed });
|
|
23118
|
+
const debris2 = (o, p, kind, point, normal, count, speed, src, material) => emit2({ ...base(o, src), type: "debris", part: p.spec.id, kind, point, normal, count, speed, ...material && material !== p.spec.material ? { material } : {} });
|
|
22869
23119
|
const holeRate = (hole, pressurized) => (pressurized ? 0.5 : 0.1) * (hole.diameter / 9e-3);
|
|
22870
23120
|
const detachEvents = (o, opened, by, src) => {
|
|
22871
23121
|
for (const j of opened) emit2({ ...base(o, src), type: "detach", joint: j.spec.id, parts: [j.spec.a, j.spec.b], by, groups: o.st.groups.map((g) => [...g]) });
|
|
@@ -22906,7 +23156,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22906
23156
|
const small = pa.dims[0] * pa.dims[1] * pa.dims[2] <= pb.dims[0] * pb.dims[1] * pb.dims[2] ? pa : pb;
|
|
22907
23157
|
return Math.max(0.06, 0.5 * Math.min(small.dims[0], small.dims[1], small.dims[2]));
|
|
22908
23158
|
};
|
|
22909
|
-
const
|
|
23159
|
+
const jointLength = (o, j) => {
|
|
23160
|
+
const A = partWorldAabb(o, o.parts[j.ia]), B = partWorldAabb(o, o.parts[j.ib]);
|
|
23161
|
+
let len = 0;
|
|
23162
|
+
for (let k = 0; k < 3; k++) len = Math.max(len, Math.min(A.max[k], B.max[k]) - Math.max(A.min[k], B.min[k]));
|
|
23163
|
+
return len;
|
|
23164
|
+
};
|
|
23165
|
+
const wearJoints = (o, p, amount, near, radius = 0.06, src, split = false, span) => {
|
|
22910
23166
|
if (amount <= 0) return;
|
|
22911
23167
|
const mine = (o.byPart.get(p.spec.id) ?? []).filter((j) => !j.st.open);
|
|
22912
23168
|
if (split && mine.length) amount /= mine.length;
|
|
@@ -22914,7 +23170,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22914
23170
|
if (j.st.open) continue;
|
|
22915
23171
|
if (j.spec.kind === "rebar" && (isReinforced(o.parts[j.ia].spec) || isReinforced(o.parts[j.ib].spec))) continue;
|
|
22916
23172
|
if (near && jointReach(o, j, near) > Math.max(radius, jointReachLimit(o, j))) continue;
|
|
22917
|
-
j.st.hp -= amount;
|
|
23173
|
+
j.st.hp -= span === void 0 ? amount : amount * Math.min(1, span / Math.max(jointLength(o, j), 1e-6));
|
|
22918
23174
|
if (j.st.hp <= 0) {
|
|
22919
23175
|
j.st.hp = 0;
|
|
22920
23176
|
j.st.open = true;
|
|
@@ -22943,7 +23199,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22943
23199
|
if (spalls.length > MAX_SPALLS) spalls.shift();
|
|
22944
23200
|
markDamaged(p);
|
|
22945
23201
|
emit2({ ...base(o, src), type: "spall", part: p.spec.id, layer: layer2.index, point: wp, area: Math.PI * radius * radius });
|
|
22946
|
-
debris2(o, p, layer2.mat.hitDebris, wp, normal, 5, 2, src);
|
|
23202
|
+
debris2(o, p, layer2.mat.hitDebris, wp, normal, 5, 2, src, layer2.mat.id);
|
|
23203
|
+
setStage(o, p, 1, {}, src);
|
|
23204
|
+
};
|
|
23205
|
+
const crater = (o, p, wp, normal, radius, src) => {
|
|
23206
|
+
markDamaged(p);
|
|
23207
|
+
emit2({ ...base(o, src), type: "spall", part: p.spec.id, layer: -1, point: wp, area: Math.PI * radius * radius });
|
|
23208
|
+
debris2(o, p, p.mat.breakDebris, wp, normal, 6, 1.5, src);
|
|
22947
23209
|
setStage(o, p, 1, {}, src);
|
|
22948
23210
|
};
|
|
22949
23211
|
const insideOpening = (o, p, objectPoint) => {
|
|
@@ -23022,9 +23284,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23022
23284
|
const lp = toLocal(p.pos, p.q, objectPoint);
|
|
23023
23285
|
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);
|
|
23024
23286
|
};
|
|
23025
|
-
const chipUnits = (o, p, wp,
|
|
23287
|
+
const chipUnits = (o, p, kind, wp, hitEnergy, dir, radius, src) => {
|
|
23026
23288
|
var _a, _b;
|
|
23027
|
-
if (!p.spec.units ||
|
|
23289
|
+
if (!p.spec.units || !p.staged || chipEnergy <= 0 || p.st.stripped || isLost(p) || (p.st.stage ?? 0) >= 2) return;
|
|
23290
|
+
const rule = p.mat.hits?.[kind];
|
|
23291
|
+
const perKg = rule?.unitJoules ?? chipEnergy;
|
|
23292
|
+
const energy = hitEnergy - (rule?.floor ?? 0);
|
|
23293
|
+
if (perKg <= 0 || energy <= 0) return;
|
|
23028
23294
|
const [u, v] = planeAxes(p.thin);
|
|
23029
23295
|
const lp = toLocal(p.pos, p.q, objLocal(o, wp));
|
|
23030
23296
|
const grid = gridOf(p);
|
|
@@ -23038,7 +23304,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23038
23304
|
const share = gap === 0 ? 1 : CHIP_SPLASH * (1 - gap / radius);
|
|
23039
23305
|
const total = (worn[i] ?? 0) + energy * share;
|
|
23040
23306
|
const mass = p.mat.density * cell.size[0] * cell.size[1] * cell.size[2];
|
|
23041
|
-
if (total <
|
|
23307
|
+
if (total < perKg * mass) {
|
|
23042
23308
|
worn[i] = total;
|
|
23043
23309
|
continue;
|
|
23044
23310
|
}
|
|
@@ -23063,7 +23329,32 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23063
23329
|
emit2({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [cell.size[0], cell.size[1], cell.size[2]], rotation: q, fragments });
|
|
23064
23330
|
debris2(o, p, p.mat.breakDebris, center, vec.scale(dir ?? [0, 1, 0], -1), 6, 2, src);
|
|
23065
23331
|
}
|
|
23332
|
+
if (p.spec.reinforcement) exposeRebar(o, p, src);
|
|
23066
23333
|
for (const cell of out) addBreach(o, p, toWorld(c, q, cell.center), cell.size[u] * cell.size[v], energy, dir, src);
|
|
23334
|
+
if (p.structural && !isLost(p)) {
|
|
23335
|
+
solveStructure(o);
|
|
23336
|
+
collapseCheck(o, src);
|
|
23337
|
+
}
|
|
23338
|
+
};
|
|
23339
|
+
const exposeRebar = (o, p, src) => {
|
|
23340
|
+
const r = p.spec.reinforcement;
|
|
23341
|
+
if (!r) return;
|
|
23342
|
+
const [u, v] = planeAxes(p.thin);
|
|
23343
|
+
const all = rebarBars(p.dims, p.thin, r.spacing);
|
|
23344
|
+
let bars;
|
|
23345
|
+
if (p.st.stripped) bars = all;
|
|
23346
|
+
else {
|
|
23347
|
+
bars = [];
|
|
23348
|
+
for (const cell of p.st.chipped ?? []) bars.push(...clipBarsToBox(all, u, v, cell.center, cell.size));
|
|
23349
|
+
const op = p.st.opening;
|
|
23350
|
+
if (op) {
|
|
23351
|
+
const lc = toLocal(p.pos, p.q, op.center);
|
|
23352
|
+
bars.push(...clipBarsToDisc(all, u, v, [lc[u], lc[v]], op.radius + 0.05));
|
|
23353
|
+
}
|
|
23354
|
+
}
|
|
23355
|
+
const bow = clamp2(((p.st.stress ?? 0) - 1) / 0.5, 0, 1);
|
|
23356
|
+
if (bow > 0) bars = bars.flatMap((bar2, i) => bendBar(bar2, p.thin, bow * BAR_BOW, i));
|
|
23357
|
+
emit2({ ...base(o, src), type: "expose", part: p.spec.id, bars: worldBars(o, p, bars) });
|
|
23067
23358
|
};
|
|
23068
23359
|
const openBreach = (o, p, center, total, energy, dir, src) => {
|
|
23069
23360
|
const [u, v] = planeAxes(p.thin);
|
|
@@ -23091,10 +23382,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23091
23382
|
setStage(o, p, 2, { opening: { center: worldCenter, radius }, fragments }, src);
|
|
23092
23383
|
debris2(o, p, p.mat.breakDebris, worldCenter, vec.scale(dir ?? [0, 1, 0], -1), 14, 3, src);
|
|
23093
23384
|
const reinforcement = p.spec.reinforcement;
|
|
23094
|
-
if (reinforcement)
|
|
23095
|
-
const bars = worldBars(o, p, clipBarsToDisc(rebarBars(p.dims, p.thin, reinforcement.spacing), u, v, [lc[u], lc[v]], radius + 0.05));
|
|
23096
|
-
if (bars.length > 0) emit2({ ...base(o, src), type: "expose", part: p.spec.id, bars });
|
|
23097
|
-
}
|
|
23385
|
+
if (reinforcement) exposeRebar(o, p, src);
|
|
23098
23386
|
if (p.structural) solveStructure(o);
|
|
23099
23387
|
};
|
|
23100
23388
|
const stripPart = (o, p, reinforcement, src) => {
|
|
@@ -23106,8 +23394,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23106
23394
|
p.st.burning = false;
|
|
23107
23395
|
p.rt.jet = false;
|
|
23108
23396
|
markDamaged(p);
|
|
23109
|
-
emit2({ ...base(o, src), type: "expose", part: p.spec.id, bars: worldBars(o, p, bars) });
|
|
23110
23397
|
solveStructure(o);
|
|
23398
|
+
exposeRebar(o, p, src);
|
|
23111
23399
|
collapseCheck(o, src);
|
|
23112
23400
|
};
|
|
23113
23401
|
const unitFragmentPlan = (p, cap) => {
|
|
@@ -23161,7 +23449,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23161
23449
|
const grain = p.spec.grain ? AXIS[p.spec.grain] : void 0;
|
|
23162
23450
|
const hitLocal = toLocal(c, q, hitW);
|
|
23163
23451
|
const unitPlan = p.spec.units ? unitFragmentPlan(p, maxFragments * UNIT_FRAGMENT_FACTOR) : [];
|
|
23164
|
-
const axis2 = style === "splinter" ? severAxis(p) : -1;
|
|
23452
|
+
const axis2 = style === "splinter" || style === "snap" ? severAxis(p) : -1;
|
|
23165
23453
|
const cutAt2 = axis2 < 0 ? void 0 : p.rt.cutAt ?? (origin ? hitLocal[axis2] : void 0);
|
|
23166
23454
|
const plan = unitPlan.length > 0 ? unitPlan : planFragments({
|
|
23167
23455
|
style,
|
|
@@ -23233,7 +23521,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23233
23521
|
};
|
|
23234
23522
|
const CHAIN_TRIGGER_OF = { ballistic: "shot", explosive: "explosion" };
|
|
23235
23523
|
const severAxis = (p) => {
|
|
23236
|
-
if (p.mat.fracture !== "splinter" || p.spec.shape.kind !== "box") return -1;
|
|
23524
|
+
if (p.mat.fracture !== "splinter" && p.mat.fracture !== "snap" || p.spec.shape.kind !== "box") return -1;
|
|
23237
23525
|
const d = p.dims;
|
|
23238
23526
|
const order = [0, 1, 2].sort((a, b) => d[b] - d[a]);
|
|
23239
23527
|
return d[order[0]] >= SEVER_ASPECT * d[order[1]] && d[order[0]] >= 3 * SEVER_BAND ? order[0] : -1;
|
|
@@ -23294,6 +23582,49 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23294
23582
|
}
|
|
23295
23583
|
}
|
|
23296
23584
|
};
|
|
23585
|
+
const tearOf = (mat, kind) => {
|
|
23586
|
+
const h = mat.hits?.[kind];
|
|
23587
|
+
const tear = h?.tear ?? (kind === "ballistic" && mat.penetrationClass === "wood" ? "splinters" : "none");
|
|
23588
|
+
return { tear, joules: h?.tearJoules ?? TEAR_JOULES };
|
|
23589
|
+
};
|
|
23590
|
+
const tearAt = (o, p, kind, entry2, exit, d, E, scale, src) => {
|
|
23591
|
+
const { tear, joules } = tearOf(p.mat, kind);
|
|
23592
|
+
if (tear === "none") return;
|
|
23593
|
+
const shot = kind === "ballistic";
|
|
23594
|
+
const n = shot ? exit ? clamp2(Math.round(E / joules), 1, 7) : 1 : clamp2(Math.floor(E / joules), 0, 5);
|
|
23595
|
+
if (n === 0) return;
|
|
23596
|
+
const fibre = tear === "lumps";
|
|
23597
|
+
const { q } = partXf(o, p);
|
|
23598
|
+
const along = (p.spec.grain ? AXIS[p.spec.grain] : void 0) ?? [0, 1, 2].sort((a, b) => p.dims[b] - p.dims[a])[0];
|
|
23599
|
+
const fragments = [];
|
|
23600
|
+
for (let i = 0; i < n; i++) {
|
|
23601
|
+
const back = !exit || i % 3 === 2;
|
|
23602
|
+
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());
|
|
23603
|
+
const size = [w, w, w];
|
|
23604
|
+
size[along] = len;
|
|
23605
|
+
size[(along + 1) % 3] = w;
|
|
23606
|
+
size[(along + 2) % 3] = t;
|
|
23607
|
+
const spread3 = [(rnd2() - 0.5) * 0.8, (rnd2() - 0.2) * 0.8, (rnd2() - 0.5) * 0.8];
|
|
23608
|
+
const speed = shot ? back ? 1.5 + 2 * rnd2() : 2 + 4 * rnd2() : 0.8 + 1.2 * rnd2();
|
|
23609
|
+
const v = vec.scale(vec.normalize(vec.add(back ? vec.scale(d, -1) : d, spread3)), speed);
|
|
23610
|
+
const mass = size[0] * size[1] * size[2] * p.mat.density;
|
|
23611
|
+
fragments.push({
|
|
23612
|
+
id: `${p.spec.id}#t${tears++}-${i}`,
|
|
23613
|
+
part: p.spec.id,
|
|
23614
|
+
material: p.spec.material,
|
|
23615
|
+
shape: fibre ? "chunk" : "splinter",
|
|
23616
|
+
center: back || !exit ? vec.madd(entry2, d, -0.01) : vec.madd(exit, d, 0.01),
|
|
23617
|
+
size,
|
|
23618
|
+
rotation: q,
|
|
23619
|
+
velocity: v,
|
|
23620
|
+
inner: true,
|
|
23621
|
+
angularVelocity: [(rnd2() - 0.5) * 30, (rnd2() - 0.5) * 30, (rnd2() - 0.5) * 30],
|
|
23622
|
+
mass
|
|
23623
|
+
});
|
|
23624
|
+
}
|
|
23625
|
+
const patch = [scale * 4, scale * 4, scale * 4];
|
|
23626
|
+
emit2({ ...base(o, src), type: "chip", part: p.spec.id, center: exit ?? entry2, size: patch, rotation: q, fragments });
|
|
23627
|
+
};
|
|
23297
23628
|
const ballistic = (o, p, entry2, n, d, E, caliber, pathLen, src, round5 = {}) => {
|
|
23298
23629
|
const mat = p.mat;
|
|
23299
23630
|
const piercing = round5.piercing ?? 1;
|
|
@@ -23322,6 +23653,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23322
23653
|
return { penetrated: false, exitEnergy: 0, damage: dmg2 };
|
|
23323
23654
|
}
|
|
23324
23655
|
if (p.layers.length > 0) spallOuter(o, p, entry2, face, n, Math.max(0.03, caliber / 1e3 * 4), src);
|
|
23656
|
+
else if (mat.hits?.ballistic?.crater) crater(o, p, entry2, n, clamp2(0.02 + Math.sqrt(E) * 15e-4, 0.02, 0.15), src);
|
|
23325
23657
|
const brittle = mat.ductility < 0.3;
|
|
23326
23658
|
const ratio = Ep / Math.max(thr, 1e-6);
|
|
23327
23659
|
const crackLen = clamp2(0.03 + ratio * 0.2, 0.03, 0.8);
|
|
@@ -23354,9 +23686,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23354
23686
|
if (mat.fracture !== "shatter") addHole(o, p, entry2, n, caliber / 1e3, false, void 0, src);
|
|
23355
23687
|
} else addHole(o, p, entry2, n, caliber / 1e3, false, void 0, src);
|
|
23356
23688
|
debris2(o, p, mat.hitDebris, entry2, n, clamp2(Math.round(E / 60) + 2, 2, 14), clamp2(Math.sqrt(E) / 6, 1, 8), src);
|
|
23357
|
-
wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true);
|
|
23358
|
-
const
|
|
23359
|
-
|
|
23689
|
+
wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true, BULLET_JOINT_SPAN);
|
|
23690
|
+
const absorbed = penetrated && mat.ductility >= 0.5 && mat.fracture !== "tear" ? Math.min(E, thr) : E;
|
|
23691
|
+
const dmg = applyDamage(o, p, absorbed * DMG_PER_J * scale, "ballistic", entry2, d, absorbed * 0.1, 12, src);
|
|
23692
|
+
if (!isLost(p)) tearAt(o, p, "ballistic", entry2, penetrated ? exitPoint : void 0, d, E, caliber / 1e3, src);
|
|
23693
|
+
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);
|
|
23360
23694
|
return { penetrated, exitEnergy: penetrated ? penMm !== void 0 ? E * (1 - thr / Ep) : E - thr / (hard ? piercing : 1) : 0, exitPoint, damage: dmg };
|
|
23361
23695
|
};
|
|
23362
23696
|
const melee = (o, p, kind, E, point, n, d, contactR, src) => {
|
|
@@ -23364,14 +23698,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23364
23698
|
const thrMm = mat.penetration * p.thickness * 1e3;
|
|
23365
23699
|
const fragile = kind === "blunt" ? fragility(mat.ductility, p.thickness) : 1;
|
|
23366
23700
|
const Ec = E * fragile;
|
|
23701
|
+
const sheet = mat.ductility >= 0.5 && p.thickness <= THIN_SHEET_CRUSH;
|
|
23702
|
+
const fold = sheet ? Math.min(4, Math.sqrt(1e-3 / p.thickness)) : 1;
|
|
23703
|
+
const patch = sheet ? Math.min(contactR, THIN_SHEET_CONTACT) : contactR;
|
|
23367
23704
|
if (E > 0) {
|
|
23368
23705
|
if (kind === "blunt") {
|
|
23369
|
-
if (mat.ductility >= 0.5) addDent(o, p, point, n, Math.max(
|
|
23706
|
+
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);
|
|
23370
23707
|
else if (mat.ductility < 0.3) {
|
|
23371
23708
|
if (Ec >= 5) addCrack(o, p, point, n, clamp2(0.04 + Math.min(Ec, E * 6) * 8e-4, 0.04, 0.6), src);
|
|
23372
23709
|
} 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);
|
|
23373
23710
|
} else if (mat.fracture === "tear") {
|
|
23374
23711
|
addHole(o, p, point, n, clamp2(0.02 + E * 5e-4, 0.02, 0.3), true, void 0, src);
|
|
23712
|
+
} else if (mat.ductility >= 0.3 && E >= thrMm) {
|
|
23713
|
+
addHole(o, p, point, n, clamp2(contactR, 0.01, 0.08), true, void 0, src);
|
|
23714
|
+
if (sheet) addDent(o, p, point, n, Math.max(patch * 0.6, 0.01), clamp2(E * 4e-5 * fold, 5e-4, 0.02), src);
|
|
23375
23715
|
} else if (mat.ductility >= 0.5) {
|
|
23376
23716
|
addDent(o, p, point, n, Math.max(contactR, 0.01), clamp2(E * 4e-5, 5e-4, 0.02), src);
|
|
23377
23717
|
}
|
|
@@ -23384,7 +23724,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23384
23724
|
const scale = mat.damageScale?.[kind] ?? 1;
|
|
23385
23725
|
const done = applyDamage(o, p, Ec * DMG_PER_J * scale * (kind === "slash" ? p.cutFactor : 1), kind, point, d, E * 0.1, 12, src);
|
|
23386
23726
|
addBreach(o, p, point, breachAreaOf(p, done, false), E, d, src);
|
|
23387
|
-
if (kind === "blunt") chipUnits(o, p, point, E, d, Math.max(contactR, 0.03), src);
|
|
23727
|
+
if (kind === "blunt") chipUnits(o, p, "blunt", point, E, d, Math.max(contactR, 0.03), src);
|
|
23728
|
+
if (E > 0 && !isLost(p)) tearAt(o, p, kind, point, void 0, d, E, clamp2(contactR * 0.2, 6e-3, 0.02), src);
|
|
23388
23729
|
return done;
|
|
23389
23730
|
};
|
|
23390
23731
|
const blastPart = (o, p, point, energy, radius, src, res, reachAt) => {
|
|
@@ -23963,6 +24304,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23963
24304
|
if (p.rt.stressT <= 0) {
|
|
23964
24305
|
p.rt.stressT = 0.5;
|
|
23965
24306
|
emit2({ ...base(o), type: "stress", part: p.spec.id, stress, load: p.st.load ?? 0 });
|
|
24307
|
+
if (p.spec.reinforcement && (p.st.stripped || p.st.chipped?.length || p.st.opening)) exposeRebar(o, p);
|
|
23966
24308
|
}
|
|
23967
24309
|
applyDamage(o, p, overloadRate(stress) * p.st.maxHp * dt, "blunt", null, null, 5, 3);
|
|
23968
24310
|
} else if (stress > 0.8 && p.mat.ductility < 0.3 && p.rt.stressT <= 0 && p.st.cracks.length < 6) {
|
|
@@ -24179,6 +24521,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
24179
24521
|
const r = raycastInternal(origin, direction, maxDistance);
|
|
24180
24522
|
return r ? { object: r.object, part: r.part, point: r.point, normal: r.normal, distance: r.distance } : null;
|
|
24181
24523
|
},
|
|
24524
|
+
sweepBox(box5, direction, distance3, options2 = {}) {
|
|
24525
|
+
const d = vec.normalize(direction);
|
|
24526
|
+
const ignored = options2.ignore === void 0 ? void 0 : objects.get(options2.ignore);
|
|
24527
|
+
const ignore = ignored ? new Set(ignored.parts.map((p) => `${ignored.id}\0${p.spec.id}`)) : void 0;
|
|
24528
|
+
let best = null;
|
|
24529
|
+
for (const origin of sweepOrigins(box5, d, options2.spacing ?? 0.2)) {
|
|
24530
|
+
const r = raycastInternal(origin, d, distance3 + SWEEP_BACK, ignore);
|
|
24531
|
+
if (!r || best && r.distance >= best.distance) continue;
|
|
24532
|
+
best = { object: r.object, part: r.part, point: r.point, normal: r.normal, distance: Math.max(0, r.distance - SWEEP_BACK) };
|
|
24533
|
+
}
|
|
24534
|
+
return best;
|
|
24535
|
+
},
|
|
24182
24536
|
shoot(origin, direction, energy, caliber, source, round5) {
|
|
24183
24537
|
const extras = typeof round5 === "number" ? { piercing: round5 } : round5 ?? {};
|
|
24184
24538
|
return withCollapses(run(() => {
|
|
@@ -25750,7 +26104,24 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
25750
26104
|
}
|
|
25751
26105
|
return spec;
|
|
25752
26106
|
};
|
|
25753
|
-
var
|
|
26107
|
+
var MEMBER_CAGE = { spacing: 0.1, diameter: 8e-3, unit: 0.1 };
|
|
26108
|
+
var CAGED_ROLES = /* @__PURE__ */ new Set(["beam", "column"]);
|
|
26109
|
+
var caged = (spec, part, rebar2) => {
|
|
26110
|
+
if (!rebar2 || part.material !== "concrete" || !CAGED_ROLES.has(part.role) || spec.reinforcement) return spec;
|
|
26111
|
+
const size = spec.shape.kind === "box" ? spec.shape.size : null;
|
|
26112
|
+
if (!size) return spec;
|
|
26113
|
+
const thin = Math.min(...size);
|
|
26114
|
+
return {
|
|
26115
|
+
...spec,
|
|
26116
|
+
reinforcement: { material: rebar2, spacing: MEMBER_CAGE.spacing, diameter: MEMBER_CAGE.diameter },
|
|
26117
|
+
units: { size: [MEMBER_CAGE.unit, MEMBER_CAGE.unit, thin], bond: "stack", mortar: "concrete" }
|
|
26118
|
+
};
|
|
26119
|
+
};
|
|
26120
|
+
var partSpecOf = (part, capacity, detailed, rebar2) => {
|
|
26121
|
+
if (detailed && part.assembly) return assemblySpec(part, capacity);
|
|
26122
|
+
const spec = boxSpec(part, capacity);
|
|
26123
|
+
return detailed ? caged(spec, part, rebar2) : spec;
|
|
26124
|
+
};
|
|
25754
26125
|
function toDestructibleSpec(structure, options = {}) {
|
|
25755
26126
|
const { safety = 0.65, redundancy = 0.97, safetyOthers = 0.45 } = options;
|
|
25756
26127
|
const kept = structure.parts.filter((part) => !options.filter || options.filter(part));
|
|
@@ -25767,7 +26138,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
25767
26138
|
const sizing = { safety, redundancy, safetyOthers };
|
|
25768
26139
|
const sized = { ...panels, capacities: options.sized === false ? /* @__PURE__ */ new Map() : sizeCapacities(panels.parts, panels.supports, sizing) };
|
|
25769
26140
|
const { parts, supports, capacities } = detail === "units" ? applyUnits(sized, structure) : sized;
|
|
25770
|
-
const specs = parts.map((part) => partSpecOf(part, capacities.get(part.id), detail !== "coarse"));
|
|
26141
|
+
const specs = parts.map((part) => partSpecOf(part, capacities.get(part.id), detail !== "coarse", structure.construction.frame.rebar));
|
|
25771
26142
|
const margin = options.terrainMargin ?? TERRAIN_MARGIN;
|
|
25772
26143
|
const x0 = Math.min(...parts.map((part) => part.aabb[0]));
|
|
25773
26144
|
const z0 = Math.min(...parts.map((part) => part.aabb[1]));
|
|
@@ -33732,7 +34103,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33732
34103
|
if (!pc || pc.unit) return sp;
|
|
33733
34104
|
if (pc.role !== "wall" && pc.role !== "partition") {
|
|
33734
34105
|
const def = getAssembly(pc.assembly || (pc.material === "concrete" && ["slab", "beam", "column", "stair"].includes(pc.role) ? "reinforced_concrete" : ""));
|
|
33735
|
-
|
|
34106
|
+
const out = def && def.reinforcement && !sp.reinforcement ? { ...sp, reinforcement: { ...def.reinforcement } } : sp;
|
|
34107
|
+
if (out.reinforcement && !out.units && pc.material === "concrete" && (pc.role === "beam" || pc.role === "column") && sp.shape.kind === "box") {
|
|
34108
|
+
return { ...out, units: { size: [MEMBER_CAGE.unit, MEMBER_CAGE.unit, Math.min(...sp.shape.size)], bond: "stack", mortar: "concrete" } };
|
|
34109
|
+
}
|
|
34110
|
+
return out;
|
|
33736
34111
|
}
|
|
33737
34112
|
if (!pc.assembly) return sp;
|
|
33738
34113
|
const [u0, v0, u1, v1] = pc.aabb, alongU = u1 - u0 >= v1 - v0;
|
|
@@ -33767,6 +34142,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33767
34142
|
pos.array.set(saved, v0 * 3);
|
|
33768
34143
|
pos.needsUpdate = true;
|
|
33769
34144
|
}
|
|
34145
|
+
function noise2(x, y, cell) {
|
|
34146
|
+
const h = (i2, j2) => {
|
|
34147
|
+
const s = Math.sin(i2 * 127.1 + j2 * 311.7) * 43758.5453;
|
|
34148
|
+
return s - Math.floor(s);
|
|
34149
|
+
};
|
|
34150
|
+
const fx = x / cell, fy = y / cell, i = Math.floor(fx), j = Math.floor(fy), u = fx - i, v = fy - j;
|
|
34151
|
+
const su = u * u * (3 - 2 * u), sv = v * v * (3 - 2 * v);
|
|
34152
|
+
return (h(i, j) * (1 - su) + h(i + 1, j) * su) * (1 - sv) + (h(i, j + 1) * (1 - su) + h(i + 1, j + 1) * su) * sv;
|
|
34153
|
+
}
|
|
34154
|
+
var MASK_TEXEL = 0.02;
|
|
34155
|
+
var SPALL_MIN = 0.025;
|
|
34156
|
+
var SPALL_RAGGED = 0.045;
|
|
34157
|
+
var COVER2 = 0.015;
|
|
33770
34158
|
function installDestructionBreach(K, _shared) {
|
|
33771
34159
|
const { THREE, fragmentMaterial, invalidate, invalidateShadow } = K;
|
|
33772
34160
|
function createBreachView(opts) {
|
|
@@ -33776,94 +34164,198 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33776
34164
|
const unitMaterial = new THREE.MeshLambertMaterial({ color: 16777215 });
|
|
33777
34165
|
const unitGeometry = new THREE.BoxGeometry(1, 1, 1);
|
|
33778
34166
|
const tmp = { m: new THREE.Matrix4(), q: new THREE.Quaternion(), p: new THREE.Vector3(), s: new THREE.Vector3(), c: new THREE.Color() };
|
|
33779
|
-
const wallColour = (items) => {
|
|
33780
|
-
for (const it of items) {
|
|
33781
|
-
if (!it.mesh) continue;
|
|
33782
|
-
const c = it.mesh.geometry.attributes.color;
|
|
33783
|
-
if (!c) continue;
|
|
33784
|
-
const a = c.array;
|
|
33785
|
-
tmp.c.setRGB(a[it.v0 * 3], a[it.v0 * 3 + 1], a[it.v0 * 3 + 2]);
|
|
33786
|
-
return tmp.c.getHex();
|
|
33787
|
-
}
|
|
33788
|
-
return null;
|
|
33789
|
-
};
|
|
33790
34167
|
const local2 = (p) => {
|
|
33791
34168
|
house.updateMatrixWorld(true);
|
|
33792
34169
|
const v = house.worldToLocal(tmp.p.set(p[0], p[1], p[2]));
|
|
33793
34170
|
return [v.x, v.y, v.z];
|
|
33794
34171
|
};
|
|
33795
|
-
function
|
|
34172
|
+
function cells(part, units) {
|
|
33796
34173
|
const [u0, v0, u1, v1] = part.aabb;
|
|
33797
34174
|
const alongU = u1 - u0 >= v1 - v0;
|
|
33798
34175
|
const len = alongU ? u1 - u0 : v1 - v0;
|
|
33799
|
-
const thick = alongU ? v1 - v0 : u1 - u0;
|
|
33800
34176
|
const [ul, uh] = units.size;
|
|
33801
34177
|
const rows = Math.max(1, Math.round((part.y1 - part.y0) / uh));
|
|
33802
34178
|
const rowH = (part.y1 - part.y0) / rows;
|
|
33803
34179
|
const per = Math.max(1, Math.round(len / ul));
|
|
33804
34180
|
const w = len / per;
|
|
33805
|
-
const
|
|
33806
|
-
const list2 = [];
|
|
34181
|
+
const out = [];
|
|
33807
34182
|
for (let r = 0; r < rows; r++) {
|
|
33808
34183
|
const shift = units.bond === "running" && r & 1 ? w / 2 : 0;
|
|
33809
|
-
|
|
33810
|
-
|
|
33811
|
-
|
|
33812
|
-
a = Math.max(0, a);
|
|
33813
|
-
b = Math.min(len, b);
|
|
33814
|
-
if (b - a < 1e-3) continue;
|
|
33815
|
-
const mid = (a + b) / 2;
|
|
33816
|
-
const x = alongU ? u0 + mid : (u0 + u1) / 2;
|
|
33817
|
-
const z = alongU ? (v0 + v1) / 2 : v0 + mid;
|
|
33818
|
-
const y = part.y0 + (r + 0.5) * rowH;
|
|
33819
|
-
const d = opening ? Math.hypot(x - opening.center[0], y - opening.center[1], z - opening.center[2]) : Infinity;
|
|
33820
|
-
if (opening && d < opening.radius) continue;
|
|
33821
|
-
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);
|
|
33822
|
-
if (chips2.some(gone)) continue;
|
|
33823
|
-
const near = opening && d < opening.radius + 0.25 || chips2.some((c) => Math.hypot(c[0] - x, c[1] - y, c[2] - z) < 0.15);
|
|
33824
|
-
list2.push({ x, y, z, sx: alongU ? b - a : thick, sy: rowH, sz: alongU ? thick : b - a, colour: near || paint2 === null ? edge : paint2 });
|
|
34184
|
+
for (let i = 0; i < per + (shift ? 1 : 0); i++) {
|
|
34185
|
+
const a = Math.max(0, i * w - shift), b = Math.min(len, i * w - shift + w);
|
|
34186
|
+
if (b - a > 1e-3) out.push({ a, b, y0: part.y0 + r * rowH, y1: part.y0 + (r + 1) * rowH, r, i });
|
|
33825
34187
|
}
|
|
33826
34188
|
}
|
|
33827
|
-
return
|
|
34189
|
+
return out;
|
|
34190
|
+
}
|
|
34191
|
+
const specOf = (id) => opts.spec()?.parts?.find((q) => q.id === id);
|
|
34192
|
+
const same = (a, b) => a.every((x, k) => Math.abs(x - b[k]) < 1e-3);
|
|
34193
|
+
function hostOf(partId) {
|
|
34194
|
+
if (structure.meshesOf(partId).some((it) => it.mesh)) return partId;
|
|
34195
|
+
const part = structure.byId.get(partId);
|
|
34196
|
+
if (!part) return null;
|
|
34197
|
+
for (const q of structure.parts) {
|
|
34198
|
+
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;
|
|
34199
|
+
}
|
|
34200
|
+
return null;
|
|
34201
|
+
}
|
|
34202
|
+
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);
|
|
34203
|
+
function shell(it, mask) {
|
|
34204
|
+
const g0 = it.mesh.geometry, g = new THREE.BufferGeometry();
|
|
34205
|
+
const src = it.mesh.userData._p0 || g0.attributes.position.array;
|
|
34206
|
+
for (const [name, attr] of Object.entries(g0.attributes)) {
|
|
34207
|
+
const k = attr.itemSize;
|
|
34208
|
+
g.setAttribute(name, new THREE.BufferAttribute((name === "position" ? src : attr.array).slice(it.v0 * k, it.v1 * k), k));
|
|
34209
|
+
}
|
|
34210
|
+
if (g0.index) {
|
|
34211
|
+
const ix = g0.index.array.slice(it.i0, it.i1);
|
|
34212
|
+
for (let k = 0; k < ix.length; k++) ix[k] -= it.v0;
|
|
34213
|
+
g.setIndex(new THREE.BufferAttribute(ix, 1));
|
|
34214
|
+
}
|
|
34215
|
+
g.computeBoundingBox();
|
|
34216
|
+
g.computeBoundingSphere();
|
|
34217
|
+
const base = it.mesh.material;
|
|
34218
|
+
const material = base.clone();
|
|
34219
|
+
const toHouse = { value: new THREE.Matrix4() };
|
|
34220
|
+
material.onBeforeCompile = (sh) => {
|
|
34221
|
+
base.onBeforeCompile?.(sh);
|
|
34222
|
+
sh.uniforms.uToHouse = toHouse;
|
|
34223
|
+
sh.uniforms.uMask = { value: mask.texture };
|
|
34224
|
+
sh.uniforms.uMaskRect = { value: mask.rect };
|
|
34225
|
+
sh.uniforms.uMaskAlongX = { value: mask.alongU ? 1 : 0 };
|
|
34226
|
+
sh.vertexShader = sh.vertexShader.replace("void main() {", "uniform mat4 uToHouse;\nvarying vec3 vHousePos;\nvoid main() {").replace("#include <begin_vertex>", "#include <begin_vertex>\nvHousePos = (uToHouse * vec4(transformed, 1.0)).xyz;");
|
|
34227
|
+
sh.fragmentShader = sh.fragmentShader.replace("void main() {", "uniform sampler2D uMask;\nuniform vec4 uMaskRect;\nuniform float uMaskAlongX;\nvarying vec3 vHousePos;\nvoid main() {\n vec2 mUv = vec2(((uMaskAlongX > 0.5 ? vHousePos.x : vHousePos.z) - uMaskRect.x) / uMaskRect.z, (vHousePos.y - uMaskRect.y) / uMaskRect.w);\n if (mUv.x >= 0.0 && mUv.x <= 1.0 && mUv.y >= 0.0 && mUv.y <= 1.0 && texture2D(uMask, mUv).r > 0.5) discard;");
|
|
34228
|
+
};
|
|
34229
|
+
material.customProgramCacheKey = () => "breachMask" + (base.customProgramCacheKey?.() ?? "");
|
|
34230
|
+
const mesh3 = new THREE.Mesh(g, material);
|
|
34231
|
+
mesh3.name = "breach-shell";
|
|
34232
|
+
mesh3.userData.breachMask = mask;
|
|
34233
|
+
mesh3.position.copy(it.mesh.position);
|
|
34234
|
+
mesh3.quaternion.copy(it.mesh.quaternion);
|
|
34235
|
+
mesh3.scale.copy(it.mesh.scale);
|
|
34236
|
+
mesh3.castShadow = it.mesh.castShadow;
|
|
34237
|
+
mesh3.receiveShadow = it.mesh.receiveShadow;
|
|
34238
|
+
mesh3.renderOrder = it.mesh.renderOrder;
|
|
34239
|
+
mesh3.onBeforeRender = () => {
|
|
34240
|
+
house.updateMatrixWorld();
|
|
34241
|
+
toHouse.value.copy(house.matrixWorld).invert().multiply(mesh3.matrixWorld);
|
|
34242
|
+
};
|
|
34243
|
+
it.mesh.parent.add(mesh3);
|
|
34244
|
+
mesh3.updateMatrixWorld(true);
|
|
34245
|
+
toHouse.value.copy(house.matrixWorld).invert().multiply(mesh3.matrixWorld);
|
|
34246
|
+
return mesh3;
|
|
34247
|
+
}
|
|
34248
|
+
function maskOf(hostId, parts) {
|
|
34249
|
+
const host = structure.byId.get(hostId);
|
|
34250
|
+
const [u0, v0, u1, v1] = host.aabb;
|
|
34251
|
+
const alongU = u1 - u0 >= v1 - v0;
|
|
34252
|
+
const y0 = Math.min(...parts.map((id) => structure.byId.get(id).y0)), y1 = Math.max(...parts.map((id) => structure.byId.get(id).y1));
|
|
34253
|
+
const len = alongU ? u1 - u0 : v1 - v0;
|
|
34254
|
+
const w = Math.max(2, Math.min(2048, Math.ceil(len / MASK_TEXEL))), h = Math.max(2, Math.min(1024, Math.ceil((y1 - y0) / MASK_TEXEL)));
|
|
34255
|
+
const data = new Uint8Array(w * h);
|
|
34256
|
+
const texture = new THREE.DataTexture(data, w, h, THREE.RedFormat);
|
|
34257
|
+
texture.magFilter = THREE.LinearFilter;
|
|
34258
|
+
texture.minFilter = THREE.LinearFilter;
|
|
34259
|
+
texture.needsUpdate = true;
|
|
34260
|
+
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) };
|
|
34261
|
+
}
|
|
34262
|
+
const boxDistance = (s, y, a, b, c, d) => Math.hypot(Math.max(a - s, 0, s - b), Math.max(c - y, 0, y - d));
|
|
34263
|
+
function paint2(view) {
|
|
34264
|
+
const { mask } = view;
|
|
34265
|
+
const along = (p) => (mask.alongU ? p[0] : p[2]) - mask.start;
|
|
34266
|
+
const holes = [];
|
|
34267
|
+
const discs = [];
|
|
34268
|
+
const shown = [];
|
|
34269
|
+
for (const id of view.parts) {
|
|
34270
|
+
const part = structure.byId.get(id), units2 = specOf(id).units, chips2 = view.chips.get(id), opening = view.openings.get(id);
|
|
34271
|
+
const all = cells(part, units2);
|
|
34272
|
+
const thick = mask.alongU ? part.aabb[3] - part.aabb[1] : part.aabb[2] - part.aabb[0];
|
|
34273
|
+
const mid = mask.alongU ? (part.aabb[1] + part.aabb[3]) / 2 : (part.aabb[0] + part.aabb[2]) / 2;
|
|
34274
|
+
if (opening) discs.push({ s: along(opening.center), y: opening.center[1], r: opening.radius });
|
|
34275
|
+
const gone = (c) => chips2.some((p) => p[1] >= c.y0 && p[1] <= c.y1 && along(p) >= c.a && along(p) <= c.b) || opening && Math.hypot((c.a + c.b) / 2 - along(opening.center), (c.y0 + c.y1) / 2 - opening.center[1]) < opening.radius;
|
|
34276
|
+
const kept = [];
|
|
34277
|
+
for (const c of all) (gone(c) ? holes : kept).push(c);
|
|
34278
|
+
for (const c of kept) shown.push({ c, part, units: units2, thick, mid });
|
|
34279
|
+
}
|
|
34280
|
+
const reach = SPALL_MIN + SPALL_RAGGED;
|
|
34281
|
+
mask.data.fill(0);
|
|
34282
|
+
const stamp = (s0, s1, y0, y1, inside2) => {
|
|
34283
|
+
const i0 = Math.max(0, Math.floor((s0 - reach) / mask.len * mask.w)), i1 = Math.min(mask.w - 1, Math.ceil((s1 + reach) / mask.len * mask.w));
|
|
34284
|
+
const j0 = Math.max(0, Math.floor((y0 - reach - mask.y0) / mask.height * mask.h)), j1 = Math.min(mask.h - 1, Math.ceil((y1 + reach - mask.y0) / mask.height * mask.h));
|
|
34285
|
+
for (let j = j0; j <= j1; j++) {
|
|
34286
|
+
const y = mask.y0 + (j + 0.5) / mask.h * mask.height;
|
|
34287
|
+
for (let i = i0; i <= i1; i++) {
|
|
34288
|
+
const s = (i + 0.5) / mask.w * mask.len;
|
|
34289
|
+
const edge = SPALL_MIN + SPALL_RAGGED * (0.6 * noise2(s, y, 0.03) + 0.4 * noise2(s + 7.3, y - 3.1, 0.011));
|
|
34290
|
+
if (inside2(s, y) <= edge) mask.data[j * mask.w + i] = 255;
|
|
34291
|
+
}
|
|
34292
|
+
}
|
|
34293
|
+
};
|
|
34294
|
+
for (const c of holes) stamp(c.a, c.b, c.y0, c.y1, (s, y) => boxDistance(s, y, c.a, c.b, c.y0, c.y1));
|
|
34295
|
+
for (const d of discs) stamp(d.s - d.r, d.s + d.r, d.y - d.r, d.y + d.r, (s, y) => Math.max(0, Math.hypot(s - d.s, y - d.y) - d.r));
|
|
34296
|
+
mask.texture.needsUpdate = true;
|
|
34297
|
+
const near = (c) => holes.some((h) => boxDistance((c.a + c.b) / 2, (c.y0 + c.y1) / 2, h.a - (c.b - c.a) / 2, h.b + (c.b - c.a) / 2, h.y0 - (c.y1 - c.y0) / 2, h.y1 + (c.y1 - c.y0) / 2) <= reach) || discs.some((d) => boxDistance(d.s, d.y, c.a, c.b, c.y0, c.y1) <= d.r + reach);
|
|
34298
|
+
const list2 = [];
|
|
34299
|
+
const tone = (hex2, k) => tmp.c.setHex(hex2).multiplyScalar(k).getHex();
|
|
34300
|
+
for (const { c, part, units: units2, thick, mid } of shown) {
|
|
34301
|
+
if (!near(c)) continue;
|
|
34302
|
+
const centre = mask.start + (c.a + c.b) / 2, y = (c.y0 + c.y1) / 2, len = c.b - c.a, h = c.y1 - c.y0;
|
|
34303
|
+
const at3 = (s, dy, d, colour) => list2.push({ x: mask.alongU ? centre : mid, y, z: mask.alongU ? mid : centre, sx: mask.alongU ? s : d, sy: dy, sz: mask.alongU ? d : s, colour });
|
|
34304
|
+
const base = fragmentMaterial(part.material).color.getHex();
|
|
34305
|
+
const n = noise2(centre * 3.1, y * 2.7, 0.07);
|
|
34306
|
+
if (units2.mortar === "concrete") {
|
|
34307
|
+
at3(len, h, thick - 2 * COVER2 - 0.03 * n, tone(base, 0.86 + 0.2 * n));
|
|
34308
|
+
} else {
|
|
34309
|
+
at3(len, h, thick - 2 * COVER2 - 0.012, 10327948);
|
|
34310
|
+
at3(len - 0.012, h - 0.012, thick - 2 * COVER2, tone(base, 0.8 + 0.35 * n));
|
|
34311
|
+
}
|
|
34312
|
+
}
|
|
34313
|
+
if (view.units) {
|
|
34314
|
+
view.units.removeFromParent();
|
|
34315
|
+
view.units.dispose();
|
|
34316
|
+
}
|
|
34317
|
+
const units = new THREE.InstancedMesh(unitGeometry, unitMaterial, Math.max(1, list2.length));
|
|
34318
|
+
units.name = "breach:" + view.host;
|
|
34319
|
+
list2.forEach((u, i) => {
|
|
34320
|
+
tmp.m.compose(tmp.p.set(u.x, u.y, u.z), tmp.q.identity(), tmp.s.set(u.sx, u.sy, u.sz));
|
|
34321
|
+
units.setMatrixAt(i, tmp.m);
|
|
34322
|
+
units.setColorAt(i, tmp.c.setHex(u.colour));
|
|
34323
|
+
});
|
|
34324
|
+
units.count = list2.length;
|
|
34325
|
+
units.instanceMatrix.needsUpdate = true;
|
|
34326
|
+
if (units.instanceColor) units.instanceColor.needsUpdate = true;
|
|
34327
|
+
units.castShadow = true;
|
|
34328
|
+
units.receiveShadow = true;
|
|
34329
|
+
units.visible = lod === 0;
|
|
34330
|
+
house.add(units);
|
|
34331
|
+
view.units = units;
|
|
34332
|
+
view.gone = holes.length;
|
|
33828
34333
|
}
|
|
33829
34334
|
function draw2(partId, change) {
|
|
33830
34335
|
if (lod !== 0) return false;
|
|
33831
|
-
const
|
|
33832
|
-
|
|
33833
|
-
|
|
33834
|
-
let view = views.get(partId);
|
|
34336
|
+
const hostId = hostOf(partId);
|
|
34337
|
+
if (!hostId || !specOf(partId)?.units) return false;
|
|
34338
|
+
let view = views.get(hostId);
|
|
33835
34339
|
if (!view) {
|
|
33836
|
-
const items = structure.meshesOf(
|
|
34340
|
+
const items = structure.meshesOf(hostId).filter((it) => it.mesh);
|
|
33837
34341
|
if (!items.length) return false;
|
|
33838
|
-
|
|
34342
|
+
const parts = [hostId, ...riders(hostId)].filter((id) => structure.byId.get(id) && specOf(id)?.units);
|
|
34343
|
+
if (!parts.includes(partId)) return false;
|
|
34344
|
+
const mask = maskOf(hostId, parts);
|
|
34345
|
+
view = { host: hostId, parts, items, mask, shells: [], saved: null, units: null, gone: 0, chips: new Map(parts.map((id) => [id, []])), openings: /* @__PURE__ */ new Map() };
|
|
33839
34346
|
}
|
|
34347
|
+
if (!view.chips.has(partId)) return false;
|
|
33840
34348
|
if (change.opening) {
|
|
33841
|
-
if (view.
|
|
33842
|
-
view.
|
|
34349
|
+
if (view.openings.has(partId)) return false;
|
|
34350
|
+
view.openings.set(partId, { center: local2(change.opening.center), radius: change.opening.radius });
|
|
33843
34351
|
}
|
|
33844
|
-
if (change.chip) view.chips.push(local2(change.chip));
|
|
33845
|
-
|
|
33846
|
-
|
|
33847
|
-
view.
|
|
33848
|
-
view.mesh.dispose();
|
|
34352
|
+
if (change.chip) view.chips.get(partId).push(local2(change.chip));
|
|
34353
|
+
if (!view.saved) {
|
|
34354
|
+
view.shells = view.items.map((it) => shell(it, view.mask));
|
|
34355
|
+
view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
33849
34356
|
}
|
|
33850
|
-
|
|
33851
|
-
|
|
33852
|
-
list2.forEach((u, i) => {
|
|
33853
|
-
tmp.m.compose(tmp.p.set(u.x, u.y, u.z), tmp.q.identity(), tmp.s.set(u.sx, u.sy, u.sz));
|
|
33854
|
-
mesh3.setMatrixAt(i, tmp.m);
|
|
33855
|
-
mesh3.setColorAt(i, tmp.c.setHex(u.colour));
|
|
33856
|
-
});
|
|
33857
|
-
mesh3.count = list2.length;
|
|
33858
|
-
mesh3.instanceMatrix.needsUpdate = true;
|
|
33859
|
-
if (mesh3.instanceColor) mesh3.instanceColor.needsUpdate = true;
|
|
33860
|
-
mesh3.castShadow = true;
|
|
33861
|
-
mesh3.receiveShadow = true;
|
|
33862
|
-
house.add(mesh3);
|
|
33863
|
-
if (!view.saved) view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
33864
|
-
view.mesh = mesh3;
|
|
33865
|
-
view.units = list2.length;
|
|
33866
|
-
views.set(partId, view);
|
|
34357
|
+
paint2(view);
|
|
34358
|
+
views.set(hostId, view);
|
|
33867
34359
|
invalidate();
|
|
33868
34360
|
invalidateShadow();
|
|
33869
34361
|
return true;
|
|
@@ -33874,30 +34366,40 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33874
34366
|
else s.data = collapseRange(s.it.mesh, s.v0, s.it.v1);
|
|
33875
34367
|
}
|
|
33876
34368
|
}
|
|
34369
|
+
function dispose(view) {
|
|
34370
|
+
view.units.removeFromParent();
|
|
34371
|
+
view.units.dispose();
|
|
34372
|
+
for (const m of view.shells) {
|
|
34373
|
+
m.removeFromParent();
|
|
34374
|
+
m.geometry.dispose();
|
|
34375
|
+
m.material.dispose();
|
|
34376
|
+
}
|
|
34377
|
+
view.mask.texture.dispose();
|
|
34378
|
+
}
|
|
33877
34379
|
return {
|
|
33878
|
-
/** Handles a `stage` event of the house's object. Returns true when the wall was
|
|
34380
|
+
/** Handles a `stage` event of the house's object. Returns true when the wall was cut. */
|
|
33879
34381
|
stage(event) {
|
|
33880
34382
|
return event.stage === 2 && !!event.opening ? draw2(event.part, { opening: event.opening }) : false;
|
|
33881
34383
|
},
|
|
33882
|
-
/** Handles a `chip` event: the unit that came out leaves a
|
|
34384
|
+
/** Handles a `chip` event: the unit that came out leaves a hole in the wall where it was. Returns true when the wall was cut. */
|
|
33883
34385
|
chip(event) {
|
|
33884
34386
|
return draw2(event.part, { chip: event.center });
|
|
33885
34387
|
},
|
|
33886
|
-
/** The part broke or fell:
|
|
34388
|
+
/** The part broke or fell: its damage goes (the plain range stays collapsed, the renderer hides the part). */
|
|
33887
34389
|
drop(partId) {
|
|
33888
34390
|
const v = views.get(partId);
|
|
33889
34391
|
if (!v) return;
|
|
33890
|
-
v
|
|
33891
|
-
v.mesh.dispose();
|
|
34392
|
+
dispose(v);
|
|
33892
34393
|
views.delete(partId);
|
|
33893
34394
|
},
|
|
33894
|
-
/** LOD 0 draws the
|
|
34395
|
+
/** LOD 0 draws the cut wall; LOD 1 and 2 give the wall its box back. */
|
|
33895
34396
|
setLod(level) {
|
|
33896
34397
|
const was = lod;
|
|
33897
34398
|
lod = level;
|
|
33898
34399
|
if (was === 0 === (level === 0)) return;
|
|
33899
34400
|
for (const v of views.values()) {
|
|
33900
|
-
v.
|
|
34401
|
+
v.units.visible = level === 0;
|
|
34402
|
+
for (const m of v.shells) m.visible = level === 0;
|
|
33901
34403
|
plain2(v, level !== 0);
|
|
33902
34404
|
}
|
|
33903
34405
|
invalidate();
|
|
@@ -33906,17 +34408,21 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33906
34408
|
/** Everything back to what it was (after `world.reset`). */
|
|
33907
34409
|
restore() {
|
|
33908
34410
|
for (const v of views.values()) {
|
|
33909
|
-
v
|
|
33910
|
-
v.mesh.dispose();
|
|
34411
|
+
dispose(v);
|
|
33911
34412
|
if (lod === 0) plain2(v, true);
|
|
33912
34413
|
}
|
|
33913
34414
|
views.clear();
|
|
33914
34415
|
},
|
|
33915
|
-
/** The wall
|
|
34416
|
+
/** The wall has damage drawn. */
|
|
33916
34417
|
has(partId) {
|
|
33917
34418
|
return views.has(partId);
|
|
33918
34419
|
},
|
|
33919
|
-
|
|
34420
|
+
/** Walls with damage drawn, units out of them, and units laid bare at the edge of the cuts. */
|
|
34421
|
+
statistics: () => ({
|
|
34422
|
+
walls: views.size,
|
|
34423
|
+
gone: [...views.values()].reduce((n, v) => n + v.gone, 0),
|
|
34424
|
+
units: [...views.values()].reduce((n, v) => n + v.units.count, 0)
|
|
34425
|
+
})
|
|
33920
34426
|
};
|
|
33921
34427
|
}
|
|
33922
34428
|
Object.assign(K, { createBreachView });
|
|
@@ -34916,6 +35422,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34916
35422
|
return buildApi(K, shared);
|
|
34917
35423
|
}
|
|
34918
35424
|
var WOOD_THIN = 0.035;
|
|
35425
|
+
var BOARD_TOP_THICK = 0.07;
|
|
35426
|
+
var BOARD_TOP_WIDTH = 0.5;
|
|
35427
|
+
var BOARD_WIDTH = 0.16;
|
|
34919
35428
|
var SHELF_SPAN = 1.5;
|
|
34920
35429
|
var SHELVING = /shelf|bookcase|rack/;
|
|
34921
35430
|
function carcass(parts, drawn) {
|
|
@@ -34930,6 +35439,39 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34930
35439
|
} else if (y <= x && y <= z) part.structure = { role: "beam", maxSpan: SHELF_SPAN * Math.max(x, z) };
|
|
34931
35440
|
}
|
|
34932
35441
|
}
|
|
35442
|
+
function splitTopsIntoBoards(drawn, materialOf2, carcassed) {
|
|
35443
|
+
const tops = /* @__PURE__ */ new Map();
|
|
35444
|
+
if (carcassed) return tops;
|
|
35445
|
+
for (let i = drawn.length - 1; i >= 0; i--) {
|
|
35446
|
+
const p = drawn[i];
|
|
35447
|
+
if (p.key !== "wood" || materialOf2.wood !== "wood_hard" || p.shape.kind !== "box" || p.rotation) continue;
|
|
35448
|
+
const [sx, sy, sz] = p.shape.size;
|
|
35449
|
+
const across2 = sx < sz ? 0 : 2;
|
|
35450
|
+
const width = Math.min(sx, sz);
|
|
35451
|
+
if (sy < WOOD_THIN || sy > BOARD_TOP_THICK || sy >= width || width < BOARD_TOP_WIDTH) continue;
|
|
35452
|
+
const count = Math.round(width / BOARD_WIDTH);
|
|
35453
|
+
const boards = [];
|
|
35454
|
+
for (let b = 0; b < count; b++) {
|
|
35455
|
+
const size = [sx, sy, sz];
|
|
35456
|
+
size[across2] = width / count;
|
|
35457
|
+
const position = [...p.position];
|
|
35458
|
+
position[across2] += (b + 0.5) * size[across2] - width / 2;
|
|
35459
|
+
const min2 = [...p.min];
|
|
35460
|
+
const max2 = [...p.max];
|
|
35461
|
+
min2[across2] = position[across2] - size[across2] / 2;
|
|
35462
|
+
max2[across2] = position[across2] + size[across2] / 2;
|
|
35463
|
+
boards.push({ ...p, id: `${p.id}_b${b}`, shape: { kind: "box", size }, position, min: min2, max: max2, color: shadeBoard(p.color, b) });
|
|
35464
|
+
}
|
|
35465
|
+
drawn.splice(i, 1, ...boards);
|
|
35466
|
+
tops.set(p.id, boards);
|
|
35467
|
+
}
|
|
35468
|
+
return tops;
|
|
35469
|
+
}
|
|
35470
|
+
function shadeBoard(color2, board) {
|
|
35471
|
+
const k = [1, 0.94, 1.05, 0.97, 1.03][board % 5];
|
|
35472
|
+
const channel = (shift) => Math.min(255, Math.round((color2 >> shift & 255) * k)) << shift;
|
|
35473
|
+
return channel(16) | channel(8) | channel(0);
|
|
35474
|
+
}
|
|
34933
35475
|
var FLOOR_TOUCH = 5e-3;
|
|
34934
35476
|
var LOOSE = /* @__PURE__ */ new Set(["paper"]);
|
|
34935
35477
|
var BASE_MATERIAL = {
|
|
@@ -35007,10 +35549,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
35007
35549
|
};
|
|
35008
35550
|
run(A);
|
|
35009
35551
|
if (!drawn.length) throw new Error(`game-floorplan-three: the builder of "${name}" drew no box or cylinder`);
|
|
35552
|
+
const boardsOf = splitTopsIntoBoards(drawn, materialOf2, Boolean(opts.carcass));
|
|
35010
35553
|
const parts = drawn.map((p) => {
|
|
35011
35554
|
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]);
|
|
35012
35555
|
let material = materialOf2[p.key] ?? "plastic";
|
|
35013
|
-
if (p.key === "wood" && material === "wood_hard" &&
|
|
35556
|
+
if (p.key === "wood" && material === "wood_hard" && opts.carcass && !opts.materials?.wood) material = "mdf";
|
|
35557
|
+
else if (p.key === "wood" && material === "wood_hard" && thin < WOOD_THIN) material = "wood_soft";
|
|
35014
35558
|
const part = { id: p.id, material, shape: p.shape, position: p.position };
|
|
35015
35559
|
if (p.rotation) part.rotation = p.rotation;
|
|
35016
35560
|
if (!LOOSE.has(material) && p.min[1] <= FLOOR_TOUCH) part.anchored = true;
|
|
@@ -35045,6 +35589,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
35045
35589
|
if (area3 < 0.6 * footprint || p.max[1] < 0.2) continue;
|
|
35046
35590
|
if (!top || p.max[1] > top.y + 1e-6) top = { part: p.id, y: p.max[1] };
|
|
35047
35591
|
}
|
|
35592
|
+
for (const boards of boardsOf.values()) {
|
|
35593
|
+
if (top && boards[0].max[1] <= top.y - 1e-6) continue;
|
|
35594
|
+
const mid = boards[boards.length >> 1];
|
|
35595
|
+
const min2 = [Math.min(...boards.map((b) => b.min[0])), Math.min(...boards.map((b) => b.min[2]))];
|
|
35596
|
+
const max2 = [Math.max(...boards.map((b) => b.max[0])), Math.max(...boards.map((b) => b.max[2]))];
|
|
35597
|
+
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) };
|
|
35598
|
+
}
|
|
35048
35599
|
if (opts.carcass) carcass(parts, byId);
|
|
35049
35600
|
const spec = { name, parts, joints, tags: ["furniture"] };
|
|
35050
35601
|
const colors = new Map(drawn.map((p) => [p.id, p.color]));
|
|
@@ -38674,8 +39225,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
38674
39225
|
bedHeight = roadY * 1e3 + z * 14 - (x - params.roadSlopeAnchorX) * 5;
|
|
38675
39226
|
roughness = 0.55;
|
|
38676
39227
|
}
|
|
38677
|
-
const
|
|
38678
|
-
bed[index] = bedHeight + (
|
|
39228
|
+
const noise3 = valueNoise(column * 0.35, row * 0.35) * 0.6 + valueNoise(column * 1.3, row * 1.3) * 0.4;
|
|
39229
|
+
bed[index] = bedHeight + (noise3 - 0.5) * roughness * 2;
|
|
38679
39230
|
vertical[index] = region === 0 || region === 2 ? 0.95 : 1;
|
|
38680
39231
|
pin[index] = 0.62 + 0.76 * (valueNoise(column * 0.21 + 40, row * 0.21) * 0.5 + hashCell(column, row) * 0.5) * (region === 3 ? 1.25 : 1);
|
|
38681
39232
|
}
|
|
@@ -39099,14 +39650,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39099
39650
|
},
|
|
39100
39651
|
tessellate: {
|
|
39101
39652
|
cylinder: {
|
|
39102
|
-
heightSegments:
|
|
39103
|
-
radialSegments:
|
|
39653
|
+
heightSegments: 24,
|
|
39654
|
+
radialSegments: 40,
|
|
39655
|
+
capRings: 6
|
|
39104
39656
|
},
|
|
39105
39657
|
box: {
|
|
39106
39658
|
widthSegments: 6,
|
|
39107
39659
|
heightSegments: 1,
|
|
39108
39660
|
depthSegments: 4
|
|
39109
39661
|
}
|
|
39662
|
+
},
|
|
39663
|
+
wall: {
|
|
39664
|
+
body: 1e-4,
|
|
39665
|
+
ends: 25e-5
|
|
39110
39666
|
}
|
|
39111
39667
|
}
|
|
39112
39668
|
},
|
|
@@ -39130,14 +39686,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39130
39686
|
},
|
|
39131
39687
|
tessellate: {
|
|
39132
39688
|
cylinder: {
|
|
39133
|
-
heightSegments:
|
|
39134
|
-
radialSegments:
|
|
39689
|
+
heightSegments: 24,
|
|
39690
|
+
radialSegments: 40,
|
|
39691
|
+
capRings: 6
|
|
39135
39692
|
},
|
|
39136
39693
|
box: {
|
|
39137
39694
|
widthSegments: 6,
|
|
39138
39695
|
heightSegments: 1,
|
|
39139
39696
|
depthSegments: 4
|
|
39140
39697
|
}
|
|
39698
|
+
},
|
|
39699
|
+
wall: {
|
|
39700
|
+
body: 18e-5,
|
|
39701
|
+
ends: 22e-5
|
|
39141
39702
|
}
|
|
39142
39703
|
}
|
|
39143
39704
|
}
|
|
@@ -39227,12 +39788,53 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39227
39788
|
if (!box22) return 0;
|
|
39228
39789
|
return (box22.max.x - box22.min.x) * (box22.max.y - box22.min.y) * (box22.max.z - box22.min.z);
|
|
39229
39790
|
}
|
|
39230
|
-
function
|
|
39791
|
+
function ringedCylinder(T2, p, radial, maxRows, rings) {
|
|
39792
|
+
const half = p.height / 2;
|
|
39793
|
+
const column = 2 * Math.PI * Math.max(p.radiusTop, p.radiusBottom, 1e-6) / radial;
|
|
39794
|
+
const rows = Math.max(1, Math.min(maxRows, Math.round(p.height / column)));
|
|
39795
|
+
const points = [];
|
|
39796
|
+
if (!p.openEnded) for (let i = 0; i <= rings; i++) points.push(new T2.Vector2(p.radiusBottom * i / rings, -half));
|
|
39797
|
+
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));
|
|
39798
|
+
if (!p.openEnded) for (let i = rings; i >= 0; i--) points.push(new T2.Vector2(p.radiusTop * i / rings, half));
|
|
39799
|
+
return lathed(T2, points, radial, p.thetaStart, p.thetaLength);
|
|
39800
|
+
}
|
|
39801
|
+
function lathed(T2, points, radial, phiStart, phiLength) {
|
|
39802
|
+
const geometry = new T2.LatheGeometry([...points], radial, phiStart, phiLength);
|
|
39803
|
+
geometry.computeVertexNormals();
|
|
39804
|
+
const position = geometry.getAttribute("position");
|
|
39805
|
+
const normal = geometry.getAttribute("normal");
|
|
39806
|
+
const middle = (Math.min(...points.map((point) => point.y)) + Math.max(...points.map((point) => point.y))) / 2;
|
|
39807
|
+
for (let i = 0; i < normal.count; i++) {
|
|
39808
|
+
if (Math.hypot(normal.getX(i), normal.getY(i), normal.getZ(i)) > 0.5) continue;
|
|
39809
|
+
normal.setXYZ(i, 0, position.getY(i) >= middle ? 1 : -1, 0);
|
|
39810
|
+
}
|
|
39811
|
+
return geometry;
|
|
39812
|
+
}
|
|
39813
|
+
function finerProfile(T2, points, step) {
|
|
39814
|
+
const out = [];
|
|
39815
|
+
points.forEach((point, index) => {
|
|
39816
|
+
const next = points[index + 1];
|
|
39817
|
+
out.push(point.clone());
|
|
39818
|
+
if (!next) return;
|
|
39819
|
+
const pieces = Math.max(1, Math.round(point.distanceTo(next) / step));
|
|
39820
|
+
for (let k = 1; k < pieces; k++) out.push(point.clone().lerp(next, k / pieces));
|
|
39821
|
+
});
|
|
39822
|
+
return out;
|
|
39823
|
+
}
|
|
39824
|
+
function tessellated(geometry, rule, T2) {
|
|
39231
39825
|
const Shape = geometry.constructor;
|
|
39232
39826
|
if (geometry.type === "CylinderGeometry" && rule.cylinder) {
|
|
39233
|
-
const
|
|
39827
|
+
const parameters = geometry.parameters;
|
|
39828
|
+
const { radiusTop, radiusBottom, height, openEnded, thetaStart, thetaLength } = parameters;
|
|
39829
|
+
if (T2 && rule.cylinder.capRings !== void 0) return ringedCylinder(T2, parameters, rule.cylinder.radialSegments, rule.cylinder.heightSegments, rule.cylinder.capRings);
|
|
39234
39830
|
return new Shape(radiusTop, radiusBottom, height, rule.cylinder.radialSegments, rule.cylinder.heightSegments, openEnded, thetaStart, thetaLength);
|
|
39235
39831
|
}
|
|
39832
|
+
if (geometry.type === "LatheGeometry" && rule.cylinder && T2 && rule.cylinder.capRings !== void 0) {
|
|
39833
|
+
const { points, segments, phiStart, phiLength } = geometry.parameters;
|
|
39834
|
+
if (segments >= rule.cylinder.radialSegments) return void 0;
|
|
39835
|
+
const widest = Math.max(...points.map((point) => point.x), 1e-6);
|
|
39836
|
+
return lathed(T2, finerProfile(T2, points, 2 * Math.PI * widest / rule.cylinder.radialSegments), rule.cylinder.radialSegments, phiStart, phiLength);
|
|
39837
|
+
}
|
|
39236
39838
|
if (geometry.type === "BoxGeometry" && rule.box) {
|
|
39237
39839
|
const { width, height, depth } = geometry.parameters;
|
|
39238
39840
|
return new Shape(width, height, depth, rule.box.widthSegments, rule.box.heightSegments, rule.box.depthSegments);
|
|
@@ -39240,14 +39842,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39240
39842
|
return void 0;
|
|
39241
39843
|
}
|
|
39242
39844
|
var triangleCount = (geometry) => (geometry.index ? geometry.index.count : geometry.getAttribute("position").count) / 3;
|
|
39243
|
-
function tessellateShapes(root, rule) {
|
|
39845
|
+
function tessellateShapes(root, rule, T2) {
|
|
39244
39846
|
const rebuilt = /* @__PURE__ */ new Map();
|
|
39245
39847
|
root.traverse((object2) => {
|
|
39246
39848
|
const mesh3 = object2;
|
|
39247
39849
|
if (!mesh3.isMesh) return;
|
|
39248
39850
|
let fresh = rebuilt.get(mesh3.geometry);
|
|
39249
39851
|
if (!fresh) {
|
|
39250
|
-
fresh = tessellated(mesh3.geometry, rule);
|
|
39852
|
+
fresh = tessellated(mesh3.geometry, rule, T2);
|
|
39251
39853
|
if (!fresh) return;
|
|
39252
39854
|
rebuilt.set(mesh3.geometry, fresh);
|
|
39253
39855
|
}
|
|
@@ -39261,10 +39863,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39261
39863
|
root.userData.tessellationTriangles = added;
|
|
39262
39864
|
}
|
|
39263
39865
|
function tagForDestruction(root, options = {}) {
|
|
39264
|
-
const { modelId, weight, size } = options;
|
|
39866
|
+
const { modelId, weight, size, three } = options;
|
|
39265
39867
|
if (weight !== void 0 && weight > 0) root.userData.destructionMass = weight;
|
|
39266
39868
|
const rule = modelId === void 0 ? void 0 : itemDestruction(modelId);
|
|
39267
|
-
if (rule?.tessellate) tessellateShapes(root, rule.tessellate);
|
|
39869
|
+
if (rule?.tessellate) tessellateShapes(root, rule.tessellate, three);
|
|
39268
39870
|
const solid2 = [];
|
|
39269
39871
|
root.traverse((object2) => {
|
|
39270
39872
|
const mesh3 = object2;
|
|
@@ -39284,6 +39886,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39284
39886
|
const anchor = solid2.reduce((largest, mesh3) => volumeOf(mesh3) > volumeOf(largest) ? mesh3 : largest);
|
|
39285
39887
|
solid2.forEach((mesh3, index) => {
|
|
39286
39888
|
mesh3.userData.destructionPart = mesh3 === anchor ? { id: SHELL_PART_ID } : { id: `shell_${index}`, parent: SHELL_PART_ID, kind: "weld" };
|
|
39889
|
+
if (rule.wall) mesh3.userData.destructionThickness = mesh3 === anchor ? rule.wall.body : rule.wall.ends;
|
|
39287
39890
|
});
|
|
39288
39891
|
const contents = size === void 0 ? void 0 : itemContents({ ...modelId === void 0 ? {} : { model: modelId }, size, ...weight === void 0 ? {} : { weight } });
|
|
39289
39892
|
if (contents) anchor.userData.destructionContains = { fluid: contents.liquid, liters: contents.liters };
|
|
@@ -44895,7 +45498,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
44895
45498
|
const materials = kit.materials.slice(first);
|
|
44896
45499
|
if (options.wear) setWear(materials, options.wear);
|
|
44897
45500
|
root.userData.wear = options.wear ?? 0;
|
|
44898
|
-
if (options.destructible) tagForDestruction(root, { ...kind === "model" && item.model !== void 0 ? { modelId: item.model } : {}, ...item.weight === void 0 ? {} : { weight: item.weight }, size: item.size });
|
|
45501
|
+
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 });
|
|
44899
45502
|
markKitOrigin(root, { owner: "game-items-three", kind: "item", id: item.id, ...kind === "shape" ? { standIn: true } : {} });
|
|
44900
45503
|
return { root, kind, ...shape ? { shape } : {}, size: item.size, materials };
|
|
44901
45504
|
}
|
|
@@ -55735,6 +56338,24 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
55735
56338
|
for (const decal2 of this.decals) decal2.on = false;
|
|
55736
56339
|
this.count = 0;
|
|
55737
56340
|
}
|
|
56341
|
+
/**
|
|
56342
|
+
* Takes away the marks inside a box: world `center`, `half` extents along the axes of the world `rotation` (a quaternion, x y z w; none means the
|
|
56343
|
+
* world axes). The surface they were on is gone (a brick came out of a wall with its bullet holes). Returns how many went.
|
|
56344
|
+
*/
|
|
56345
|
+
clearInside(center, half, rotation = [0, 0, 0, 1]) {
|
|
56346
|
+
const qx = -rotation[0], qy = -rotation[1], qz = -rotation[2], qw = rotation[3];
|
|
56347
|
+
let gone = 0;
|
|
56348
|
+
for (const decal2 of this.decals) {
|
|
56349
|
+
if (!decal2.on) continue;
|
|
56350
|
+
const vx2 = decal2.x - center[0], vy2 = decal2.y - center[1], vz2 = decal2.z - center[2];
|
|
56351
|
+
const tx = 2 * (qy * vz2 - qz * vy2), ty = 2 * (qz * vx2 - qx * vz2), tz = 2 * (qx * vy2 - qy * vx2);
|
|
56352
|
+
const lx = vx2 + qw * tx + (qy * tz - qz * ty), ly = vy2 + qw * ty + (qz * tx - qx * tz), lz = vz2 + qw * tz + (qx * ty - qy * tx);
|
|
56353
|
+
if (Math.abs(lx) > half[0] || Math.abs(ly) > half[1] || Math.abs(lz) > half[2]) continue;
|
|
56354
|
+
decal2.on = false;
|
|
56355
|
+
gone++;
|
|
56356
|
+
}
|
|
56357
|
+
return gone;
|
|
56358
|
+
}
|
|
55738
56359
|
update(dt) {
|
|
55739
56360
|
this.count = 0;
|
|
55740
56361
|
for (const decal2 of this.decals) {
|
|
@@ -60375,6 +60996,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
60375
60996
|
return {
|
|
60376
60997
|
id: "weapons_area",
|
|
60377
60998
|
name: text.name,
|
|
60999
|
+
ground: { surface: "concrete_slab" },
|
|
60378
61000
|
group: text.group,
|
|
60379
61001
|
get audio() {
|
|
60380
61002
|
return audio;
|
|
@@ -61437,6 +62059,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
61437
62059
|
return {
|
|
61438
62060
|
id: EXPLOSIVES_AREA_ID,
|
|
61439
62061
|
name: text.name,
|
|
62062
|
+
ground: { surface: "concrete_slab" },
|
|
61440
62063
|
group: text.group,
|
|
61441
62064
|
bench,
|
|
61442
62065
|
// 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
|