@adatechnology/game-weapons-three 0.10.1 → 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 +532 -54
- 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,6 +21129,17 @@ 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",
|
|
21075
21145
|
thermal: {
|
|
@@ -21438,7 +21508,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21438
21508
|
smoke: "white"
|
|
21439
21509
|
},
|
|
21440
21510
|
visual: {
|
|
21441
|
-
charColor: 1709072
|
|
21511
|
+
charColor: 1709072,
|
|
21512
|
+
innerColor: 14207126
|
|
21442
21513
|
},
|
|
21443
21514
|
tags: [
|
|
21444
21515
|
"plant",
|
|
@@ -21446,7 +21517,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21446
21517
|
"organic",
|
|
21447
21518
|
"flammable"
|
|
21448
21519
|
],
|
|
21449
|
-
compressive: 6e4
|
|
21520
|
+
compressive: 6e4,
|
|
21521
|
+
hits: {
|
|
21522
|
+
blunt: {
|
|
21523
|
+
tear: "none"
|
|
21524
|
+
}
|
|
21525
|
+
}
|
|
21450
21526
|
},
|
|
21451
21527
|
{
|
|
21452
21528
|
id: "cactus",
|
|
@@ -21561,6 +21637,130 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21561
21637
|
"masonry"
|
|
21562
21638
|
],
|
|
21563
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
|
|
21564
21764
|
}
|
|
21565
21765
|
];
|
|
21566
21766
|
var material_hints_default = {
|
|
@@ -21734,6 +21934,32 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21734
21934
|
return (1 + 4 * (0.3 - ductility) / 0.3) * Math.min(25, Math.max(1, (0.02 / Math.max(thickness, 1e-4)) ** 2));
|
|
21735
21935
|
};
|
|
21736
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;
|
|
21737
21963
|
var DMG_PER_J = 0.02;
|
|
21738
21964
|
var BLAST_COUPLING = 0.1;
|
|
21739
21965
|
var SHELTER_DEFAULTS = { k: 2800, brokenTransmission: 0.5, minPath: 5e-3 };
|
|
@@ -21750,11 +21976,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21750
21976
|
var SEVER_BAND = 0.1;
|
|
21751
21977
|
var SEVER_ASPECT = 3;
|
|
21752
21978
|
var SEVER_BALLISTIC = 2;
|
|
21979
|
+
var TEAR_JOULES = 150;
|
|
21980
|
+
var tears = 0;
|
|
21753
21981
|
var SUPPORT_TOLERANCE = 0.05;
|
|
21754
21982
|
var UNIT_FRAGMENT_FACTOR = 4;
|
|
21755
21983
|
var BREACH_GRID_CAP = 4096;
|
|
21756
21984
|
var CHIP_ENERGY = 200;
|
|
21757
21985
|
var CHIP_SPLASH = 0.5;
|
|
21986
|
+
var BAR_BOW = 0.08;
|
|
21758
21987
|
var CUT_SLICE = 1;
|
|
21759
21988
|
var cutFactorOf = (shape) => clamp2(Math.max(...shapeDims(shape)) / CUT_SLICE, 1, 50);
|
|
21760
21989
|
var clamp2 = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
@@ -21764,8 +21993,24 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
21764
21993
|
return v === void 0 ? void 0 : v * (mat.penetrationScale ?? 1);
|
|
21765
21994
|
};
|
|
21766
21995
|
var capacityScale = (p) => {
|
|
21767
|
-
|
|
21768
|
-
|
|
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);
|
|
21769
22014
|
};
|
|
21770
22015
|
var isLost = (p) => p.st.status === "broken" || p.st.status === "melted" || p.st.status === "ashes";
|
|
21771
22016
|
var clone = (v) => structuredClone(v);
|
|
@@ -22946,6 +23191,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
22946
23191
|
debris2(o, p, layer2.mat.hitDebris, wp, normal, 5, 2, src);
|
|
22947
23192
|
setStage(o, p, 1, {}, src);
|
|
22948
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
|
+
};
|
|
22949
23200
|
const insideOpening = (o, p, objectPoint) => {
|
|
22950
23201
|
const op = p.st.opening;
|
|
22951
23202
|
if (!op) return false;
|
|
@@ -23022,9 +23273,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23022
23273
|
const lp = toLocal(p.pos, p.q, objectPoint);
|
|
23023
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);
|
|
23024
23275
|
};
|
|
23025
|
-
const chipUnits = (o, p, wp,
|
|
23276
|
+
const chipUnits = (o, p, kind, wp, hitEnergy, dir, radius, src) => {
|
|
23026
23277
|
var _a, _b;
|
|
23027
|
-
if (!p.spec.units ||
|
|
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;
|
|
23028
23283
|
const [u, v] = planeAxes(p.thin);
|
|
23029
23284
|
const lp = toLocal(p.pos, p.q, objLocal(o, wp));
|
|
23030
23285
|
const grid = gridOf(p);
|
|
@@ -23038,7 +23293,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23038
23293
|
const share = gap === 0 ? 1 : CHIP_SPLASH * (1 - gap / radius);
|
|
23039
23294
|
const total = (worn[i] ?? 0) + energy * share;
|
|
23040
23295
|
const mass = p.mat.density * cell.size[0] * cell.size[1] * cell.size[2];
|
|
23041
|
-
if (total <
|
|
23296
|
+
if (total < perKg * mass) {
|
|
23042
23297
|
worn[i] = total;
|
|
23043
23298
|
continue;
|
|
23044
23299
|
}
|
|
@@ -23063,7 +23318,32 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23063
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 });
|
|
23064
23319
|
debris2(o, p, p.mat.breakDebris, center, vec.scale(dir ?? [0, 1, 0], -1), 6, 2, src);
|
|
23065
23320
|
}
|
|
23321
|
+
if (p.spec.reinforcement) exposeRebar(o, p, src);
|
|
23066
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) });
|
|
23067
23347
|
};
|
|
23068
23348
|
const openBreach = (o, p, center, total, energy, dir, src) => {
|
|
23069
23349
|
const [u, v] = planeAxes(p.thin);
|
|
@@ -23091,10 +23371,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23091
23371
|
setStage(o, p, 2, { opening: { center: worldCenter, radius }, fragments }, src);
|
|
23092
23372
|
debris2(o, p, p.mat.breakDebris, worldCenter, vec.scale(dir ?? [0, 1, 0], -1), 14, 3, src);
|
|
23093
23373
|
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
|
-
}
|
|
23374
|
+
if (reinforcement) exposeRebar(o, p, src);
|
|
23098
23375
|
if (p.structural) solveStructure(o);
|
|
23099
23376
|
};
|
|
23100
23377
|
const stripPart = (o, p, reinforcement, src) => {
|
|
@@ -23106,8 +23383,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23106
23383
|
p.st.burning = false;
|
|
23107
23384
|
p.rt.jet = false;
|
|
23108
23385
|
markDamaged(p);
|
|
23109
|
-
emit2({ ...base(o, src), type: "expose", part: p.spec.id, bars: worldBars(o, p, bars) });
|
|
23110
23386
|
solveStructure(o);
|
|
23387
|
+
exposeRebar(o, p, src);
|
|
23111
23388
|
collapseCheck(o, src);
|
|
23112
23389
|
};
|
|
23113
23390
|
const unitFragmentPlan = (p, cap) => {
|
|
@@ -23161,7 +23438,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23161
23438
|
const grain = p.spec.grain ? AXIS[p.spec.grain] : void 0;
|
|
23162
23439
|
const hitLocal = toLocal(c, q, hitW);
|
|
23163
23440
|
const unitPlan = p.spec.units ? unitFragmentPlan(p, maxFragments * UNIT_FRAGMENT_FACTOR) : [];
|
|
23164
|
-
const axis2 = style === "splinter" ? severAxis(p) : -1;
|
|
23441
|
+
const axis2 = style === "splinter" || style === "snap" ? severAxis(p) : -1;
|
|
23165
23442
|
const cutAt2 = axis2 < 0 ? void 0 : p.rt.cutAt ?? (origin ? hitLocal[axis2] : void 0);
|
|
23166
23443
|
const plan = unitPlan.length > 0 ? unitPlan : planFragments({
|
|
23167
23444
|
style,
|
|
@@ -23233,7 +23510,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23233
23510
|
};
|
|
23234
23511
|
const CHAIN_TRIGGER_OF = { ballistic: "shot", explosive: "explosion" };
|
|
23235
23512
|
const severAxis = (p) => {
|
|
23236
|
-
if (p.mat.fracture !== "splinter" || p.spec.shape.kind !== "box") return -1;
|
|
23513
|
+
if (p.mat.fracture !== "splinter" && p.mat.fracture !== "snap" || p.spec.shape.kind !== "box") return -1;
|
|
23237
23514
|
const d = p.dims;
|
|
23238
23515
|
const order = [0, 1, 2].sort((a, b) => d[b] - d[a]);
|
|
23239
23516
|
return d[order[0]] >= SEVER_ASPECT * d[order[1]] && d[order[0]] >= 3 * SEVER_BAND ? order[0] : -1;
|
|
@@ -23294,6 +23571,49 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23294
23571
|
}
|
|
23295
23572
|
}
|
|
23296
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
|
+
};
|
|
23297
23617
|
const ballistic = (o, p, entry2, n, d, E, caliber, pathLen, src, round5 = {}) => {
|
|
23298
23618
|
const mat = p.mat;
|
|
23299
23619
|
const piercing = round5.piercing ?? 1;
|
|
@@ -23322,6 +23642,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23322
23642
|
return { penetrated: false, exitEnergy: 0, damage: dmg2 };
|
|
23323
23643
|
}
|
|
23324
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);
|
|
23325
23646
|
const brittle = mat.ductility < 0.3;
|
|
23326
23647
|
const ratio = Ep / Math.max(thr, 1e-6);
|
|
23327
23648
|
const crackLen = clamp2(0.03 + ratio * 0.2, 0.03, 0.8);
|
|
@@ -23355,8 +23676,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23355
23676
|
} else addHole(o, p, entry2, n, caliber / 1e3, false, void 0, src);
|
|
23356
23677
|
debris2(o, p, mat.hitDebris, entry2, n, clamp2(Math.round(E / 60) + 2, 2, 14), clamp2(Math.sqrt(E) / 6, 1, 8), src);
|
|
23357
23678
|
wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true);
|
|
23358
|
-
const
|
|
23359
|
-
|
|
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);
|
|
23360
23683
|
return { penetrated, exitEnergy: penetrated ? penMm !== void 0 ? E * (1 - thr / Ep) : E - thr / (hard ? piercing : 1) : 0, exitPoint, damage: dmg };
|
|
23361
23684
|
};
|
|
23362
23685
|
const melee = (o, p, kind, E, point, n, d, contactR, src) => {
|
|
@@ -23364,14 +23687,20 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23364
23687
|
const thrMm = mat.penetration * p.thickness * 1e3;
|
|
23365
23688
|
const fragile = kind === "blunt" ? fragility(mat.ductility, p.thickness) : 1;
|
|
23366
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;
|
|
23367
23693
|
if (E > 0) {
|
|
23368
23694
|
if (kind === "blunt") {
|
|
23369
|
-
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);
|
|
23370
23696
|
else if (mat.ductility < 0.3) {
|
|
23371
23697
|
if (Ec >= 5) addCrack(o, p, point, n, clamp2(0.04 + Math.min(Ec, E * 6) * 8e-4, 0.04, 0.6), src);
|
|
23372
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);
|
|
23373
23699
|
} else if (mat.fracture === "tear") {
|
|
23374
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);
|
|
23375
23704
|
} else if (mat.ductility >= 0.5) {
|
|
23376
23705
|
addDent(o, p, point, n, Math.max(contactR, 0.01), clamp2(E * 4e-5, 5e-4, 0.02), src);
|
|
23377
23706
|
}
|
|
@@ -23384,7 +23713,8 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23384
23713
|
const scale = mat.damageScale?.[kind] ?? 1;
|
|
23385
23714
|
const done = applyDamage(o, p, Ec * DMG_PER_J * scale * (kind === "slash" ? p.cutFactor : 1), kind, point, d, E * 0.1, 12, src);
|
|
23386
23715
|
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);
|
|
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);
|
|
23388
23718
|
return done;
|
|
23389
23719
|
};
|
|
23390
23720
|
const blastPart = (o, p, point, energy, radius, src, res, reachAt) => {
|
|
@@ -23963,6 +24293,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
23963
24293
|
if (p.rt.stressT <= 0) {
|
|
23964
24294
|
p.rt.stressT = 0.5;
|
|
23965
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);
|
|
23966
24297
|
}
|
|
23967
24298
|
applyDamage(o, p, overloadRate(stress) * p.st.maxHp * dt, "blunt", null, null, 5, 3);
|
|
23968
24299
|
} else if (stress > 0.8 && p.mat.ductility < 0.3 && p.rt.stressT <= 0 && p.st.cracks.length < 6) {
|
|
@@ -24179,6 +24510,18 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
24179
24510
|
const r = raycastInternal(origin, direction, maxDistance);
|
|
24180
24511
|
return r ? { object: r.object, part: r.part, point: r.point, normal: r.normal, distance: r.distance } : null;
|
|
24181
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
|
+
},
|
|
24182
24525
|
shoot(origin, direction, energy, caliber, source, round5) {
|
|
24183
24526
|
const extras = typeof round5 === "number" ? { piercing: round5 } : round5 ?? {};
|
|
24184
24527
|
return withCollapses(run(() => {
|
|
@@ -25750,7 +26093,24 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
25750
26093
|
}
|
|
25751
26094
|
return spec;
|
|
25752
26095
|
};
|
|
25753
|
-
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
|
+
};
|
|
25754
26114
|
function toDestructibleSpec(structure, options = {}) {
|
|
25755
26115
|
const { safety = 0.65, redundancy = 0.97, safetyOthers = 0.45 } = options;
|
|
25756
26116
|
const kept = structure.parts.filter((part) => !options.filter || options.filter(part));
|
|
@@ -25767,7 +26127,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
25767
26127
|
const sizing = { safety, redundancy, safetyOthers };
|
|
25768
26128
|
const sized = { ...panels, capacities: options.sized === false ? /* @__PURE__ */ new Map() : sizeCapacities(panels.parts, panels.supports, sizing) };
|
|
25769
26129
|
const { parts, supports, capacities } = detail === "units" ? applyUnits(sized, structure) : sized;
|
|
25770
|
-
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));
|
|
25771
26131
|
const margin = options.terrainMargin ?? TERRAIN_MARGIN;
|
|
25772
26132
|
const x0 = Math.min(...parts.map((part) => part.aabb[0]));
|
|
25773
26133
|
const z0 = Math.min(...parts.map((part) => part.aabb[1]));
|
|
@@ -33732,7 +34092,11 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33732
34092
|
if (!pc || pc.unit) return sp;
|
|
33733
34093
|
if (pc.role !== "wall" && pc.role !== "partition") {
|
|
33734
34094
|
const def = getAssembly(pc.assembly || (pc.material === "concrete" && ["slab", "beam", "column", "stair"].includes(pc.role) ? "reinforced_concrete" : ""));
|
|
33735
|
-
|
|
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;
|
|
33736
34100
|
}
|
|
33737
34101
|
if (!pc.assembly) return sp;
|
|
33738
34102
|
const [u0, v0, u1, v1] = pc.aabb, alongU = u1 - u0 >= v1 - v0;
|
|
@@ -33826,29 +34190,44 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33826
34190
|
}
|
|
33827
34191
|
return list2;
|
|
33828
34192
|
}
|
|
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);
|
|
33829
34205
|
function draw2(partId, change) {
|
|
33830
34206
|
if (lod !== 0) return false;
|
|
33831
|
-
const
|
|
33832
|
-
|
|
33833
|
-
|
|
33834
|
-
let view = views.get(partId);
|
|
34207
|
+
const hostId = hostOf(partId);
|
|
34208
|
+
if (!hostId || !specOf(partId)?.units) return false;
|
|
34209
|
+
let view = views.get(hostId);
|
|
33835
34210
|
if (!view) {
|
|
33836
|
-
const items = structure.meshesOf(
|
|
34211
|
+
const items = structure.meshesOf(hostId).filter((it) => it.mesh);
|
|
33837
34212
|
if (!items.length) return false;
|
|
33838
|
-
|
|
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() };
|
|
33839
34215
|
}
|
|
34216
|
+
if (!view.chips.has(partId)) return false;
|
|
33840
34217
|
if (change.opening) {
|
|
33841
|
-
if (view.
|
|
33842
|
-
view.
|
|
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);
|
|
33843
34221
|
}
|
|
33844
|
-
if (change.chip) view.chips.push(local2(change.chip));
|
|
33845
|
-
const list2 =
|
|
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));
|
|
33846
34225
|
if (view.mesh) {
|
|
33847
34226
|
view.mesh.removeFromParent();
|
|
33848
34227
|
view.mesh.dispose();
|
|
33849
34228
|
}
|
|
33850
34229
|
const mesh3 = new THREE.InstancedMesh(unitGeometry, unitMaterial, Math.max(1, list2.length));
|
|
33851
|
-
mesh3.name = "breach:" +
|
|
34230
|
+
mesh3.name = "breach:" + hostId;
|
|
33852
34231
|
list2.forEach((u, i) => {
|
|
33853
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));
|
|
33854
34233
|
mesh3.setMatrixAt(i, tmp.m);
|
|
@@ -33863,7 +34242,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
33863
34242
|
if (!view.saved) view.saved = view.items.map((it) => ({ it, v0: it.v0, data: collapseRange(it.mesh, it.v0, it.v1) }));
|
|
33864
34243
|
view.mesh = mesh3;
|
|
33865
34244
|
view.units = list2.length;
|
|
33866
|
-
views.set(
|
|
34245
|
+
views.set(hostId, view);
|
|
33867
34246
|
invalidate();
|
|
33868
34247
|
invalidateShadow();
|
|
33869
34248
|
return true;
|
|
@@ -34916,6 +35295,9 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34916
35295
|
return buildApi(K, shared);
|
|
34917
35296
|
}
|
|
34918
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;
|
|
34919
35301
|
var SHELF_SPAN = 1.5;
|
|
34920
35302
|
var SHELVING = /shelf|bookcase|rack/;
|
|
34921
35303
|
function carcass(parts, drawn) {
|
|
@@ -34930,6 +35312,39 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
34930
35312
|
} else if (y <= x && y <= z) part.structure = { role: "beam", maxSpan: SHELF_SPAN * Math.max(x, z) };
|
|
34931
35313
|
}
|
|
34932
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
|
+
}
|
|
34933
35348
|
var FLOOR_TOUCH = 5e-3;
|
|
34934
35349
|
var LOOSE = /* @__PURE__ */ new Set(["paper"]);
|
|
34935
35350
|
var BASE_MATERIAL = {
|
|
@@ -35007,10 +35422,12 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
35007
35422
|
};
|
|
35008
35423
|
run(A);
|
|
35009
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));
|
|
35010
35426
|
const parts = drawn.map((p) => {
|
|
35011
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]);
|
|
35012
35428
|
let material = materialOf2[p.key] ?? "plastic";
|
|
35013
|
-
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";
|
|
35014
35431
|
const part = { id: p.id, material, shape: p.shape, position: p.position };
|
|
35015
35432
|
if (p.rotation) part.rotation = p.rotation;
|
|
35016
35433
|
if (!LOOSE.has(material) && p.min[1] <= FLOOR_TOUCH) part.anchored = true;
|
|
@@ -35045,6 +35462,13 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
35045
35462
|
if (area3 < 0.6 * footprint || p.max[1] < 0.2) continue;
|
|
35046
35463
|
if (!top || p.max[1] > top.y + 1e-6) top = { part: p.id, y: p.max[1] };
|
|
35047
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
|
+
}
|
|
35048
35472
|
if (opts.carcass) carcass(parts, byId);
|
|
35049
35473
|
const spec = { name, parts, joints, tags: ["furniture"] };
|
|
35050
35474
|
const colors = new Map(drawn.map((p) => [p.id, p.color]));
|
|
@@ -39099,14 +39523,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39099
39523
|
},
|
|
39100
39524
|
tessellate: {
|
|
39101
39525
|
cylinder: {
|
|
39102
|
-
heightSegments:
|
|
39103
|
-
radialSegments:
|
|
39526
|
+
heightSegments: 24,
|
|
39527
|
+
radialSegments: 40,
|
|
39528
|
+
capRings: 6
|
|
39104
39529
|
},
|
|
39105
39530
|
box: {
|
|
39106
39531
|
widthSegments: 6,
|
|
39107
39532
|
heightSegments: 1,
|
|
39108
39533
|
depthSegments: 4
|
|
39109
39534
|
}
|
|
39535
|
+
},
|
|
39536
|
+
wall: {
|
|
39537
|
+
body: 1e-4,
|
|
39538
|
+
ends: 25e-5
|
|
39110
39539
|
}
|
|
39111
39540
|
}
|
|
39112
39541
|
},
|
|
@@ -39130,14 +39559,19 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39130
39559
|
},
|
|
39131
39560
|
tessellate: {
|
|
39132
39561
|
cylinder: {
|
|
39133
|
-
heightSegments:
|
|
39134
|
-
radialSegments:
|
|
39562
|
+
heightSegments: 24,
|
|
39563
|
+
radialSegments: 40,
|
|
39564
|
+
capRings: 6
|
|
39135
39565
|
},
|
|
39136
39566
|
box: {
|
|
39137
39567
|
widthSegments: 6,
|
|
39138
39568
|
heightSegments: 1,
|
|
39139
39569
|
depthSegments: 4
|
|
39140
39570
|
}
|
|
39571
|
+
},
|
|
39572
|
+
wall: {
|
|
39573
|
+
body: 18e-5,
|
|
39574
|
+
ends: 22e-5
|
|
39141
39575
|
}
|
|
39142
39576
|
}
|
|
39143
39577
|
}
|
|
@@ -39227,12 +39661,53 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39227
39661
|
if (!box22) return 0;
|
|
39228
39662
|
return (box22.max.x - box22.min.x) * (box22.max.y - box22.min.y) * (box22.max.z - box22.min.z);
|
|
39229
39663
|
}
|
|
39230
|
-
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) {
|
|
39231
39698
|
const Shape = geometry.constructor;
|
|
39232
39699
|
if (geometry.type === "CylinderGeometry" && rule.cylinder) {
|
|
39233
|
-
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);
|
|
39234
39703
|
return new Shape(radiusTop, radiusBottom, height, rule.cylinder.radialSegments, rule.cylinder.heightSegments, openEnded, thetaStart, thetaLength);
|
|
39235
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
|
+
}
|
|
39236
39711
|
if (geometry.type === "BoxGeometry" && rule.box) {
|
|
39237
39712
|
const { width, height, depth } = geometry.parameters;
|
|
39238
39713
|
return new Shape(width, height, depth, rule.box.widthSegments, rule.box.heightSegments, rule.box.depthSegments);
|
|
@@ -39240,14 +39715,14 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39240
39715
|
return void 0;
|
|
39241
39716
|
}
|
|
39242
39717
|
var triangleCount = (geometry) => (geometry.index ? geometry.index.count : geometry.getAttribute("position").count) / 3;
|
|
39243
|
-
function tessellateShapes(root, rule) {
|
|
39718
|
+
function tessellateShapes(root, rule, T2) {
|
|
39244
39719
|
const rebuilt = /* @__PURE__ */ new Map();
|
|
39245
39720
|
root.traverse((object2) => {
|
|
39246
39721
|
const mesh3 = object2;
|
|
39247
39722
|
if (!mesh3.isMesh) return;
|
|
39248
39723
|
let fresh = rebuilt.get(mesh3.geometry);
|
|
39249
39724
|
if (!fresh) {
|
|
39250
|
-
fresh = tessellated(mesh3.geometry, rule);
|
|
39725
|
+
fresh = tessellated(mesh3.geometry, rule, T2);
|
|
39251
39726
|
if (!fresh) return;
|
|
39252
39727
|
rebuilt.set(mesh3.geometry, fresh);
|
|
39253
39728
|
}
|
|
@@ -39261,10 +39736,10 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39261
39736
|
root.userData.tessellationTriangles = added;
|
|
39262
39737
|
}
|
|
39263
39738
|
function tagForDestruction(root, options = {}) {
|
|
39264
|
-
const { modelId, weight, size } = options;
|
|
39739
|
+
const { modelId, weight, size, three } = options;
|
|
39265
39740
|
if (weight !== void 0 && weight > 0) root.userData.destructionMass = weight;
|
|
39266
39741
|
const rule = modelId === void 0 ? void 0 : itemDestruction(modelId);
|
|
39267
|
-
if (rule?.tessellate) tessellateShapes(root, rule.tessellate);
|
|
39742
|
+
if (rule?.tessellate) tessellateShapes(root, rule.tessellate, three);
|
|
39268
39743
|
const solid2 = [];
|
|
39269
39744
|
root.traverse((object2) => {
|
|
39270
39745
|
const mesh3 = object2;
|
|
@@ -39284,6 +39759,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
39284
39759
|
const anchor = solid2.reduce((largest, mesh3) => volumeOf(mesh3) > volumeOf(largest) ? mesh3 : largest);
|
|
39285
39760
|
solid2.forEach((mesh3, index) => {
|
|
39286
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;
|
|
39287
39763
|
});
|
|
39288
39764
|
const contents = size === void 0 ? void 0 : itemContents({ ...modelId === void 0 ? {} : { model: modelId }, size, ...weight === void 0 ? {} : { weight } });
|
|
39289
39765
|
if (contents) anchor.userData.destructionContains = { fluid: contents.liquid, liters: contents.liters };
|
|
@@ -44895,7 +45371,7 @@ uniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3
|
|
|
44895
45371
|
const materials = kit.materials.slice(first);
|
|
44896
45372
|
if (options.wear) setWear(materials, options.wear);
|
|
44897
45373
|
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 });
|
|
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 });
|
|
44899
45375
|
markKitOrigin(root, { owner: "game-items-three", kind: "item", id: item.id, ...kind === "shape" ? { standIn: true } : {} });
|
|
44900
45376
|
return { root, kind, ...shape ? { shape } : {}, size: item.size, materials };
|
|
44901
45377
|
}
|
|
@@ -60375,6 +60851,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
60375
60851
|
return {
|
|
60376
60852
|
id: "weapons_area",
|
|
60377
60853
|
name: text.name,
|
|
60854
|
+
ground: { surface: "concrete_slab" },
|
|
60378
60855
|
group: text.group,
|
|
60379
60856
|
get audio() {
|
|
60380
60857
|
return audio;
|
|
@@ -61437,6 +61914,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
61437
61914
|
return {
|
|
61438
61915
|
id: EXPLOSIVES_AREA_ID,
|
|
61439
61916
|
name: text.name,
|
|
61917
|
+
ground: { surface: "concrete_slab" },
|
|
61440
61918
|
group: text.group,
|
|
61441
61919
|
bench,
|
|
61442
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
|