@adatechnology/game-destruction 0.18.2 → 0.20.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.global.js +161 -14
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +142 -15
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -2955,7 +2955,7 @@ var fragility = (ductility, thickness) => {
|
|
|
2955
2955
|
};
|
|
2956
2956
|
|
|
2957
2957
|
// src/world.ts
|
|
2958
|
-
import { ignitionChance, resolveIgnitionRules, sparkTargetFactor } from "@adatechnology/game-contracts";
|
|
2958
|
+
import { bodyImpulse, DEFAULT_BLAST_IMPULSE, ignitionChance, resolveIgnitionRules, sideOnOverpressure, sparkTargetFactor } from "@adatechnology/game-contracts";
|
|
2959
2959
|
var THIN_SHEET_DISHING = 5e-3;
|
|
2960
2960
|
var SWEEP_BACK = 0.01;
|
|
2961
2961
|
function sweepOrigins(box, d, spacing) {
|
|
@@ -2997,9 +2997,15 @@ var BREACH_BLAST_FACTOR = 6;
|
|
|
2997
2997
|
var BREACH_AREA = 0.25;
|
|
2998
2998
|
var BREACH_BLAST_REACH = 0.12;
|
|
2999
2999
|
var MEMBER_CUT_REACH = 0.5;
|
|
3000
|
+
var FAR_MEMBER_HP_FLOOR = 0.25;
|
|
3000
3001
|
var BLAST_REFERENCE_RESISTANCE = 200 * 1900 * 0.13;
|
|
3001
3002
|
var BLAST_EDGE_RAGGED = 0.3;
|
|
3002
3003
|
var BLAST_EDGE_LOOSE = 1.35;
|
|
3004
|
+
var PANEL_PRESSURE = 7e4;
|
|
3005
|
+
var PANEL_IMPULSE = 150;
|
|
3006
|
+
var PANEL_PI = 6e6;
|
|
3007
|
+
var PANEL_POINTS = [[0, 0], [-0.3, 0], [0.3, 0], [0, -0.3], [0, 0.3]];
|
|
3008
|
+
var PANEL_POINTS_LOADED = 4;
|
|
3003
3009
|
var BLAST_EDGE_WEAR = 0.6;
|
|
3004
3010
|
var RESIDUAL_CAPACITY = 0.15;
|
|
3005
3011
|
var SEVER_BAND = 0.1;
|
|
@@ -3024,23 +3030,42 @@ var penetrationOf = (mat, table) => {
|
|
|
3024
3030
|
const v = table[mat.penetrationClass ?? mat.id] ?? table[mat.id];
|
|
3025
3031
|
return v === void 0 ? void 0 : v * (mat.penetrationScale ?? 1);
|
|
3026
3032
|
};
|
|
3027
|
-
var
|
|
3033
|
+
var BURIED_BLAST_REACH = 0.5;
|
|
3034
|
+
var GIVE_AT_CUT_HP = 0.5;
|
|
3035
|
+
var capacityScale = (p, borne, through) => {
|
|
3028
3036
|
const residual = p.spec.reinforcement?.residualCapacity ?? RESIDUAL_CAPACITY;
|
|
3029
3037
|
if (p.st.stripped) return residual;
|
|
3030
|
-
const kept = Math.min(p.rt.removed ? 1 - p.rt.removed / p.mass0 : 1,
|
|
3038
|
+
const kept = Math.min(p.rt.removed ? 1 - p.rt.removed / p.mass0 : 1, sectionKept(p, residual, borne, through));
|
|
3031
3039
|
return Math.max(p.spec.reinforcement ? residual : 0.05, kept);
|
|
3032
3040
|
};
|
|
3033
|
-
var
|
|
3041
|
+
var sectionKept = (p, residual, borne, through) => {
|
|
3042
|
+
let kept = 1;
|
|
3043
|
+
forEachSection(p, borne, (c, along, gone) => {
|
|
3044
|
+
const share = through?.(c.center, along) ?? 1;
|
|
3045
|
+
if (share <= 0) return;
|
|
3046
|
+
kept = Math.min(kept, Math.max(p.spec.reinforcement ? residual : 0, 1 - gone) / share);
|
|
3047
|
+
});
|
|
3048
|
+
return kept;
|
|
3049
|
+
};
|
|
3050
|
+
var sectionLoss = (p, borne) => {
|
|
3051
|
+
let worst = 0;
|
|
3052
|
+
forEachSection(p, borne, (_c, _along, gone) => {
|
|
3053
|
+
worst = Math.max(worst, gone);
|
|
3054
|
+
});
|
|
3055
|
+
return Math.min(1, worst);
|
|
3056
|
+
};
|
|
3057
|
+
var forEachSection = (p, borne, visit) => {
|
|
3034
3058
|
const cells = p.st.chipped;
|
|
3035
|
-
if (!cells?.length) return
|
|
3059
|
+
if (!cells?.length) return;
|
|
3036
3060
|
const [u, v] = planeAxes(p.thin);
|
|
3037
3061
|
const role = p.spec.structure?.role;
|
|
3038
3062
|
const up = rotateVec(p.q, [0, 0, 0].map((_, k) => k === v ? 1 : 0));
|
|
3039
3063
|
const upright = Math.abs(up[1]) > 0.7 ? v : Math.abs(rotateVec(p.q, [0, 0, 0].map((_, k) => k === u ? 1 : 0))[1]) > 0.7 ? u : -1;
|
|
3040
3064
|
const along = (role === "wall" || role === "partition" || role === "column") && upright >= 0 ? upright : p.dims[u] >= p.dims[v] ? u : v;
|
|
3041
3065
|
const across = along === u ? v : u;
|
|
3042
|
-
|
|
3066
|
+
const lying = along !== upright || upright < 0;
|
|
3043
3067
|
for (const c of cells) {
|
|
3068
|
+
if (lying && borne?.(c.center, along)) continue;
|
|
3044
3069
|
const spans = [];
|
|
3045
3070
|
for (const d of cells) if (Math.abs(d.center[along] - c.center[along]) < d.size[along] / 2 + 1e-6) spans.push([d.center[across] - d.size[across] / 2, d.center[across] + d.size[across] / 2]);
|
|
3046
3071
|
spans.sort((a, b) => a[0] - b[0]);
|
|
@@ -3050,9 +3075,8 @@ var sectionLoss = (p) => {
|
|
|
3050
3075
|
gone += b - Math.max(a, end);
|
|
3051
3076
|
end = b;
|
|
3052
3077
|
}
|
|
3053
|
-
|
|
3078
|
+
visit(c, along, Math.min(1, gone / Math.max(p.dims[across], 1e-6)));
|
|
3054
3079
|
}
|
|
3055
|
-
return Math.min(1, worst);
|
|
3056
3080
|
};
|
|
3057
3081
|
var isLost = (p) => p.st.status === "broken" || p.st.status === "melted" || p.st.status === "ashes";
|
|
3058
3082
|
var clone = (v) => structuredClone(v);
|
|
@@ -3363,6 +3387,26 @@ var createDestruction = (options = {}) => {
|
|
|
3363
3387
|
byTouching.set(support, { version: poseVersion, box });
|
|
3364
3388
|
return box;
|
|
3365
3389
|
};
|
|
3390
|
+
const throughOf = (p) => {
|
|
3391
|
+
const load = p.st.load ?? 0;
|
|
3392
|
+
if (load <= 0) return void 0;
|
|
3393
|
+
const above = Math.max(0, load - p.st.mass);
|
|
3394
|
+
const up = rotateVec(p.q, [0, 1, 0]);
|
|
3395
|
+
return (local, along) => {
|
|
3396
|
+
const axis = [0, 0, 0];
|
|
3397
|
+
axis[along] = 1;
|
|
3398
|
+
const sign = Math.sign(rotateVec(p.q, axis)[1]);
|
|
3399
|
+
if (Math.abs(up[1]) < 0.7 && Math.abs(rotateVec(p.q, axis)[1]) < 0.7) return 1;
|
|
3400
|
+
const half = p.dims[along] / 2;
|
|
3401
|
+
const share = clamp2((half - sign * local[along]) / Math.max(p.dims[along], 1e-6), 0, 1);
|
|
3402
|
+
return (above + p.st.mass * share) / load;
|
|
3403
|
+
};
|
|
3404
|
+
};
|
|
3405
|
+
const borneOn = (p, supports) => {
|
|
3406
|
+
if (supports.length === 0) return void 0;
|
|
3407
|
+
const boxes = supports.map((support) => contactBox(p, support));
|
|
3408
|
+
return (local, along) => boxes.some(([lo, hi]) => local[along] >= lo[along] - SUPPORT_TOLERANCE && local[along] <= hi[along] + SUPPORT_TOLERANCE);
|
|
3409
|
+
};
|
|
3366
3410
|
const measureContact = (p, support) => {
|
|
3367
3411
|
const A = aabbOf(p.spec.shape, p.pos, p.q), B = aabbOf(support.spec.shape, support.pos, support.q);
|
|
3368
3412
|
const lo = [0, 0, 0], hi = [0, 0, 0];
|
|
@@ -3570,7 +3614,7 @@ var createDestruction = (options = {}) => {
|
|
|
3570
3614
|
o.unsup[i] = o.anyAnchor && !isLost(p) && !p.orphan;
|
|
3571
3615
|
continue;
|
|
3572
3616
|
}
|
|
3573
|
-
p.st.stress = p.st.load * structureSafety / (p.cap * capacityScale(p));
|
|
3617
|
+
p.st.stress = p.st.load * structureSafety / (p.cap * capacityScale(p, borneOn(p, (lowerOf.get(i) ?? []).map((k) => parts[k])), throughOf(p)));
|
|
3574
3618
|
if (p.bend) {
|
|
3575
3619
|
p.bendLoad = p.st.mass + bending[i];
|
|
3576
3620
|
const bent = restFlexure(o, p, lowerOf.get(i) ?? []);
|
|
@@ -4555,7 +4599,7 @@ var createDestruction = (options = {}) => {
|
|
|
4555
4599
|
return BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3) * clamp2(Math.cbrt(BLAST_REFERENCE_RESISTANCE / resistance), 0.3, 2);
|
|
4556
4600
|
};
|
|
4557
4601
|
const blastUnits = (o, p, wp, energy, dist, src) => {
|
|
4558
|
-
var _a
|
|
4602
|
+
var _a;
|
|
4559
4603
|
if (!p.staged || p.st.stripped || isLost(p) || chipEnergy <= 0) return false;
|
|
4560
4604
|
const reach = blastReachOf(p, energy);
|
|
4561
4605
|
if (dist >= reach) return false;
|
|
@@ -4585,6 +4629,62 @@ var createDestruction = (options = {}) => {
|
|
|
4585
4629
|
}
|
|
4586
4630
|
}
|
|
4587
4631
|
if (out.length === 0) return false;
|
|
4632
|
+
return knockOutUnits(o, p, wp, energy, out, src);
|
|
4633
|
+
};
|
|
4634
|
+
const blastPanel = (o, p, point, energy, src) => {
|
|
4635
|
+
var _a;
|
|
4636
|
+
if (!p.staged || p.st.stripped || isLost(p) || !p.spec.units || p.spec.units.mortar === p.spec.material || p.spec.reinforcement) return false;
|
|
4637
|
+
const [u, v] = planeAxes(p.thin);
|
|
4638
|
+
const lp = toLocal(p.pos, p.q, objLocal(o, point));
|
|
4639
|
+
const half = p.dims[u] / 2;
|
|
4640
|
+
const posts = [];
|
|
4641
|
+
for (const m of o.parts) {
|
|
4642
|
+
if (m === p || !m.spec.reinforcement || isLost(m) || m.spec.shape.kind !== "box") continue;
|
|
4643
|
+
const mp = toLocal(p.pos, p.q, m.pos);
|
|
4644
|
+
if (Math.abs(mp[p.thin]) > p.dims[p.thin] + 0.15 || Math.abs(mp[u]) > half + 0.15 || m.dims[v] < p.dims[v] * 0.5) continue;
|
|
4645
|
+
posts.push(mp[u]);
|
|
4646
|
+
}
|
|
4647
|
+
let from = -half, to = half;
|
|
4648
|
+
for (const x of posts) {
|
|
4649
|
+
if (x <= lp[u] && x > from) from = x;
|
|
4650
|
+
if (x >= lp[u] && x < to) to = x;
|
|
4651
|
+
}
|
|
4652
|
+
if (to - from < 0.2) return false;
|
|
4653
|
+
const tnt = energy * DEFAULT_BLAST_IMPULSE.tntPerJoule;
|
|
4654
|
+
const centre = objLocal(o, point);
|
|
4655
|
+
const span = to - from, height = p.dims[v];
|
|
4656
|
+
let loaded = 0;
|
|
4657
|
+
for (const [fu, fv] of PANEL_POINTS) {
|
|
4658
|
+
const at = [0, 0, 0];
|
|
4659
|
+
at[u] = (from + to) / 2 + fu * span;
|
|
4660
|
+
at[v] = fv * height;
|
|
4661
|
+
at[p.thin] = Math.sign(lp[p.thin]) * p.dims[p.thin] / 2;
|
|
4662
|
+
const r = vec.distance(toWorld(p.pos, p.q, at), centre);
|
|
4663
|
+
const side = sideOnOverpressure(tnt, r);
|
|
4664
|
+
const reflected = 2 * side + 6 * side * side / (side + 7 * 101325);
|
|
4665
|
+
const impulse = bodyImpulse(tnt, r);
|
|
4666
|
+
if (reflected > PANEL_PRESSURE && impulse > PANEL_IMPULSE && (reflected - PANEL_PRESSURE) * (impulse - PANEL_IMPULSE) >= PANEL_PI) loaded++;
|
|
4667
|
+
}
|
|
4668
|
+
if (loaded < PANEL_POINTS_LOADED) return false;
|
|
4669
|
+
const grid = gridOf(p);
|
|
4670
|
+
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
4671
|
+
const out = [];
|
|
4672
|
+
for (let i = 0; i < grid.length; i++) {
|
|
4673
|
+
const cell = grid[i];
|
|
4674
|
+
if (worn[i] === -1) continue;
|
|
4675
|
+
if (cell.center[u] - cell.size[u] / 2 >= from - 1e-6 && cell.center[u] + cell.size[u] / 2 <= to + 1e-6) out.push(i);
|
|
4676
|
+
}
|
|
4677
|
+
if (out.length === 0) return false;
|
|
4678
|
+
for (const i of out) worn[i] = -1;
|
|
4679
|
+
return knockOutUnits(o, p, point, energy, out, src);
|
|
4680
|
+
};
|
|
4681
|
+
const knockOutUnits = (o, p, wp, energy, out, src) => {
|
|
4682
|
+
var _a, _b;
|
|
4683
|
+
const [u, v] = planeAxes(p.thin);
|
|
4684
|
+
const op = p.st.opening ? toLocal(p.pos, p.q, p.st.opening.center) : null;
|
|
4685
|
+
const grid = gridOf(p);
|
|
4686
|
+
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
4687
|
+
for (const i of out) worn[i] = -1;
|
|
4588
4688
|
const loose = unsupportedCells(grid, p.thin, p.dims, (i) => worn[i] !== -1 && !(op && p.st.opening && Math.hypot(grid[i].center[u] - op[u], grid[i].center[v] - op[v]) <= p.st.opening.radius));
|
|
4589
4689
|
for (const i of loose) worn[i] = -1;
|
|
4590
4690
|
const blown = out.map((i) => grid[i]), fallen = loose.map((i) => grid[i]);
|
|
@@ -4660,6 +4760,27 @@ var createDestruction = (options = {}) => {
|
|
|
4660
4760
|
debris(o, p, p.mat.breakDebris, center, [0, -1, 0], 6, 1, src);
|
|
4661
4761
|
return loose.length;
|
|
4662
4762
|
};
|
|
4763
|
+
const giveAtCut = (o, p, src) => {
|
|
4764
|
+
if (!p.spec.reinforcement || !p.spec.units || !p.st.chipped?.length || sectionLoss(p) <= 0) return false;
|
|
4765
|
+
const opened = [];
|
|
4766
|
+
for (const j of o.byPart.get(p.spec.id) ?? []) {
|
|
4767
|
+
if (j.st.open) continue;
|
|
4768
|
+
const onIt = j.bears === "a_on_b" && j.spec.b === p.spec.id || j.bears === "b_on_a" && j.spec.a === p.spec.id;
|
|
4769
|
+
if (!onIt) continue;
|
|
4770
|
+
j.st.open = true;
|
|
4771
|
+
j.st.openedBy = "break";
|
|
4772
|
+
opened.push(j);
|
|
4773
|
+
}
|
|
4774
|
+
if (opened.length === 0) return false;
|
|
4775
|
+
p.st.hp = Math.max(p.st.hp, p.st.maxHp * GIVE_AT_CUT_HP);
|
|
4776
|
+
markDamaged(p);
|
|
4777
|
+
solveStructure(o);
|
|
4778
|
+
recomputeGroups(o);
|
|
4779
|
+
detachEvents(o, opened, "break", src);
|
|
4780
|
+
exposeRebar(o, p, src);
|
|
4781
|
+
collapseCheck(o, src);
|
|
4782
|
+
return true;
|
|
4783
|
+
};
|
|
4663
4784
|
const stripPart = (o, p, reinforcement, src) => {
|
|
4664
4785
|
const bars = rebarBars(p.dims, p.thin, reinforcement.spacing);
|
|
4665
4786
|
p.st.stripped = true;
|
|
@@ -4717,6 +4838,7 @@ var createDestruction = (options = {}) => {
|
|
|
4717
4838
|
hingeDrop(o, p, src);
|
|
4718
4839
|
return;
|
|
4719
4840
|
}
|
|
4841
|
+
if (!force && giveAtCut(o, p, src)) return;
|
|
4720
4842
|
const ex = p.spec.explodes;
|
|
4721
4843
|
const style = force ?? (p.snap ? "snap" : p.mat.fracture === "none" ? "snap" : p.mat.fracture);
|
|
4722
4844
|
const { c, q } = partXf(o, p);
|
|
@@ -5045,12 +5167,15 @@ var createDestruction = (options = {}) => {
|
|
|
5045
5167
|
return reach;
|
|
5046
5168
|
}
|
|
5047
5169
|
if (Ein > 20 && p.layers.length > 0) spallOuter(o, p, wp, faceOf(o, p, wn), wn, clamp2(0.05 + Math.sqrt(Ein) * 2e-3, 0.05, 0.4), src);
|
|
5048
|
-
const
|
|
5170
|
+
const breachReach = BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3);
|
|
5171
|
+
const farMember = Boolean(p.spec.reinforcement && p.spec.units) && dist > MEMBER_CUT_REACH * breachReach;
|
|
5172
|
+
const dealt = farMember ? applyDamage(o, p, Math.min(amount, Math.max(0, p.st.hp - p.st.maxHp * FAR_MEMBER_HP_FLOOR)), "explosive", null, null, Ein * 0.3, 40, src) : applyDamage(o, p, amount, "explosive", point, null, Ein * 0.3, 40, src);
|
|
5049
5173
|
res.damage += dealt;
|
|
5050
5174
|
if (p.bend && flexure.enabled) bendByBlast(o, p, point, energy, radius, reach, src);
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5175
|
+
if (p.spec.units && p.spec.units.mortar !== p.spec.material) {
|
|
5176
|
+
blastPanel(o, p, point, energy, src);
|
|
5177
|
+
if (!isLost(p)) blastUnits(o, p, wp, energy, dist, src);
|
|
5178
|
+
} else if (farMember) blastUnits(o, p, wp, energy, dist, src);
|
|
5054
5179
|
else if (dist <= breachReach) addBreach(o, p, wp, breachAreaOf(p, dealt, true), Ein, null, src);
|
|
5055
5180
|
return reach;
|
|
5056
5181
|
};
|
|
@@ -5063,7 +5188,9 @@ var createDestruction = (options = {}) => {
|
|
|
5063
5188
|
const dx = local[0] - p.pos[0];
|
|
5064
5189
|
const dy = local[1] - p.pos[1];
|
|
5065
5190
|
const dz = local[2] - p.pos[2];
|
|
5066
|
-
if (dx * dx + dy * dy + dz * dz
|
|
5191
|
+
if (dx * dx + dy * dy + dz * dz >= reach * reach) continue;
|
|
5192
|
+
if (p.spec.anchored && p.spec.structure?.role === "foundation" && distToPart(o, p, point) > BURIED_BLAST_REACH) continue;
|
|
5193
|
+
near.push(p);
|
|
5067
5194
|
}
|
|
5068
5195
|
blastProbe.partsTested += o.parts.length;
|
|
5069
5196
|
blastProbe.partsNear += near.length;
|