@adatechnology/game-destruction 0.12.0 → 0.13.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 -0
- package/dist/index.global.js +143 -18
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +143 -18
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -2706,6 +2706,7 @@ var CONFINEMENT_DEFAULTS = { rays: 26, reach: 1.5, gain: 1.5, power: 2, max: 3 }
|
|
|
2706
2706
|
var FLAMMABLE_FLUIDS = ["gas", "fuel"];
|
|
2707
2707
|
var VENT_DIAMETER = 8e-3;
|
|
2708
2708
|
var FLAME_LIGHTS_LEAK_C = 470;
|
|
2709
|
+
var RESTING_HOLD_COS = Math.cos(Math.PI / 6);
|
|
2709
2710
|
var BREACH_RADIUS = 0.55;
|
|
2710
2711
|
var BREACH_BLAST_FACTOR = 6;
|
|
2711
2712
|
var BREACH_AREA = 0.25;
|
|
@@ -2721,6 +2722,7 @@ var UNIT_FRAGMENT_FACTOR = 4;
|
|
|
2721
2722
|
var BREACH_GRID_CAP = 4096;
|
|
2722
2723
|
var CHIP_ENERGY = 200;
|
|
2723
2724
|
var CHIP_SPLASH = 0.5;
|
|
2725
|
+
var CRATER_SPENT = 0.6;
|
|
2724
2726
|
var BAR_BOW = 0.08;
|
|
2725
2727
|
var BULLET_JOINT_SPAN = 0.3;
|
|
2726
2728
|
var CUT_SLICE = 1;
|
|
@@ -2741,12 +2743,22 @@ var sectionLoss = (p) => {
|
|
|
2741
2743
|
const cells = p.st.chipped;
|
|
2742
2744
|
if (!cells?.length) return 0;
|
|
2743
2745
|
const [u, v] = planeAxes(p.thin);
|
|
2744
|
-
const
|
|
2746
|
+
const role = p.spec.structure?.role;
|
|
2747
|
+
const up = rotateVec(p.q, [0, 0, 0].map((_, k) => k === v ? 1 : 0));
|
|
2748
|
+
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;
|
|
2749
|
+
const along = (role === "wall" || role === "partition" || role === "column") && upright >= 0 ? upright : p.dims[u] >= p.dims[v] ? u : v;
|
|
2745
2750
|
const across = along === u ? v : u;
|
|
2746
2751
|
let worst = 0;
|
|
2747
2752
|
for (const c of cells) {
|
|
2748
|
-
|
|
2749
|
-
for (const d of cells) if (Math.abs(d.center[along] - c.center[along]) < d.size[along] / 2 + 1e-6)
|
|
2753
|
+
const spans = [];
|
|
2754
|
+
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]);
|
|
2755
|
+
spans.sort((a, b) => a[0] - b[0]);
|
|
2756
|
+
let gone = 0, end = -Infinity;
|
|
2757
|
+
for (const [a, b] of spans) {
|
|
2758
|
+
if (b <= end) continue;
|
|
2759
|
+
gone += b - Math.max(a, end);
|
|
2760
|
+
end = b;
|
|
2761
|
+
}
|
|
2750
2762
|
worst = Math.max(worst, gone / Math.max(p.dims[across], 1e-6));
|
|
2751
2763
|
}
|
|
2752
2764
|
return Math.min(1, worst);
|
|
@@ -3042,7 +3054,18 @@ var createDestruction = (options = {}) => {
|
|
|
3042
3054
|
if (k < 0 || j.spec.kind !== "tie") return k;
|
|
3043
3055
|
return partXf(o, o.parts[k]).c[1] > partXf(o, o.parts[r]).c[1] + 1e-6 ? k : -1;
|
|
3044
3056
|
};
|
|
3057
|
+
let poseVersion = 0;
|
|
3058
|
+
const contactMemo = /* @__PURE__ */ new WeakMap();
|
|
3045
3059
|
const contactBox = (p, support) => {
|
|
3060
|
+
let byTouching = contactMemo.get(p);
|
|
3061
|
+
if (!byTouching) contactMemo.set(p, byTouching = /* @__PURE__ */ new Map());
|
|
3062
|
+
const known = byTouching.get(support);
|
|
3063
|
+
if (known && known.version === poseVersion) return known.box;
|
|
3064
|
+
const box = measureContact(p, support);
|
|
3065
|
+
byTouching.set(support, { version: poseVersion, box });
|
|
3066
|
+
return box;
|
|
3067
|
+
};
|
|
3068
|
+
const measureContact = (p, support) => {
|
|
3046
3069
|
const A = aabbOf(p.spec.shape, p.pos, p.q), B = aabbOf(support.spec.shape, support.pos, support.q);
|
|
3047
3070
|
const lo = [0, 0, 0], hi = [0, 0, 0];
|
|
3048
3071
|
for (let k = 0; k < 3; k++) {
|
|
@@ -3837,7 +3860,7 @@ var createDestruction = (options = {}) => {
|
|
|
3837
3860
|
p.st.holes.push(hole);
|
|
3838
3861
|
if (p.st.holes.length > maxHoles) p.st.holes.shift();
|
|
3839
3862
|
markDamaged(p);
|
|
3840
|
-
emit({ ...base(o, src), type: "hole", part: p.spec.id, hole, worldPoint: wp, ...exit ? { exitPoint: exit } : {} });
|
|
3863
|
+
emit({ ...base(o, src), type: "hole", part: p.spec.id, hole, worldPoint: wp, ...exit ? { exitPoint: exit } : {}, ...p.spec.powder ? { powder: { ...p.spec.powder } } : {} });
|
|
3841
3864
|
setStage(o, p, 1, {}, src);
|
|
3842
3865
|
return hole;
|
|
3843
3866
|
};
|
|
@@ -3854,6 +3877,22 @@ var createDestruction = (options = {}) => {
|
|
|
3854
3877
|
const detachEvents = (o, opened, by, src) => {
|
|
3855
3878
|
for (const j of opened) emit({ ...base(o, src), type: "detach", joint: j.spec.id, parts: [j.spec.a, j.spec.b], by, groups: o.st.groups.map((g) => [...g]) });
|
|
3856
3879
|
};
|
|
3880
|
+
const slideOffResting = (o, rotation) => {
|
|
3881
|
+
const upY = 1 - 2 * (rotation[0] * rotation[0] + rotation[2] * rotation[2]);
|
|
3882
|
+
if (upY >= RESTING_HOLD_COS) return;
|
|
3883
|
+
const opened = o.joints.filter((j) => j.spec.kind === "resting" && !j.st.open);
|
|
3884
|
+
if (opened.length === 0) return;
|
|
3885
|
+
run(() => {
|
|
3886
|
+
for (const j of opened) {
|
|
3887
|
+
j.st.open = true;
|
|
3888
|
+
j.st.openedBy = "break";
|
|
3889
|
+
}
|
|
3890
|
+
solveStructure(o);
|
|
3891
|
+
recomputeGroups(o);
|
|
3892
|
+
detachEvents(o, opened, "break");
|
|
3893
|
+
collapseCheck(o);
|
|
3894
|
+
});
|
|
3895
|
+
};
|
|
3857
3896
|
const checkDestroyed = (o, src) => {
|
|
3858
3897
|
if (!o.st.destroyed && o.parts.length > 0 && o.parts.every(isLost)) {
|
|
3859
3898
|
o.st.destroyed = true;
|
|
@@ -3954,7 +3993,7 @@ var createDestruction = (options = {}) => {
|
|
|
3954
3993
|
const localHolesOf = (p) => p.st.holes.map((h) => ({ point: toLocal(p.pos, p.q, h.point), normal: rotateVec(quat.conjugate(p.q), h.normal), diameter: h.diameter }));
|
|
3955
3994
|
const unitsOf = (p) => p.spec.units ?? { size: [p.mat.fragmentSize?.[1] ?? 0.2, p.mat.fragmentSize?.[1] ?? 0.2, p.thickness], bond: "stack" };
|
|
3956
3995
|
const FRAGMENT_SHAPE = { shatter: "shard", splinter: "splinter", tear: "scrap" };
|
|
3957
|
-
const cellFragments = (o, p, cells, hitW, dir, speed, mass, tag) => {
|
|
3996
|
+
const cellFragments = (o, p, cells, hitW, dir, speed, mass, tag, inner = false) => {
|
|
3958
3997
|
const { c, q } = partXf(o, p);
|
|
3959
3998
|
const holes = p.st.holes.length > 0 ? localHolesOf(p) : [];
|
|
3960
3999
|
const [u, v] = planeAxes(p.thin);
|
|
@@ -3978,7 +4017,8 @@ var createDestruction = (options = {}) => {
|
|
|
3978
4017
|
velocity: [dv[0] * k, dv[1] * k + 0.5 * rnd(), dv[2] * k],
|
|
3979
4018
|
angularVelocity: [(rnd() - 0.5) * 8, (rnd() - 0.5) * 8, (rnd() - 0.5) * 8],
|
|
3980
4019
|
mass: mass * faceArea(cell) / total,
|
|
3981
|
-
...marks.length > 0 ? { marks } : {}
|
|
4020
|
+
...marks.length > 0 ? { marks } : {},
|
|
4021
|
+
...inner ? { inner } : {}
|
|
3982
4022
|
};
|
|
3983
4023
|
});
|
|
3984
4024
|
};
|
|
@@ -4019,7 +4059,7 @@ var createDestruction = (options = {}) => {
|
|
|
4019
4059
|
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);
|
|
4020
4060
|
};
|
|
4021
4061
|
const chipUnits = (o, p, kind, wp, hitEnergy, dir, radius, src) => {
|
|
4022
|
-
var _a, _b;
|
|
4062
|
+
var _a, _b, _c;
|
|
4023
4063
|
if (!p.spec.units || !p.staged || chipEnergy <= 0 || p.st.stripped || isLost(p) || (p.st.stage ?? 0) >= 2) return;
|
|
4024
4064
|
const rule = p.mat.hits?.[kind];
|
|
4025
4065
|
const perKg = rule?.unitJoules ?? chipEnergy;
|
|
@@ -4029,7 +4069,9 @@ var createDestruction = (options = {}) => {
|
|
|
4029
4069
|
const lp = toLocal(p.pos, p.q, objLocal(o, wp));
|
|
4030
4070
|
const grid = gridOf(p);
|
|
4031
4071
|
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
4072
|
+
const cut = (_b = p.rt).craters ?? (_b.craters = {});
|
|
4032
4073
|
const out = [];
|
|
4074
|
+
const shot = kind === "ballistic";
|
|
4033
4075
|
for (let i = 0; i < grid.length; i++) {
|
|
4034
4076
|
const cell = grid[i];
|
|
4035
4077
|
if (worn[i] === -1) continue;
|
|
@@ -4042,18 +4084,39 @@ var createDestruction = (options = {}) => {
|
|
|
4042
4084
|
worn[i] = total;
|
|
4043
4085
|
continue;
|
|
4044
4086
|
}
|
|
4045
|
-
|
|
4046
|
-
|
|
4087
|
+
if (!shot) {
|
|
4088
|
+
worn[i] = -1;
|
|
4089
|
+
out.push(cell);
|
|
4090
|
+
continue;
|
|
4091
|
+
}
|
|
4092
|
+
const size = [cell.size[0], cell.size[1], cell.size[2]];
|
|
4093
|
+
const center = [cell.center[0], cell.center[1], cell.center[2]];
|
|
4094
|
+
for (const a of [u, v]) {
|
|
4095
|
+
const w = Math.min(cell.size[a], craterAcross(hitEnergy) * (0.85 + 0.3 * rnd()));
|
|
4096
|
+
const lo = cell.center[a] - cell.size[a] / 2 + w / 2, hi = cell.center[a] + cell.size[a] / 2 - w / 2;
|
|
4097
|
+
size[a] = w;
|
|
4098
|
+
center[a] = clamp2(lp[a], lo, hi);
|
|
4099
|
+
}
|
|
4100
|
+
const taken2 = (cut[i] ?? 0) + size[u] * size[v];
|
|
4101
|
+
if (taken2 >= cell.size[u] * cell.size[v] * CRATER_SPENT) {
|
|
4102
|
+
worn[i] = -1;
|
|
4103
|
+
out.push({ ...cell, crater: true });
|
|
4104
|
+
continue;
|
|
4105
|
+
}
|
|
4106
|
+
worn[i] = 0;
|
|
4107
|
+
cut[i] = taken2;
|
|
4108
|
+
out.push({ center, size, crater: true });
|
|
4047
4109
|
}
|
|
4048
4110
|
if (out.length === 0) return;
|
|
4049
4111
|
const { c, q } = partXf(o, p);
|
|
4050
|
-
const chipped = (
|
|
4112
|
+
const chipped = (_c = p.st).chipped ?? (_c.chipped = []);
|
|
4051
4113
|
const holes = localHolesOf(p);
|
|
4052
4114
|
for (const cell of out) {
|
|
4053
4115
|
const mass = Math.min(p.st.mass, p.mat.density * cell.size[0] * cell.size[1] * cell.size[2]);
|
|
4054
4116
|
const center = toWorld(c, q, cell.center);
|
|
4055
4117
|
const speed = clamp2(Math.sqrt(2 * energy * 0.05 / Math.max(mass, 0.05)), 0.5, 6);
|
|
4056
|
-
const
|
|
4118
|
+
const tag = `c${chipped.length}_`;
|
|
4119
|
+
const fragments = cell.crater ? craterFragments(o, p, cell, dir, speed, mass, tag) : cellFragments(o, p, [cell], wp, dir, speed, mass, tag, true);
|
|
4057
4120
|
p.st.holes = p.st.holes.filter((_, k) => marksInBox(cell.center, cell.size, void 0, [holes[k]]).length === 0);
|
|
4058
4121
|
chipped.push({ center: [cell.center[0], cell.center[1], cell.center[2]], size: [cell.size[0], cell.size[1], cell.size[2]] });
|
|
4059
4122
|
p.st.mass = Math.max(0, p.st.mass - mass);
|
|
@@ -4070,6 +4133,44 @@ var createDestruction = (options = {}) => {
|
|
|
4070
4133
|
collapseCheck(o, src);
|
|
4071
4134
|
}
|
|
4072
4135
|
};
|
|
4136
|
+
const craterAcross = (energy) => clamp2(0.03 + 12e-4 * Math.sqrt(Math.max(0, energy)), 0.03, 0.14);
|
|
4137
|
+
const craterFragments = (o, p, cell, dir, speed, mass, tag) => {
|
|
4138
|
+
const { c, q } = partXf(o, p);
|
|
4139
|
+
const [u, v] = planeAxes(p.thin);
|
|
4140
|
+
const d = dir ?? rotateVec(q, [p.thin === 0 ? 1 : 0, p.thin === 1 ? 1 : 0, p.thin === 2 ? 1 : 0]);
|
|
4141
|
+
const exitSign = Math.sign(rotateVec(quat.conjugate(q), d)[p.thin]) || 1;
|
|
4142
|
+
const bit = Math.max(0.01, Math.min(cell.size[u], cell.size[v]) / 3);
|
|
4143
|
+
const n = clamp2(Math.round(cell.size[u] * cell.size[v] / (bit * bit * 3)), 4, 10) + Math.floor(rnd() * 3);
|
|
4144
|
+
const out = [];
|
|
4145
|
+
for (let i = 0; i < n; i++) {
|
|
4146
|
+
const back = i % 3 === 2;
|
|
4147
|
+
const lc = [cell.center[0], cell.center[1], cell.center[2]];
|
|
4148
|
+
lc[u] += (rnd() - 0.5) * cell.size[u] * 0.7;
|
|
4149
|
+
lc[v] += (rnd() - 0.5) * cell.size[v] * 0.7;
|
|
4150
|
+
lc[p.thin] += (back ? -exitSign : exitSign) * (p.thickness / 2 + 0.01);
|
|
4151
|
+
const size = [0, 0, 0];
|
|
4152
|
+
size[u] = bit * (0.6 + 0.8 * rnd());
|
|
4153
|
+
size[v] = bit * (0.5 + 0.7 * rnd());
|
|
4154
|
+
size[p.thin] = bit * (0.4 + 0.6 * rnd());
|
|
4155
|
+
const spread3 = [(rnd() - 0.5) * 0.9, (rnd() - 0.3) * 0.9, (rnd() - 0.5) * 0.9];
|
|
4156
|
+
const k = speed * (back ? 0.4 + 0.4 * rnd() : 0.7 + 0.8 * rnd());
|
|
4157
|
+
const vdir = vec.normalize(vec.add(back ? vec.scale(d, -1) : d, spread3));
|
|
4158
|
+
out.push({
|
|
4159
|
+
id: `${p.spec.id}#${tag}${i}`,
|
|
4160
|
+
part: p.spec.id,
|
|
4161
|
+
material: p.spec.material,
|
|
4162
|
+
shape: "chunk",
|
|
4163
|
+
center: toWorld(c, q, lc),
|
|
4164
|
+
size,
|
|
4165
|
+
rotation: q,
|
|
4166
|
+
velocity: [vdir[0] * k, vdir[1] * k + 0.5 * rnd(), vdir[2] * k],
|
|
4167
|
+
angularVelocity: [(rnd() - 0.5) * 20, (rnd() - 0.5) * 20, (rnd() - 0.5) * 20],
|
|
4168
|
+
mass: mass / n,
|
|
4169
|
+
inner: true
|
|
4170
|
+
});
|
|
4171
|
+
}
|
|
4172
|
+
return out;
|
|
4173
|
+
};
|
|
4073
4174
|
const exposeRebar = (o, p, src) => {
|
|
4074
4175
|
const r = p.spec.reinforcement;
|
|
4075
4176
|
if (!r) return;
|
|
@@ -4357,7 +4458,7 @@ var createDestruction = (options = {}) => {
|
|
|
4357
4458
|
});
|
|
4358
4459
|
}
|
|
4359
4460
|
const patch = [scale * 4, scale * 4, scale * 4];
|
|
4360
|
-
emit({ ...base(o, src), type: "chip", part: p.spec.id, center: exit ?? entry, size: patch, rotation: q, fragments });
|
|
4461
|
+
emit({ ...base(o, src), type: "chip", part: p.spec.id, center: exit ?? entry, size: patch, rotation: q, fragments, torn: true });
|
|
4361
4462
|
};
|
|
4362
4463
|
const ballistic = (o, p, entry, n, d, E, caliber, pathLen, src, round = {}) => {
|
|
4363
4464
|
const mat = p.mat;
|
|
@@ -4416,12 +4517,13 @@ var createDestruction = (options = {}) => {
|
|
|
4416
4517
|
} else if (mat.ductility >= 0.5) {
|
|
4417
4518
|
addDent(o, p, entry, n, Math.max(caliber * 3 / 1e3, 0.012), clamp2(Math.min(Math.max(p.thickness * 3, 3e-3), ratio * 0.01), 1e-3, 0.05), src);
|
|
4418
4519
|
} else if (brittle) {
|
|
4419
|
-
addCrack(o, p, entry, n, crackLen, src);
|
|
4520
|
+
if (!p.spec.units) addCrack(o, p, entry, n, crackLen, src);
|
|
4420
4521
|
if (mat.fracture !== "shatter") addHole(o, p, entry, n, caliber / 1e3, false, void 0, src);
|
|
4421
4522
|
} else addHole(o, p, entry, n, caliber / 1e3, false, void 0, src);
|
|
4422
4523
|
debris(o, p, mat.hitDebris, entry, n, clamp2(Math.round(E / 60) + 2, 2, 14), clamp2(Math.sqrt(E) / 6, 1, 8), src);
|
|
4423
4524
|
wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true, BULLET_JOINT_SPAN);
|
|
4424
|
-
const
|
|
4525
|
+
const hollowTear = mat.fracture === "tear" && p.spec.fill !== void 0 && p.spec.fill < 0.5;
|
|
4526
|
+
const absorbed = penetrated && (mat.ductility >= 0.5 && mat.fracture !== "tear" || hollowTear) ? Math.min(E, thr) : E;
|
|
4425
4527
|
const dmg = applyDamage(o, p, absorbed * DMG_PER_J * scale, "ballistic", entry, d, absorbed * 0.1, 12, src);
|
|
4426
4528
|
if (!isLost(p)) tearAt(o, p, "ballistic", entry, penetrated ? exitPoint : void 0, d, E, caliber / 1e3, src);
|
|
4427
4529
|
chipUnits(o, p, "ballistic", entry, penetrated ? Math.min(E, Math.max(thr, E * 0.5)) : E, d, Math.max(0.05, caliber / 1e3 * 8), src);
|
|
@@ -4506,10 +4608,25 @@ var createDestruction = (options = {}) => {
|
|
|
4506
4608
|
if (dist <= BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3)) addBreach(o, p, wp, breachAreaOf(p, dealt, true), Ein, null, src);
|
|
4507
4609
|
return reach;
|
|
4508
4610
|
};
|
|
4611
|
+
const blastProbe = { partsTested: 0, partsNear: 0 };
|
|
4612
|
+
const blastCandidates = (o, point, radius) => {
|
|
4613
|
+
const local = toLocal(o.st.position, o.st.rotation, point);
|
|
4614
|
+
const near = [];
|
|
4615
|
+
for (const p of o.parts) {
|
|
4616
|
+
const reach = radius + p.bound;
|
|
4617
|
+
const dx = local[0] - p.pos[0];
|
|
4618
|
+
const dy = local[1] - p.pos[1];
|
|
4619
|
+
const dz = local[2] - p.pos[2];
|
|
4620
|
+
if (dx * dx + dy * dy + dz * dz < reach * reach) near.push(p);
|
|
4621
|
+
}
|
|
4622
|
+
blastProbe.partsTested += o.parts.length;
|
|
4623
|
+
blastProbe.partsNear += near.length;
|
|
4624
|
+
return near;
|
|
4625
|
+
};
|
|
4509
4626
|
const blastObject = (o, point, energy, radius, src) => {
|
|
4510
4627
|
const start = cur.length;
|
|
4511
4628
|
const res = { object: o.id, damage: 0, penetrated: false, exitEnergy: 0, events: [] };
|
|
4512
|
-
for (const p of o
|
|
4629
|
+
for (const p of blastCandidates(o, point, radius)) blastPart(o, p, point, energy, radius, src, res);
|
|
4513
4630
|
res.events = cur.slice(start);
|
|
4514
4631
|
return res;
|
|
4515
4632
|
};
|
|
@@ -4633,7 +4750,7 @@ var createDestruction = (options = {}) => {
|
|
|
4633
4750
|
let order = 0;
|
|
4634
4751
|
for (const o of inRange) {
|
|
4635
4752
|
if (only && only !== o) continue;
|
|
4636
|
-
for (const p of o
|
|
4753
|
+
for (const p of blastCandidates(o, point, radius)) {
|
|
4637
4754
|
if (isLost(p)) continue;
|
|
4638
4755
|
const dist = distToPart(o, p, point);
|
|
4639
4756
|
if (dist < radius) items.push({ dist, order: order++, o, p });
|
|
@@ -5180,6 +5297,7 @@ var createDestruction = (options = {}) => {
|
|
|
5180
5297
|
const p = getPart(o, partId);
|
|
5181
5298
|
p.pos = [position[0], position[1], position[2]];
|
|
5182
5299
|
p.q = q;
|
|
5300
|
+
poseVersion++;
|
|
5183
5301
|
updateBound(o);
|
|
5184
5302
|
},
|
|
5185
5303
|
remove(id) {
|
|
@@ -5198,6 +5316,7 @@ var createDestruction = (options = {}) => {
|
|
|
5198
5316
|
const o = getObj(id);
|
|
5199
5317
|
o.base = { pos: [position[0], position[1], position[2]], rot: [rotation[0], rotation[1], rotation[2], rotation[3]] };
|
|
5200
5318
|
applySoilPose(o);
|
|
5319
|
+
slideOffResting(o, rotation);
|
|
5201
5320
|
},
|
|
5202
5321
|
splitGroup(id, group, newId) {
|
|
5203
5322
|
if (impls.has(id)) throw new Error(`object "${id}" is a registered DestructibleImpl and cannot be split; its module owns its pieces`);
|
|
@@ -5221,7 +5340,7 @@ var createDestruction = (options = {}) => {
|
|
|
5221
5340
|
if (o.spec.name !== void 0) s.name = o.spec.name;
|
|
5222
5341
|
if (o.spec.tags) s.tags = [...o.spec.tags];
|
|
5223
5342
|
if (o.spec.soil !== void 0) s.soil = o.spec.soil;
|
|
5224
|
-
return
|
|
5343
|
+
return s;
|
|
5225
5344
|
};
|
|
5226
5345
|
const inNew = (pid) => moved.has(pid);
|
|
5227
5346
|
const inOld = (pid) => !moved.has(pid);
|
|
@@ -5248,7 +5367,12 @@ var createDestruction = (options = {}) => {
|
|
|
5248
5367
|
const p = getPart(o, partId);
|
|
5249
5368
|
return whole(() => doHit(o, h, p));
|
|
5250
5369
|
},
|
|
5370
|
+
blastProbe() {
|
|
5371
|
+
return { ...blastProbe };
|
|
5372
|
+
},
|
|
5251
5373
|
explode(point, energy, radius, source, blast) {
|
|
5374
|
+
blastProbe.partsTested = 0;
|
|
5375
|
+
blastProbe.partsNear = 0;
|
|
5252
5376
|
return withCollapses(run(() => blastWorld(point, energy, radius, source, blast)));
|
|
5253
5377
|
},
|
|
5254
5378
|
raycast(origin, direction, maxDistance = Infinity) {
|
|
@@ -5258,7 +5382,8 @@ var createDestruction = (options = {}) => {
|
|
|
5258
5382
|
sweepBox(box, direction, distance, options2 = {}) {
|
|
5259
5383
|
const d = vec.normalize(direction);
|
|
5260
5384
|
const ignored = options2.ignore === void 0 ? void 0 : objects.get(options2.ignore);
|
|
5261
|
-
const
|
|
5385
|
+
const hosted = options2.ignore === void 0 || ignored ? void 0 : impls.get(options2.ignore);
|
|
5386
|
+
const ignore = ignored ? new Set(ignored.parts.map((p) => `${ignored.id}\0${p.spec.id}`)) : hosted ? new Set(hosted.impl.describe().parts.map((p) => `${hosted.impl.id}\0${p.id}`)) : void 0;
|
|
5262
5387
|
let best = null;
|
|
5263
5388
|
for (const origin of sweepOrigins(box, d, options2.spacing ?? 0.2)) {
|
|
5264
5389
|
const r = raycastInternal(origin, d, distance + SWEEP_BACK, ignore);
|