@adatechnology/game-floorplan-structure 1.2.3 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +7 -1
- package/dist/index.global.js +390 -29
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +20 -2
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.global.js
CHANGED
|
@@ -32,6 +32,7 @@ var GameFloorplanStructure = (() => {
|
|
|
32
32
|
FLAT_ROOF_DEFAULTS: () => FLAT_ROOF_DEFAULTS,
|
|
33
33
|
GROUND: () => GROUND,
|
|
34
34
|
MECHANICAL_DEFAULTS: () => MECHANICAL_DEFAULTS,
|
|
35
|
+
MEMBER_CAGE: () => MEMBER_CAGE,
|
|
35
36
|
PILE_AREA: () => PILE_AREA,
|
|
36
37
|
PILE_DEFAULTS: () => PILE_DEFAULTS,
|
|
37
38
|
PLATE_DEFAULTS: () => PLATE_DEFAULTS,
|
|
@@ -2791,7 +2792,9 @@ var GameFloorplanStructure = (() => {
|
|
|
2791
2792
|
const band = { c: [root.c[0], root.c[1], root.c[2]], s: [dims[0], dims[1], dims[2]] };
|
|
2792
2793
|
band.c[L] = (lo + hi) / 2;
|
|
2793
2794
|
band.s[L] = Math.max(hi - lo, 0.01);
|
|
2794
|
-
|
|
2795
|
+
if (inp.style === "snap") {
|
|
2796
|
+
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] });
|
|
2797
|
+
} else for (const p of splinterBox(inp, band, Math.max(3, inp.maxFragments - out.length))) out.push(p);
|
|
2795
2798
|
return out;
|
|
2796
2799
|
};
|
|
2797
2800
|
var tearStack = (inp, root, t, u, v, n, sheet) => {
|
|
@@ -2822,6 +2825,7 @@ var GameFloorplanStructure = (() => {
|
|
|
2822
2825
|
const t = sorted[0];
|
|
2823
2826
|
const [u, v] = [sorted[1], sorted[2]].sort((a, b) => a - b);
|
|
2824
2827
|
if (style === "snap") {
|
|
2828
|
+
if (inp.cut) return severAt(inp, root, inp.cut.at, inp.cut.gap);
|
|
2825
2829
|
const n2 = Math.min(maxFragments, 2 + Math.floor(rnd() * 3));
|
|
2826
2830
|
for (const b of bsp(root, n2, [0, 1, 2], rnd)) out.push({ center: b.c, size: b.s, q: idq, shape: "slab", weight: b.s[0] * b.s[1] * b.s[2] });
|
|
2827
2831
|
return out;
|
|
@@ -2995,6 +2999,27 @@ var GameFloorplanStructure = (() => {
|
|
|
2995
2999
|
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]]));
|
|
2996
3000
|
return out;
|
|
2997
3001
|
};
|
|
3002
|
+
var clipBarsToBox = (bars, u, v, center, size) => {
|
|
3003
|
+
const out = [];
|
|
3004
|
+
for (const [a, b] of bars) {
|
|
3005
|
+
const axis = a[u] !== b[u] ? u : v;
|
|
3006
|
+
const other = axis === u ? v : u;
|
|
3007
|
+
if (Math.abs(a[other] - center[other]) > size[other] / 2) continue;
|
|
3008
|
+
const lo = Math.max(Math.min(a[axis], b[axis]), center[axis] - size[axis] / 2), hi = Math.min(Math.max(a[axis], b[axis]), center[axis] + size[axis] / 2);
|
|
3009
|
+
if (hi - lo < 1e-6) continue;
|
|
3010
|
+
const p = [a[0], a[1], a[2]], q = [b[0], b[1], b[2]];
|
|
3011
|
+
p[axis] = lo;
|
|
3012
|
+
q[axis] = hi;
|
|
3013
|
+
out.push([p, q]);
|
|
3014
|
+
}
|
|
3015
|
+
return out;
|
|
3016
|
+
};
|
|
3017
|
+
var bendBar = ([a, b], thin, bow, i) => {
|
|
3018
|
+
const length = Math.hypot(b[0] - a[0], b[1] - a[1], b[2] - a[2]);
|
|
3019
|
+
const m = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2, (a[2] + b[2]) / 2];
|
|
3020
|
+
m[thin] += (i % 2 === 0 ? 1 : -1) * bow * length;
|
|
3021
|
+
return [[a, m], [m, b]];
|
|
3022
|
+
};
|
|
2998
3023
|
var clipBarsToDisc = (bars, u, v, center, radius) => {
|
|
2999
3024
|
const out = [];
|
|
3000
3025
|
for (const [a, b] of bars) {
|
|
@@ -3915,14 +3940,21 @@ var GameFloorplanStructure = (() => {
|
|
|
3915
3940
|
smoke: "grey"
|
|
3916
3941
|
},
|
|
3917
3942
|
visual: {
|
|
3918
|
-
charColor: 1709072
|
|
3943
|
+
charColor: 1709072,
|
|
3944
|
+
innerColor: 14730131
|
|
3919
3945
|
},
|
|
3920
3946
|
tags: [
|
|
3921
3947
|
"wood",
|
|
3922
3948
|
"organic",
|
|
3923
3949
|
"flammable"
|
|
3924
3950
|
],
|
|
3925
|
-
compressive: 1e5
|
|
3951
|
+
compressive: 1e5,
|
|
3952
|
+
hits: {
|
|
3953
|
+
blunt: {
|
|
3954
|
+
tear: "splinters",
|
|
3955
|
+
tearJoules: 60
|
|
3956
|
+
}
|
|
3957
|
+
}
|
|
3926
3958
|
},
|
|
3927
3959
|
{
|
|
3928
3960
|
id: "wood_hard",
|
|
@@ -3952,14 +3984,21 @@ var GameFloorplanStructure = (() => {
|
|
|
3952
3984
|
smoke: "grey"
|
|
3953
3985
|
},
|
|
3954
3986
|
visual: {
|
|
3955
|
-
charColor: 1709072
|
|
3987
|
+
charColor: 1709072,
|
|
3988
|
+
innerColor: 13213802
|
|
3956
3989
|
},
|
|
3957
3990
|
tags: [
|
|
3958
3991
|
"wood",
|
|
3959
3992
|
"organic",
|
|
3960
3993
|
"flammable"
|
|
3961
3994
|
],
|
|
3962
|
-
compressive: 15e4
|
|
3995
|
+
compressive: 15e4,
|
|
3996
|
+
hits: {
|
|
3997
|
+
blunt: {
|
|
3998
|
+
tear: "splinters",
|
|
3999
|
+
tearJoules: 150
|
|
4000
|
+
}
|
|
4001
|
+
}
|
|
3963
4002
|
},
|
|
3964
4003
|
{
|
|
3965
4004
|
id: "plywood",
|
|
@@ -3989,14 +4028,24 @@ var GameFloorplanStructure = (() => {
|
|
|
3989
4028
|
smoke: "grey"
|
|
3990
4029
|
},
|
|
3991
4030
|
visual: {
|
|
3992
|
-
charColor: 1709072
|
|
4031
|
+
charColor: 1709072,
|
|
4032
|
+
innerColor: 14862234
|
|
3993
4033
|
},
|
|
3994
4034
|
tags: [
|
|
3995
4035
|
"wood",
|
|
3996
4036
|
"organic",
|
|
3997
4037
|
"flammable"
|
|
3998
4038
|
],
|
|
3999
|
-
compressive: 6e4
|
|
4039
|
+
compressive: 6e4,
|
|
4040
|
+
hits: {
|
|
4041
|
+
ballistic: {
|
|
4042
|
+
tear: "splinters"
|
|
4043
|
+
},
|
|
4044
|
+
blunt: {
|
|
4045
|
+
tear: "splinters",
|
|
4046
|
+
tearJoules: 80
|
|
4047
|
+
}
|
|
4048
|
+
}
|
|
4000
4049
|
},
|
|
4001
4050
|
{
|
|
4002
4051
|
id: "mdf",
|
|
@@ -4023,14 +4072,25 @@ var GameFloorplanStructure = (() => {
|
|
|
4023
4072
|
smoke: "grey"
|
|
4024
4073
|
},
|
|
4025
4074
|
visual: {
|
|
4026
|
-
charColor: 1709072
|
|
4075
|
+
charColor: 1709072,
|
|
4076
|
+
innerColor: 12096362
|
|
4027
4077
|
},
|
|
4028
4078
|
tags: [
|
|
4029
4079
|
"wood",
|
|
4030
4080
|
"organic",
|
|
4031
4081
|
"flammable"
|
|
4032
4082
|
],
|
|
4033
|
-
compressive: 3e4
|
|
4083
|
+
compressive: 3e4,
|
|
4084
|
+
hits: {
|
|
4085
|
+
ballistic: {
|
|
4086
|
+
tear: "lumps",
|
|
4087
|
+
tearJoules: 120
|
|
4088
|
+
},
|
|
4089
|
+
blunt: {
|
|
4090
|
+
tear: "lumps",
|
|
4091
|
+
tearJoules: 20
|
|
4092
|
+
}
|
|
4093
|
+
}
|
|
4034
4094
|
},
|
|
4035
4095
|
{
|
|
4036
4096
|
id: "glass",
|
|
@@ -4144,6 +4204,17 @@ var GameFloorplanStructure = (() => {
|
|
|
4144
4204
|
damageScale: {
|
|
4145
4205
|
explosive: 1.2
|
|
4146
4206
|
},
|
|
4207
|
+
hits: {
|
|
4208
|
+
ballistic: {
|
|
4209
|
+
unitJoules: 500,
|
|
4210
|
+
floor: 900,
|
|
4211
|
+
crater: true
|
|
4212
|
+
},
|
|
4213
|
+
blunt: {
|
|
4214
|
+
unitJoules: 1500,
|
|
4215
|
+
floor: 60
|
|
4216
|
+
}
|
|
4217
|
+
},
|
|
4147
4218
|
hitDebris: "chips",
|
|
4148
4219
|
breakDebris: "dust",
|
|
4149
4220
|
thermal: {
|
|
@@ -4512,7 +4583,8 @@ var GameFloorplanStructure = (() => {
|
|
|
4512
4583
|
smoke: "white"
|
|
4513
4584
|
},
|
|
4514
4585
|
visual: {
|
|
4515
|
-
charColor: 1709072
|
|
4586
|
+
charColor: 1709072,
|
|
4587
|
+
innerColor: 14207126
|
|
4516
4588
|
},
|
|
4517
4589
|
tags: [
|
|
4518
4590
|
"plant",
|
|
@@ -4520,7 +4592,12 @@ var GameFloorplanStructure = (() => {
|
|
|
4520
4592
|
"organic",
|
|
4521
4593
|
"flammable"
|
|
4522
4594
|
],
|
|
4523
|
-
compressive: 6e4
|
|
4595
|
+
compressive: 6e4,
|
|
4596
|
+
hits: {
|
|
4597
|
+
blunt: {
|
|
4598
|
+
tear: "none"
|
|
4599
|
+
}
|
|
4600
|
+
}
|
|
4524
4601
|
},
|
|
4525
4602
|
{
|
|
4526
4603
|
id: "cactus",
|
|
@@ -4635,6 +4712,130 @@ var GameFloorplanStructure = (() => {
|
|
|
4635
4712
|
"masonry"
|
|
4636
4713
|
],
|
|
4637
4714
|
compressive: 2e4
|
|
4715
|
+
},
|
|
4716
|
+
{
|
|
4717
|
+
id: "asphalt",
|
|
4718
|
+
density: 2350,
|
|
4719
|
+
hpPerKg: 10,
|
|
4720
|
+
penetration: 14,
|
|
4721
|
+
penetrationClass: "concrete",
|
|
4722
|
+
penetrationScale: 0.8,
|
|
4723
|
+
ductility: 0.1,
|
|
4724
|
+
fracture: "crumble",
|
|
4725
|
+
fragmentSize: [
|
|
4726
|
+
0.03,
|
|
4727
|
+
0.15
|
|
4728
|
+
],
|
|
4729
|
+
hitDebris: "chips",
|
|
4730
|
+
breakDebris: "dust",
|
|
4731
|
+
thermal: {
|
|
4732
|
+
conductivity: 0.1,
|
|
4733
|
+
heatCapacity: 2,
|
|
4734
|
+
ignitionC: 400,
|
|
4735
|
+
burnRate: 2e-3,
|
|
4736
|
+
smoke: "black"
|
|
4737
|
+
},
|
|
4738
|
+
tags: [
|
|
4739
|
+
"masonry",
|
|
4740
|
+
"brittle"
|
|
4741
|
+
],
|
|
4742
|
+
compressive: 3e4
|
|
4743
|
+
},
|
|
4744
|
+
{
|
|
4745
|
+
id: "sand",
|
|
4746
|
+
density: 1600,
|
|
4747
|
+
hpPerKg: 2,
|
|
4748
|
+
penetration: 6,
|
|
4749
|
+
ductility: 0.4,
|
|
4750
|
+
fracture: "crumble",
|
|
4751
|
+
fragmentSize: [
|
|
4752
|
+
0.01,
|
|
4753
|
+
0.04
|
|
4754
|
+
],
|
|
4755
|
+
hitDebris: "dust",
|
|
4756
|
+
breakDebris: "dust",
|
|
4757
|
+
thermal: {
|
|
4758
|
+
conductivity: 0.1,
|
|
4759
|
+
heatCapacity: 2
|
|
4760
|
+
},
|
|
4761
|
+
tags: [
|
|
4762
|
+
"soil"
|
|
4763
|
+
],
|
|
4764
|
+
compressive: 1e4
|
|
4765
|
+
},
|
|
4766
|
+
{
|
|
4767
|
+
id: "gravel",
|
|
4768
|
+
density: 1800,
|
|
4769
|
+
hpPerKg: 3,
|
|
4770
|
+
penetration: 8,
|
|
4771
|
+
ductility: 0.3,
|
|
4772
|
+
fracture: "crumble",
|
|
4773
|
+
fragmentSize: [
|
|
4774
|
+
0.02,
|
|
4775
|
+
0.06
|
|
4776
|
+
],
|
|
4777
|
+
hitDebris: "chips",
|
|
4778
|
+
breakDebris: "dust",
|
|
4779
|
+
thermal: {
|
|
4780
|
+
conductivity: 0.1,
|
|
4781
|
+
heatCapacity: 2
|
|
4782
|
+
},
|
|
4783
|
+
tags: [
|
|
4784
|
+
"soil",
|
|
4785
|
+
"masonry"
|
|
4786
|
+
],
|
|
4787
|
+
compressive: 2e4
|
|
4788
|
+
},
|
|
4789
|
+
{
|
|
4790
|
+
id: "turf",
|
|
4791
|
+
density: 900,
|
|
4792
|
+
hpPerKg: 3,
|
|
4793
|
+
penetration: 4,
|
|
4794
|
+
ductility: 0.5,
|
|
4795
|
+
fracture: "crumble",
|
|
4796
|
+
fragmentSize: [
|
|
4797
|
+
0.03,
|
|
4798
|
+
0.1
|
|
4799
|
+
],
|
|
4800
|
+
hitDebris: "dust",
|
|
4801
|
+
breakDebris: "dust",
|
|
4802
|
+
thermal: {
|
|
4803
|
+
conductivity: 0.1,
|
|
4804
|
+
heatCapacity: 1.5,
|
|
4805
|
+
ignitionC: 250,
|
|
4806
|
+
burnRate: 0.03,
|
|
4807
|
+
smoke: "white"
|
|
4808
|
+
},
|
|
4809
|
+
tags: [
|
|
4810
|
+
"soil",
|
|
4811
|
+
"organic"
|
|
4812
|
+
],
|
|
4813
|
+
compressive: 15e3
|
|
4814
|
+
},
|
|
4815
|
+
{
|
|
4816
|
+
id: "mortar",
|
|
4817
|
+
density: 1900,
|
|
4818
|
+
hpPerKg: 10,
|
|
4819
|
+
penetration: 12,
|
|
4820
|
+
penetrationClass: "concrete",
|
|
4821
|
+
penetrationScale: 1.2,
|
|
4822
|
+
ductility: 0.03,
|
|
4823
|
+
fracture: "crumble",
|
|
4824
|
+
fragmentSize: [
|
|
4825
|
+
0.02,
|
|
4826
|
+
0.08
|
|
4827
|
+
],
|
|
4828
|
+
hitDebris: "chips",
|
|
4829
|
+
breakDebris: "dust",
|
|
4830
|
+
thermal: {
|
|
4831
|
+
conductivity: 0.15,
|
|
4832
|
+
heatCapacity: 2.5
|
|
4833
|
+
},
|
|
4834
|
+
tags: [
|
|
4835
|
+
"masonry",
|
|
4836
|
+
"brittle"
|
|
4837
|
+
],
|
|
4838
|
+
compressive: 1e5
|
|
4638
4839
|
}
|
|
4639
4840
|
];
|
|
4640
4841
|
var material_hints_default = {
|
|
@@ -4808,6 +5009,32 @@ var GameFloorplanStructure = (() => {
|
|
|
4808
5009
|
return (1 + 4 * (0.3 - ductility) / 0.3) * Math.min(25, Math.max(1, (0.02 / Math.max(thickness, 1e-4)) ** 2));
|
|
4809
5010
|
};
|
|
4810
5011
|
var THIN_SHEET_DISHING = 5e-3;
|
|
5012
|
+
var SWEEP_BACK = 0.01;
|
|
5013
|
+
function sweepOrigins(box2, d, spacing) {
|
|
5014
|
+
const origins = [];
|
|
5015
|
+
const line = (from, to) => {
|
|
5016
|
+
const n = Math.max(1, Math.ceil((to - from) / spacing));
|
|
5017
|
+
return Array.from({ length: n + 1 }, (_, i) => from + (to - from) * i / n);
|
|
5018
|
+
};
|
|
5019
|
+
for (const axis of [0, 1, 2]) {
|
|
5020
|
+
if (Math.abs(d[axis]) < 1e-3) continue;
|
|
5021
|
+
const lead = d[axis] > 0 ? box2.max[axis] - SWEEP_BACK : box2.min[axis] + SWEEP_BACK;
|
|
5022
|
+
const u = (axis + 1) % 3;
|
|
5023
|
+
const v = (axis + 2) % 3;
|
|
5024
|
+
for (const a of line(box2.min[u], box2.max[u])) {
|
|
5025
|
+
for (const b of line(box2.min[v], box2.max[v])) {
|
|
5026
|
+
const point = [0, 0, 0];
|
|
5027
|
+
point[axis] = lead;
|
|
5028
|
+
point[u] = a;
|
|
5029
|
+
point[v] = b;
|
|
5030
|
+
origins.push(point);
|
|
5031
|
+
}
|
|
5032
|
+
}
|
|
5033
|
+
}
|
|
5034
|
+
return origins;
|
|
5035
|
+
}
|
|
5036
|
+
var THIN_SHEET_CRUSH = 5e-4;
|
|
5037
|
+
var THIN_SHEET_CONTACT = 0.025;
|
|
4811
5038
|
var DMG_PER_J = 0.02;
|
|
4812
5039
|
var BLAST_COUPLING = 0.1;
|
|
4813
5040
|
var SHELTER_DEFAULTS = { k: 2800, brokenTransmission: 0.5, minPath: 5e-3 };
|
|
@@ -4824,11 +5051,14 @@ var GameFloorplanStructure = (() => {
|
|
|
4824
5051
|
var SEVER_BAND = 0.1;
|
|
4825
5052
|
var SEVER_ASPECT = 3;
|
|
4826
5053
|
var SEVER_BALLISTIC = 2;
|
|
5054
|
+
var TEAR_JOULES = 150;
|
|
5055
|
+
var tears = 0;
|
|
4827
5056
|
var SUPPORT_TOLERANCE = 0.05;
|
|
4828
5057
|
var UNIT_FRAGMENT_FACTOR = 4;
|
|
4829
5058
|
var BREACH_GRID_CAP = 4096;
|
|
4830
5059
|
var CHIP_ENERGY = 200;
|
|
4831
5060
|
var CHIP_SPLASH = 0.5;
|
|
5061
|
+
var BAR_BOW = 0.08;
|
|
4832
5062
|
var CUT_SLICE = 1;
|
|
4833
5063
|
var cutFactorOf = (shape) => clamp22(Math.max(...shapeDims(shape)) / CUT_SLICE, 1, 50);
|
|
4834
5064
|
var clamp22 = (v, a, b) => Math.max(a, Math.min(b, v));
|
|
@@ -4838,8 +5068,24 @@ var GameFloorplanStructure = (() => {
|
|
|
4838
5068
|
return v === void 0 ? void 0 : v * (mat.penetrationScale ?? 1);
|
|
4839
5069
|
};
|
|
4840
5070
|
var capacityScale = (p) => {
|
|
4841
|
-
|
|
4842
|
-
|
|
5071
|
+
const residual = p.spec.reinforcement?.residualCapacity ?? RESIDUAL_CAPACITY;
|
|
5072
|
+
if (p.st.stripped) return residual;
|
|
5073
|
+
const kept = Math.min(p.rt.removed ? 1 - p.rt.removed / p.mass0 : 1, 1 - sectionLoss(p));
|
|
5074
|
+
return Math.max(p.spec.reinforcement ? residual : 0.05, kept);
|
|
5075
|
+
};
|
|
5076
|
+
var sectionLoss = (p) => {
|
|
5077
|
+
const cells = p.st.chipped;
|
|
5078
|
+
if (!cells?.length) return 0;
|
|
5079
|
+
const [u, v] = planeAxes(p.thin);
|
|
5080
|
+
const along = p.dims[u] >= p.dims[v] ? u : v;
|
|
5081
|
+
const across = along === u ? v : u;
|
|
5082
|
+
let worst = 0;
|
|
5083
|
+
for (const c of cells) {
|
|
5084
|
+
let gone = 0;
|
|
5085
|
+
for (const d of cells) if (Math.abs(d.center[along] - c.center[along]) < d.size[along] / 2 + 1e-6) gone += d.size[across];
|
|
5086
|
+
worst = Math.max(worst, gone / Math.max(p.dims[across], 1e-6));
|
|
5087
|
+
}
|
|
5088
|
+
return Math.min(1, worst);
|
|
4843
5089
|
};
|
|
4844
5090
|
var isLost = (p) => p.st.status === "broken" || p.st.status === "melted" || p.st.status === "ashes";
|
|
4845
5091
|
var clone = (v) => structuredClone(v);
|
|
@@ -6020,6 +6266,12 @@ var GameFloorplanStructure = (() => {
|
|
|
6020
6266
|
debris(o, p, layer.mat.hitDebris, wp, normal, 5, 2, src);
|
|
6021
6267
|
setStage(o, p, 1, {}, src);
|
|
6022
6268
|
};
|
|
6269
|
+
const crater = (o, p, wp, normal, radius, src) => {
|
|
6270
|
+
markDamaged(p);
|
|
6271
|
+
emit({ ...base(o, src), type: "spall", part: p.spec.id, layer: -1, point: wp, area: Math.PI * radius * radius });
|
|
6272
|
+
debris(o, p, p.mat.breakDebris, wp, normal, 6, 1.5, src);
|
|
6273
|
+
setStage(o, p, 1, {}, src);
|
|
6274
|
+
};
|
|
6023
6275
|
const insideOpening = (o, p, objectPoint) => {
|
|
6024
6276
|
const op = p.st.opening;
|
|
6025
6277
|
if (!op) return false;
|
|
@@ -6096,9 +6348,13 @@ var GameFloorplanStructure = (() => {
|
|
|
6096
6348
|
const lp = toLocal(p.pos, p.q, objectPoint);
|
|
6097
6349
|
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);
|
|
6098
6350
|
};
|
|
6099
|
-
const chipUnits = (o, p, wp,
|
|
6351
|
+
const chipUnits = (o, p, kind, wp, hitEnergy, dir, radius, src) => {
|
|
6100
6352
|
var _a, _b;
|
|
6101
|
-
if (!p.spec.units ||
|
|
6353
|
+
if (!p.spec.units || !p.staged || chipEnergy <= 0 || p.st.stripped || isLost(p) || (p.st.stage ?? 0) >= 2) return;
|
|
6354
|
+
const rule = p.mat.hits?.[kind];
|
|
6355
|
+
const perKg = rule?.unitJoules ?? chipEnergy;
|
|
6356
|
+
const energy = hitEnergy - (rule?.floor ?? 0);
|
|
6357
|
+
if (perKg <= 0 || energy <= 0) return;
|
|
6102
6358
|
const [u, v] = planeAxes(p.thin);
|
|
6103
6359
|
const lp = toLocal(p.pos, p.q, objLocal(o, wp));
|
|
6104
6360
|
const grid = gridOf(p);
|
|
@@ -6112,7 +6368,7 @@ var GameFloorplanStructure = (() => {
|
|
|
6112
6368
|
const share = gap === 0 ? 1 : CHIP_SPLASH * (1 - gap / radius);
|
|
6113
6369
|
const total = (worn[i] ?? 0) + energy * share;
|
|
6114
6370
|
const mass = p.mat.density * cell.size[0] * cell.size[1] * cell.size[2];
|
|
6115
|
-
if (total <
|
|
6371
|
+
if (total < perKg * mass) {
|
|
6116
6372
|
worn[i] = total;
|
|
6117
6373
|
continue;
|
|
6118
6374
|
}
|
|
@@ -6137,7 +6393,32 @@ var GameFloorplanStructure = (() => {
|
|
|
6137
6393
|
emit({ ...base(o, src), type: "chip", part: p.spec.id, center, size: [cell.size[0], cell.size[1], cell.size[2]], rotation: q, fragments });
|
|
6138
6394
|
debris(o, p, p.mat.breakDebris, center, vec.scale(dir ?? [0, 1, 0], -1), 6, 2, src);
|
|
6139
6395
|
}
|
|
6396
|
+
if (p.spec.reinforcement) exposeRebar(o, p, src);
|
|
6140
6397
|
for (const cell of out) addBreach(o, p, toWorld(c, q, cell.center), cell.size[u] * cell.size[v], energy, dir, src);
|
|
6398
|
+
if (p.structural && !isLost(p)) {
|
|
6399
|
+
solveStructure(o);
|
|
6400
|
+
collapseCheck(o, src);
|
|
6401
|
+
}
|
|
6402
|
+
};
|
|
6403
|
+
const exposeRebar = (o, p, src) => {
|
|
6404
|
+
const r = p.spec.reinforcement;
|
|
6405
|
+
if (!r) return;
|
|
6406
|
+
const [u, v] = planeAxes(p.thin);
|
|
6407
|
+
const all = rebarBars(p.dims, p.thin, r.spacing);
|
|
6408
|
+
let bars;
|
|
6409
|
+
if (p.st.stripped) bars = all;
|
|
6410
|
+
else {
|
|
6411
|
+
bars = [];
|
|
6412
|
+
for (const cell of p.st.chipped ?? []) bars.push(...clipBarsToBox(all, u, v, cell.center, cell.size));
|
|
6413
|
+
const op = p.st.opening;
|
|
6414
|
+
if (op) {
|
|
6415
|
+
const lc = toLocal(p.pos, p.q, op.center);
|
|
6416
|
+
bars.push(...clipBarsToDisc(all, u, v, [lc[u], lc[v]], op.radius + 0.05));
|
|
6417
|
+
}
|
|
6418
|
+
}
|
|
6419
|
+
const bow = clamp22(((p.st.stress ?? 0) - 1) / 0.5, 0, 1);
|
|
6420
|
+
if (bow > 0) bars = bars.flatMap((bar2, i) => bendBar(bar2, p.thin, bow * BAR_BOW, i));
|
|
6421
|
+
emit({ ...base(o, src), type: "expose", part: p.spec.id, bars: worldBars(o, p, bars) });
|
|
6141
6422
|
};
|
|
6142
6423
|
const openBreach = (o, p, center, total, energy, dir, src) => {
|
|
6143
6424
|
const [u, v] = planeAxes(p.thin);
|
|
@@ -6165,10 +6446,7 @@ var GameFloorplanStructure = (() => {
|
|
|
6165
6446
|
setStage(o, p, 2, { opening: { center: worldCenter, radius }, fragments }, src);
|
|
6166
6447
|
debris(o, p, p.mat.breakDebris, worldCenter, vec.scale(dir ?? [0, 1, 0], -1), 14, 3, src);
|
|
6167
6448
|
const reinforcement = p.spec.reinforcement;
|
|
6168
|
-
if (reinforcement)
|
|
6169
|
-
const bars = worldBars(o, p, clipBarsToDisc(rebarBars(p.dims, p.thin, reinforcement.spacing), u, v, [lc[u], lc[v]], radius + 0.05));
|
|
6170
|
-
if (bars.length > 0) emit({ ...base(o, src), type: "expose", part: p.spec.id, bars });
|
|
6171
|
-
}
|
|
6449
|
+
if (reinforcement) exposeRebar(o, p, src);
|
|
6172
6450
|
if (p.structural) solveStructure(o);
|
|
6173
6451
|
};
|
|
6174
6452
|
const stripPart = (o, p, reinforcement, src) => {
|
|
@@ -6180,8 +6458,8 @@ var GameFloorplanStructure = (() => {
|
|
|
6180
6458
|
p.st.burning = false;
|
|
6181
6459
|
p.rt.jet = false;
|
|
6182
6460
|
markDamaged(p);
|
|
6183
|
-
emit({ ...base(o, src), type: "expose", part: p.spec.id, bars: worldBars(o, p, bars) });
|
|
6184
6461
|
solveStructure(o);
|
|
6462
|
+
exposeRebar(o, p, src);
|
|
6185
6463
|
collapseCheck(o, src);
|
|
6186
6464
|
};
|
|
6187
6465
|
const unitFragmentPlan = (p, cap) => {
|
|
@@ -6235,7 +6513,7 @@ var GameFloorplanStructure = (() => {
|
|
|
6235
6513
|
const grain = p.spec.grain ? AXIS[p.spec.grain] : void 0;
|
|
6236
6514
|
const hitLocal = toLocal(c, q, hitW);
|
|
6237
6515
|
const unitPlan = p.spec.units ? unitFragmentPlan(p, maxFragments * UNIT_FRAGMENT_FACTOR) : [];
|
|
6238
|
-
const axis = style === "splinter" ? severAxis(p) : -1;
|
|
6516
|
+
const axis = style === "splinter" || style === "snap" ? severAxis(p) : -1;
|
|
6239
6517
|
const cutAt2 = axis < 0 ? void 0 : p.rt.cutAt ?? (origin ? hitLocal[axis] : void 0);
|
|
6240
6518
|
const plan = unitPlan.length > 0 ? unitPlan : planFragments({
|
|
6241
6519
|
style,
|
|
@@ -6307,7 +6585,7 @@ var GameFloorplanStructure = (() => {
|
|
|
6307
6585
|
};
|
|
6308
6586
|
const CHAIN_TRIGGER_OF = { ballistic: "shot", explosive: "explosion" };
|
|
6309
6587
|
const severAxis = (p) => {
|
|
6310
|
-
if (p.mat.fracture !== "splinter" || p.spec.shape.kind !== "box") return -1;
|
|
6588
|
+
if (p.mat.fracture !== "splinter" && p.mat.fracture !== "snap" || p.spec.shape.kind !== "box") return -1;
|
|
6311
6589
|
const d = p.dims;
|
|
6312
6590
|
const order = [0, 1, 2].sort((a, b) => d[b] - d[a]);
|
|
6313
6591
|
return d[order[0]] >= SEVER_ASPECT * d[order[1]] && d[order[0]] >= 3 * SEVER_BAND ? order[0] : -1;
|
|
@@ -6368,6 +6646,49 @@ var GameFloorplanStructure = (() => {
|
|
|
6368
6646
|
}
|
|
6369
6647
|
}
|
|
6370
6648
|
};
|
|
6649
|
+
const tearOf = (mat, kind) => {
|
|
6650
|
+
const h = mat.hits?.[kind];
|
|
6651
|
+
const tear = h?.tear ?? (kind === "ballistic" && mat.penetrationClass === "wood" ? "splinters" : "none");
|
|
6652
|
+
return { tear, joules: h?.tearJoules ?? TEAR_JOULES };
|
|
6653
|
+
};
|
|
6654
|
+
const tearAt = (o, p, kind, entry2, exit, d, E, scale, src) => {
|
|
6655
|
+
const { tear, joules } = tearOf(p.mat, kind);
|
|
6656
|
+
if (tear === "none") return;
|
|
6657
|
+
const shot = kind === "ballistic";
|
|
6658
|
+
const n = shot ? exit ? clamp22(Math.round(E / joules), 1, 7) : 1 : clamp22(Math.floor(E / joules), 0, 5);
|
|
6659
|
+
if (n === 0) return;
|
|
6660
|
+
const fibre = tear === "lumps";
|
|
6661
|
+
const { q } = partXf(o, p);
|
|
6662
|
+
const along = (p.spec.grain ? AXIS[p.spec.grain] : void 0) ?? [0, 1, 2].sort((a, b) => p.dims[b] - p.dims[a])[0];
|
|
6663
|
+
const fragments = [];
|
|
6664
|
+
for (let i = 0; i < n; i++) {
|
|
6665
|
+
const back = !exit || i % 3 === 2;
|
|
6666
|
+
const len = scale * (fibre ? 1.2 + 1.2 * rnd() : 3 + 4 * rnd()), w = scale * (0.8 + 0.8 * rnd()), t = scale * (fibre ? 0.7 + 0.6 * rnd() : 0.4 + 0.4 * rnd());
|
|
6667
|
+
const size = [w, w, w];
|
|
6668
|
+
size[along] = len;
|
|
6669
|
+
size[(along + 1) % 3] = w;
|
|
6670
|
+
size[(along + 2) % 3] = t;
|
|
6671
|
+
const spread3 = [(rnd() - 0.5) * 0.8, (rnd() - 0.2) * 0.8, (rnd() - 0.5) * 0.8];
|
|
6672
|
+
const speed = shot ? back ? 1.5 + 2 * rnd() : 2 + 4 * rnd() : 0.8 + 1.2 * rnd();
|
|
6673
|
+
const v = vec.scale(vec.normalize(vec.add(back ? vec.scale(d, -1) : d, spread3)), speed);
|
|
6674
|
+
const mass = size[0] * size[1] * size[2] * p.mat.density;
|
|
6675
|
+
fragments.push({
|
|
6676
|
+
id: `${p.spec.id}#t${tears++}-${i}`,
|
|
6677
|
+
part: p.spec.id,
|
|
6678
|
+
material: p.spec.material,
|
|
6679
|
+
shape: fibre ? "chunk" : "splinter",
|
|
6680
|
+
center: back || !exit ? vec.madd(entry2, d, -0.01) : vec.madd(exit, d, 0.01),
|
|
6681
|
+
size,
|
|
6682
|
+
rotation: q,
|
|
6683
|
+
velocity: v,
|
|
6684
|
+
inner: true,
|
|
6685
|
+
angularVelocity: [(rnd() - 0.5) * 30, (rnd() - 0.5) * 30, (rnd() - 0.5) * 30],
|
|
6686
|
+
mass
|
|
6687
|
+
});
|
|
6688
|
+
}
|
|
6689
|
+
const patch = [scale * 4, scale * 4, scale * 4];
|
|
6690
|
+
emit({ ...base(o, src), type: "chip", part: p.spec.id, center: exit ?? entry2, size: patch, rotation: q, fragments });
|
|
6691
|
+
};
|
|
6371
6692
|
const ballistic = (o, p, entry2, n, d, E, caliber, pathLen, src, round3 = {}) => {
|
|
6372
6693
|
const mat = p.mat;
|
|
6373
6694
|
const piercing = round3.piercing ?? 1;
|
|
@@ -6396,6 +6717,7 @@ var GameFloorplanStructure = (() => {
|
|
|
6396
6717
|
return { penetrated: false, exitEnergy: 0, damage: dmg2 };
|
|
6397
6718
|
}
|
|
6398
6719
|
if (p.layers.length > 0) spallOuter(o, p, entry2, face, n, Math.max(0.03, caliber / 1e3 * 4), src);
|
|
6720
|
+
else if (mat.hits?.ballistic?.crater) crater(o, p, entry2, n, clamp22(0.02 + Math.sqrt(E) * 15e-4, 0.02, 0.15), src);
|
|
6399
6721
|
const brittle = mat.ductility < 0.3;
|
|
6400
6722
|
const ratio = Ep / Math.max(thr, 1e-6);
|
|
6401
6723
|
const crackLen = clamp22(0.03 + ratio * 0.2, 0.03, 0.8);
|
|
@@ -6429,8 +6751,10 @@ var GameFloorplanStructure = (() => {
|
|
|
6429
6751
|
} else addHole(o, p, entry2, n, caliber / 1e3, false, void 0, src);
|
|
6430
6752
|
debris(o, p, mat.hitDebris, entry2, n, clamp22(Math.round(E / 60) + 2, 2, 14), clamp22(Math.sqrt(E) / 6, 1, 8), src);
|
|
6431
6753
|
wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true);
|
|
6432
|
-
const
|
|
6433
|
-
|
|
6754
|
+
const absorbed = penetrated && mat.ductility >= 0.5 && mat.fracture !== "tear" ? Math.min(E, thr) : E;
|
|
6755
|
+
const dmg = applyDamage(o, p, absorbed * DMG_PER_J * scale, "ballistic", entry2, d, absorbed * 0.1, 12, src);
|
|
6756
|
+
if (!isLost(p)) tearAt(o, p, "ballistic", entry2, penetrated ? exitPoint : void 0, d, E, caliber / 1e3, src);
|
|
6757
|
+
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);
|
|
6434
6758
|
return { penetrated, exitEnergy: penetrated ? penMm !== void 0 ? E * (1 - thr / Ep) : E - thr / (hard ? piercing : 1) : 0, exitPoint, damage: dmg };
|
|
6435
6759
|
};
|
|
6436
6760
|
const melee = (o, p, kind, E, point, n, d, contactR, src) => {
|
|
@@ -6438,14 +6762,20 @@ var GameFloorplanStructure = (() => {
|
|
|
6438
6762
|
const thrMm = mat.penetration * p.thickness * 1e3;
|
|
6439
6763
|
const fragile = kind === "blunt" ? fragility(mat.ductility, p.thickness) : 1;
|
|
6440
6764
|
const Ec = E * fragile;
|
|
6765
|
+
const sheet = mat.ductility >= 0.5 && p.thickness <= THIN_SHEET_CRUSH;
|
|
6766
|
+
const fold = sheet ? Math.min(4, Math.sqrt(1e-3 / p.thickness)) : 1;
|
|
6767
|
+
const patch = sheet ? Math.min(contactR, THIN_SHEET_CONTACT) : contactR;
|
|
6441
6768
|
if (E > 0) {
|
|
6442
6769
|
if (kind === "blunt") {
|
|
6443
|
-
if (mat.ductility >= 0.5) addDent(o, p, point, n, Math.max(
|
|
6770
|
+
if (mat.ductility >= 0.5) addDent(o, p, point, n, Math.max(patch, 0.015), clamp22(E * 1e-4 * fold, 1e-3, sheet ? Math.min(0.06, Math.min(...p.dims) * 0.45) : 0.06), src);
|
|
6444
6771
|
else if (mat.ductility < 0.3) {
|
|
6445
6772
|
if (Ec >= 5) addCrack(o, p, point, n, clamp22(0.04 + Math.min(Ec, E * 6) * 8e-4, 0.04, 0.6), src);
|
|
6446
6773
|
} else if (E >= thrMm * 0.2) addDent(o, p, point, n, Math.max(contactR, 0.015), clamp22(E * 6e-5, 1e-3, 0.04), src);
|
|
6447
6774
|
} else if (mat.fracture === "tear") {
|
|
6448
6775
|
addHole(o, p, point, n, clamp22(0.02 + E * 5e-4, 0.02, 0.3), true, void 0, src);
|
|
6776
|
+
} else if (mat.ductility >= 0.3 && E >= thrMm) {
|
|
6777
|
+
addHole(o, p, point, n, clamp22(contactR, 0.01, 0.08), true, void 0, src);
|
|
6778
|
+
if (sheet) addDent(o, p, point, n, Math.max(patch * 0.6, 0.01), clamp22(E * 4e-5 * fold, 5e-4, 0.02), src);
|
|
6449
6779
|
} else if (mat.ductility >= 0.5) {
|
|
6450
6780
|
addDent(o, p, point, n, Math.max(contactR, 0.01), clamp22(E * 4e-5, 5e-4, 0.02), src);
|
|
6451
6781
|
}
|
|
@@ -6458,7 +6788,8 @@ var GameFloorplanStructure = (() => {
|
|
|
6458
6788
|
const scale = mat.damageScale?.[kind] ?? 1;
|
|
6459
6789
|
const done = applyDamage(o, p, Ec * DMG_PER_J * scale * (kind === "slash" ? p.cutFactor : 1), kind, point, d, E * 0.1, 12, src);
|
|
6460
6790
|
addBreach(o, p, point, breachAreaOf(p, done, false), E, d, src);
|
|
6461
|
-
if (kind === "blunt") chipUnits(o, p, point, E, d, Math.max(contactR, 0.03), src);
|
|
6791
|
+
if (kind === "blunt") chipUnits(o, p, "blunt", point, E, d, Math.max(contactR, 0.03), src);
|
|
6792
|
+
if (E > 0 && !isLost(p)) tearAt(o, p, kind, point, void 0, d, E, clamp22(contactR * 0.2, 6e-3, 0.02), src);
|
|
6462
6793
|
return done;
|
|
6463
6794
|
};
|
|
6464
6795
|
const blastPart = (o, p, point, energy, radius, src, res, reachAt) => {
|
|
@@ -7037,6 +7368,7 @@ var GameFloorplanStructure = (() => {
|
|
|
7037
7368
|
if (p.rt.stressT <= 0) {
|
|
7038
7369
|
p.rt.stressT = 0.5;
|
|
7039
7370
|
emit({ ...base(o), type: "stress", part: p.spec.id, stress, load: p.st.load ?? 0 });
|
|
7371
|
+
if (p.spec.reinforcement && (p.st.stripped || p.st.chipped?.length || p.st.opening)) exposeRebar(o, p);
|
|
7040
7372
|
}
|
|
7041
7373
|
applyDamage(o, p, overloadRate(stress) * p.st.maxHp * dt, "blunt", null, null, 5, 3);
|
|
7042
7374
|
} else if (stress > 0.8 && p.mat.ductility < 0.3 && p.rt.stressT <= 0 && p.st.cracks.length < 6) {
|
|
@@ -7253,6 +7585,18 @@ var GameFloorplanStructure = (() => {
|
|
|
7253
7585
|
const r = raycastInternal(origin, direction, maxDistance);
|
|
7254
7586
|
return r ? { object: r.object, part: r.part, point: r.point, normal: r.normal, distance: r.distance } : null;
|
|
7255
7587
|
},
|
|
7588
|
+
sweepBox(box2, direction, distance2, options2 = {}) {
|
|
7589
|
+
const d = vec.normalize(direction);
|
|
7590
|
+
const ignored = options2.ignore === void 0 ? void 0 : objects.get(options2.ignore);
|
|
7591
|
+
const ignore = ignored ? new Set(ignored.parts.map((p) => `${ignored.id}\0${p.spec.id}`)) : void 0;
|
|
7592
|
+
let best = null;
|
|
7593
|
+
for (const origin of sweepOrigins(box2, d, options2.spacing ?? 0.2)) {
|
|
7594
|
+
const r = raycastInternal(origin, d, distance2 + SWEEP_BACK, ignore);
|
|
7595
|
+
if (!r || best && r.distance >= best.distance) continue;
|
|
7596
|
+
best = { object: r.object, part: r.part, point: r.point, normal: r.normal, distance: Math.max(0, r.distance - SWEEP_BACK) };
|
|
7597
|
+
}
|
|
7598
|
+
return best;
|
|
7599
|
+
},
|
|
7256
7600
|
shoot(origin, direction, energy, caliber, source, round3) {
|
|
7257
7601
|
const extras = typeof round3 === "number" ? { piercing: round3 } : round3 ?? {};
|
|
7258
7602
|
return withCollapses(run(() => {
|
|
@@ -8677,7 +9021,24 @@ var GameFloorplanStructure = (() => {
|
|
|
8677
9021
|
}
|
|
8678
9022
|
return spec;
|
|
8679
9023
|
};
|
|
8680
|
-
var
|
|
9024
|
+
var MEMBER_CAGE = { spacing: 0.1, diameter: 8e-3, unit: 0.1 };
|
|
9025
|
+
var CAGED_ROLES = /* @__PURE__ */ new Set(["beam", "column"]);
|
|
9026
|
+
var caged = (spec, part, rebar) => {
|
|
9027
|
+
if (!rebar || part.material !== "concrete" || !CAGED_ROLES.has(part.role) || spec.reinforcement) return spec;
|
|
9028
|
+
const size = spec.shape.kind === "box" ? spec.shape.size : null;
|
|
9029
|
+
if (!size) return spec;
|
|
9030
|
+
const thin = Math.min(...size);
|
|
9031
|
+
return {
|
|
9032
|
+
...spec,
|
|
9033
|
+
reinforcement: { material: rebar, spacing: MEMBER_CAGE.spacing, diameter: MEMBER_CAGE.diameter },
|
|
9034
|
+
units: { size: [MEMBER_CAGE.unit, MEMBER_CAGE.unit, thin], bond: "stack", mortar: "concrete" }
|
|
9035
|
+
};
|
|
9036
|
+
};
|
|
9037
|
+
var partSpecOf = (part, capacity, detailed, rebar) => {
|
|
9038
|
+
if (detailed && part.assembly) return assemblySpec(part, capacity);
|
|
9039
|
+
const spec = boxSpec(part, capacity);
|
|
9040
|
+
return detailed ? caged(spec, part, rebar) : spec;
|
|
9041
|
+
};
|
|
8681
9042
|
function toDestructibleSpec(structure, options = {}) {
|
|
8682
9043
|
const { safety = 0.65, redundancy = 0.97, safetyOthers = 0.45 } = options;
|
|
8683
9044
|
const kept = structure.parts.filter((part) => !options.filter || options.filter(part));
|
|
@@ -8694,7 +9055,7 @@ var GameFloorplanStructure = (() => {
|
|
|
8694
9055
|
const sizing = { safety, redundancy, safetyOthers };
|
|
8695
9056
|
const sized = { ...panels, capacities: options.sized === false ? /* @__PURE__ */ new Map() : sizeCapacities(panels.parts, panels.supports, sizing) };
|
|
8696
9057
|
const { parts, supports, capacities } = detail === "units" ? applyUnits(sized, structure) : sized;
|
|
8697
|
-
const specs = parts.map((part) => partSpecOf(part, capacities.get(part.id), detail !== "coarse"));
|
|
9058
|
+
const specs = parts.map((part) => partSpecOf(part, capacities.get(part.id), detail !== "coarse", structure.construction.frame.rebar));
|
|
8698
9059
|
const margin = options.terrainMargin ?? TERRAIN_MARGIN;
|
|
8699
9060
|
const x0 = Math.min(...parts.map((part) => part.aabb[0]));
|
|
8700
9061
|
const z0 = Math.min(...parts.map((part) => part.aabb[1]));
|