@adatechnology/game-destruction 0.12.0 → 0.13.1
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 +160 -18
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +160 -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,8 @@ 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;
|
|
2726
|
+
var EDGE_REACH = 1.5;
|
|
2724
2727
|
var BAR_BOW = 0.08;
|
|
2725
2728
|
var BULLET_JOINT_SPAN = 0.3;
|
|
2726
2729
|
var CUT_SLICE = 1;
|
|
@@ -2741,12 +2744,22 @@ var sectionLoss = (p) => {
|
|
|
2741
2744
|
const cells = p.st.chipped;
|
|
2742
2745
|
if (!cells?.length) return 0;
|
|
2743
2746
|
const [u, v] = planeAxes(p.thin);
|
|
2744
|
-
const
|
|
2747
|
+
const role = p.spec.structure?.role;
|
|
2748
|
+
const up = rotateVec(p.q, [0, 0, 0].map((_, k) => k === v ? 1 : 0));
|
|
2749
|
+
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;
|
|
2750
|
+
const along = (role === "wall" || role === "partition" || role === "column") && upright >= 0 ? upright : p.dims[u] >= p.dims[v] ? u : v;
|
|
2745
2751
|
const across = along === u ? v : u;
|
|
2746
2752
|
let worst = 0;
|
|
2747
2753
|
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)
|
|
2754
|
+
const spans = [];
|
|
2755
|
+
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]);
|
|
2756
|
+
spans.sort((a, b) => a[0] - b[0]);
|
|
2757
|
+
let gone = 0, end = -Infinity;
|
|
2758
|
+
for (const [a, b] of spans) {
|
|
2759
|
+
if (b <= end) continue;
|
|
2760
|
+
gone += b - Math.max(a, end);
|
|
2761
|
+
end = b;
|
|
2762
|
+
}
|
|
2750
2763
|
worst = Math.max(worst, gone / Math.max(p.dims[across], 1e-6));
|
|
2751
2764
|
}
|
|
2752
2765
|
return Math.min(1, worst);
|
|
@@ -3042,7 +3055,18 @@ var createDestruction = (options = {}) => {
|
|
|
3042
3055
|
if (k < 0 || j.spec.kind !== "tie") return k;
|
|
3043
3056
|
return partXf(o, o.parts[k]).c[1] > partXf(o, o.parts[r]).c[1] + 1e-6 ? k : -1;
|
|
3044
3057
|
};
|
|
3058
|
+
let poseVersion = 0;
|
|
3059
|
+
const contactMemo = /* @__PURE__ */ new WeakMap();
|
|
3045
3060
|
const contactBox = (p, support) => {
|
|
3061
|
+
let byTouching = contactMemo.get(p);
|
|
3062
|
+
if (!byTouching) contactMemo.set(p, byTouching = /* @__PURE__ */ new Map());
|
|
3063
|
+
const known = byTouching.get(support);
|
|
3064
|
+
if (known && known.version === poseVersion) return known.box;
|
|
3065
|
+
const box = measureContact(p, support);
|
|
3066
|
+
byTouching.set(support, { version: poseVersion, box });
|
|
3067
|
+
return box;
|
|
3068
|
+
};
|
|
3069
|
+
const measureContact = (p, support) => {
|
|
3046
3070
|
const A = aabbOf(p.spec.shape, p.pos, p.q), B = aabbOf(support.spec.shape, support.pos, support.q);
|
|
3047
3071
|
const lo = [0, 0, 0], hi = [0, 0, 0];
|
|
3048
3072
|
for (let k = 0; k < 3; k++) {
|
|
@@ -3837,7 +3861,7 @@ var createDestruction = (options = {}) => {
|
|
|
3837
3861
|
p.st.holes.push(hole);
|
|
3838
3862
|
if (p.st.holes.length > maxHoles) p.st.holes.shift();
|
|
3839
3863
|
markDamaged(p);
|
|
3840
|
-
emit({ ...base(o, src), type: "hole", part: p.spec.id, hole, worldPoint: wp, ...exit ? { exitPoint: exit } : {} });
|
|
3864
|
+
emit({ ...base(o, src), type: "hole", part: p.spec.id, hole, worldPoint: wp, ...exit ? { exitPoint: exit } : {}, ...p.spec.powder ? { powder: { ...p.spec.powder } } : {} });
|
|
3841
3865
|
setStage(o, p, 1, {}, src);
|
|
3842
3866
|
return hole;
|
|
3843
3867
|
};
|
|
@@ -3854,6 +3878,22 @@ var createDestruction = (options = {}) => {
|
|
|
3854
3878
|
const detachEvents = (o, opened, by, src) => {
|
|
3855
3879
|
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
3880
|
};
|
|
3881
|
+
const slideOffResting = (o, rotation) => {
|
|
3882
|
+
const upY = 1 - 2 * (rotation[0] * rotation[0] + rotation[2] * rotation[2]);
|
|
3883
|
+
if (upY >= RESTING_HOLD_COS) return;
|
|
3884
|
+
const opened = o.joints.filter((j) => j.spec.kind === "resting" && !j.st.open);
|
|
3885
|
+
if (opened.length === 0) return;
|
|
3886
|
+
run(() => {
|
|
3887
|
+
for (const j of opened) {
|
|
3888
|
+
j.st.open = true;
|
|
3889
|
+
j.st.openedBy = "break";
|
|
3890
|
+
}
|
|
3891
|
+
solveStructure(o);
|
|
3892
|
+
recomputeGroups(o);
|
|
3893
|
+
detachEvents(o, opened, "break");
|
|
3894
|
+
collapseCheck(o);
|
|
3895
|
+
});
|
|
3896
|
+
};
|
|
3857
3897
|
const checkDestroyed = (o, src) => {
|
|
3858
3898
|
if (!o.st.destroyed && o.parts.length > 0 && o.parts.every(isLost)) {
|
|
3859
3899
|
o.st.destroyed = true;
|
|
@@ -3954,7 +3994,7 @@ var createDestruction = (options = {}) => {
|
|
|
3954
3994
|
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
3995
|
const unitsOf = (p) => p.spec.units ?? { size: [p.mat.fragmentSize?.[1] ?? 0.2, p.mat.fragmentSize?.[1] ?? 0.2, p.thickness], bond: "stack" };
|
|
3956
3996
|
const FRAGMENT_SHAPE = { shatter: "shard", splinter: "splinter", tear: "scrap" };
|
|
3957
|
-
const cellFragments = (o, p, cells, hitW, dir, speed, mass, tag) => {
|
|
3997
|
+
const cellFragments = (o, p, cells, hitW, dir, speed, mass, tag, inner = false) => {
|
|
3958
3998
|
const { c, q } = partXf(o, p);
|
|
3959
3999
|
const holes = p.st.holes.length > 0 ? localHolesOf(p) : [];
|
|
3960
4000
|
const [u, v] = planeAxes(p.thin);
|
|
@@ -3978,7 +4018,8 @@ var createDestruction = (options = {}) => {
|
|
|
3978
4018
|
velocity: [dv[0] * k, dv[1] * k + 0.5 * rnd(), dv[2] * k],
|
|
3979
4019
|
angularVelocity: [(rnd() - 0.5) * 8, (rnd() - 0.5) * 8, (rnd() - 0.5) * 8],
|
|
3980
4020
|
mass: mass * faceArea(cell) / total,
|
|
3981
|
-
...marks.length > 0 ? { marks } : {}
|
|
4021
|
+
...marks.length > 0 ? { marks } : {},
|
|
4022
|
+
...inner ? { inner } : {}
|
|
3982
4023
|
};
|
|
3983
4024
|
});
|
|
3984
4025
|
};
|
|
@@ -4019,7 +4060,7 @@ var createDestruction = (options = {}) => {
|
|
|
4019
4060
|
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
4061
|
};
|
|
4021
4062
|
const chipUnits = (o, p, kind, wp, hitEnergy, dir, radius, src) => {
|
|
4022
|
-
var _a, _b;
|
|
4063
|
+
var _a, _b, _c;
|
|
4023
4064
|
if (!p.spec.units || !p.staged || chipEnergy <= 0 || p.st.stripped || isLost(p) || (p.st.stage ?? 0) >= 2) return;
|
|
4024
4065
|
const rule = p.mat.hits?.[kind];
|
|
4025
4066
|
const perKg = rule?.unitJoules ?? chipEnergy;
|
|
@@ -4029,7 +4070,9 @@ var createDestruction = (options = {}) => {
|
|
|
4029
4070
|
const lp = toLocal(p.pos, p.q, objLocal(o, wp));
|
|
4030
4071
|
const grid = gridOf(p);
|
|
4031
4072
|
const worn = (_a = p.rt).chips ?? (_a.chips = {});
|
|
4073
|
+
const cut = (_b = p.rt).craters ?? (_b.craters = {});
|
|
4032
4074
|
const out = [];
|
|
4075
|
+
const shot = kind === "ballistic";
|
|
4033
4076
|
for (let i = 0; i < grid.length; i++) {
|
|
4034
4077
|
const cell = grid[i];
|
|
4035
4078
|
if (worn[i] === -1) continue;
|
|
@@ -4042,18 +4085,42 @@ var createDestruction = (options = {}) => {
|
|
|
4042
4085
|
worn[i] = total;
|
|
4043
4086
|
continue;
|
|
4044
4087
|
}
|
|
4045
|
-
|
|
4046
|
-
|
|
4088
|
+
if (!shot) {
|
|
4089
|
+
worn[i] = -1;
|
|
4090
|
+
out.push(cell);
|
|
4091
|
+
continue;
|
|
4092
|
+
}
|
|
4093
|
+
const size = [cell.size[0], cell.size[1], cell.size[2]];
|
|
4094
|
+
const center = [cell.center[0], cell.center[1], cell.center[2]];
|
|
4095
|
+
for (const a of [u, v]) {
|
|
4096
|
+
const w = Math.min(cell.size[a], craterAcross(hitEnergy) * (0.85 + 0.3 * rnd()));
|
|
4097
|
+
const lo = cell.center[a] - cell.size[a] / 2 + w / 2, hi = cell.center[a] + cell.size[a] / 2 - w / 2;
|
|
4098
|
+
size[a] = w;
|
|
4099
|
+
center[a] = clamp2(lp[a], lo, hi);
|
|
4100
|
+
const [from, to] = tornToEdge({ p, cell, a, b: a === u ? v : u, at: lp[a], crater: [center[a] - w / 2, center[a] + w / 2], reach: w * EDGE_REACH, gone: (k) => worn[k] === -1 });
|
|
4101
|
+
size[a] = to - from;
|
|
4102
|
+
center[a] = (from + to) / 2;
|
|
4103
|
+
}
|
|
4104
|
+
const taken2 = (cut[i] ?? 0) + size[u] * size[v];
|
|
4105
|
+
if (taken2 >= cell.size[u] * cell.size[v] * CRATER_SPENT) {
|
|
4106
|
+
worn[i] = -1;
|
|
4107
|
+
out.push({ ...cell, crater: true });
|
|
4108
|
+
continue;
|
|
4109
|
+
}
|
|
4110
|
+
worn[i] = 0;
|
|
4111
|
+
cut[i] = taken2;
|
|
4112
|
+
out.push({ center, size, crater: true });
|
|
4047
4113
|
}
|
|
4048
4114
|
if (out.length === 0) return;
|
|
4049
4115
|
const { c, q } = partXf(o, p);
|
|
4050
|
-
const chipped = (
|
|
4116
|
+
const chipped = (_c = p.st).chipped ?? (_c.chipped = []);
|
|
4051
4117
|
const holes = localHolesOf(p);
|
|
4052
4118
|
for (const cell of out) {
|
|
4053
4119
|
const mass = Math.min(p.st.mass, p.mat.density * cell.size[0] * cell.size[1] * cell.size[2]);
|
|
4054
4120
|
const center = toWorld(c, q, cell.center);
|
|
4055
4121
|
const speed = clamp2(Math.sqrt(2 * energy * 0.05 / Math.max(mass, 0.05)), 0.5, 6);
|
|
4056
|
-
const
|
|
4122
|
+
const tag = `c${chipped.length}_`;
|
|
4123
|
+
const fragments = cell.crater ? craterFragments(o, p, cell, dir, speed, mass, tag) : cellFragments(o, p, [cell], wp, dir, speed, mass, tag, true);
|
|
4057
4124
|
p.st.holes = p.st.holes.filter((_, k) => marksInBox(cell.center, cell.size, void 0, [holes[k]]).length === 0);
|
|
4058
4125
|
chipped.push({ center: [cell.center[0], cell.center[1], cell.center[2]], size: [cell.size[0], cell.size[1], cell.size[2]] });
|
|
4059
4126
|
p.st.mass = Math.max(0, p.st.mass - mass);
|
|
@@ -4070,6 +4137,57 @@ var createDestruction = (options = {}) => {
|
|
|
4070
4137
|
collapseCheck(o, src);
|
|
4071
4138
|
}
|
|
4072
4139
|
};
|
|
4140
|
+
const tornToEdge = (o) => {
|
|
4141
|
+
const { p, cell, a, b, at, crater: crater2, reach, gone } = o;
|
|
4142
|
+
const half = p.dims[a] / 2;
|
|
4143
|
+
const lo = cell.center[a] - cell.size[a] / 2, hi = cell.center[a] + cell.size[a] / 2;
|
|
4144
|
+
const free = (side, sign) => {
|
|
4145
|
+
if (sign > 0 ? side >= half - 1e-6 : side <= -half + 1e-6) return sign > 0 || a !== planeAxes(p.thin)[1];
|
|
4146
|
+
const probe = side + sign * 1e-3;
|
|
4147
|
+
return gridOf(p).some((c, k) => gone(k) && Math.abs(probe - c.center[a]) <= c.size[a] / 2 && Math.abs(cell.center[b] - c.center[b]) <= c.size[b] / 2);
|
|
4148
|
+
};
|
|
4149
|
+
if (at - lo <= reach && free(lo, -1)) return [lo, Math.max(crater2[1], lo)];
|
|
4150
|
+
if (hi - at <= reach && free(hi, 1)) return [Math.min(crater2[0], hi), hi];
|
|
4151
|
+
return crater2;
|
|
4152
|
+
};
|
|
4153
|
+
const craterAcross = (energy) => clamp2(0.03 + 12e-4 * Math.sqrt(Math.max(0, energy)), 0.03, 0.14);
|
|
4154
|
+
const craterFragments = (o, p, cell, dir, speed, mass, tag) => {
|
|
4155
|
+
const { c, q } = partXf(o, p);
|
|
4156
|
+
const [u, v] = planeAxes(p.thin);
|
|
4157
|
+
const d = dir ?? rotateVec(q, [p.thin === 0 ? 1 : 0, p.thin === 1 ? 1 : 0, p.thin === 2 ? 1 : 0]);
|
|
4158
|
+
const exitSign = Math.sign(rotateVec(quat.conjugate(q), d)[p.thin]) || 1;
|
|
4159
|
+
const bit = Math.max(0.01, Math.min(cell.size[u], cell.size[v]) / 3);
|
|
4160
|
+
const n = clamp2(Math.round(cell.size[u] * cell.size[v] / (bit * bit * 3)), 4, 10) + Math.floor(rnd() * 3);
|
|
4161
|
+
const out = [];
|
|
4162
|
+
for (let i = 0; i < n; i++) {
|
|
4163
|
+
const back = i % 3 === 2;
|
|
4164
|
+
const lc = [cell.center[0], cell.center[1], cell.center[2]];
|
|
4165
|
+
lc[u] += (rnd() - 0.5) * cell.size[u] * 0.7;
|
|
4166
|
+
lc[v] += (rnd() - 0.5) * cell.size[v] * 0.7;
|
|
4167
|
+
lc[p.thin] += (back ? -exitSign : exitSign) * (p.thickness / 2 + 0.01);
|
|
4168
|
+
const size = [0, 0, 0];
|
|
4169
|
+
size[u] = bit * (0.6 + 0.8 * rnd());
|
|
4170
|
+
size[v] = bit * (0.5 + 0.7 * rnd());
|
|
4171
|
+
size[p.thin] = bit * (0.4 + 0.6 * rnd());
|
|
4172
|
+
const spread3 = [(rnd() - 0.5) * 0.9, (rnd() - 0.3) * 0.9, (rnd() - 0.5) * 0.9];
|
|
4173
|
+
const k = speed * (back ? 0.4 + 0.4 * rnd() : 0.7 + 0.8 * rnd());
|
|
4174
|
+
const vdir = vec.normalize(vec.add(back ? vec.scale(d, -1) : d, spread3));
|
|
4175
|
+
out.push({
|
|
4176
|
+
id: `${p.spec.id}#${tag}${i}`,
|
|
4177
|
+
part: p.spec.id,
|
|
4178
|
+
material: p.spec.material,
|
|
4179
|
+
shape: "chunk",
|
|
4180
|
+
center: toWorld(c, q, lc),
|
|
4181
|
+
size,
|
|
4182
|
+
rotation: q,
|
|
4183
|
+
velocity: [vdir[0] * k, vdir[1] * k + 0.5 * rnd(), vdir[2] * k],
|
|
4184
|
+
angularVelocity: [(rnd() - 0.5) * 20, (rnd() - 0.5) * 20, (rnd() - 0.5) * 20],
|
|
4185
|
+
mass: mass / n,
|
|
4186
|
+
inner: true
|
|
4187
|
+
});
|
|
4188
|
+
}
|
|
4189
|
+
return out;
|
|
4190
|
+
};
|
|
4073
4191
|
const exposeRebar = (o, p, src) => {
|
|
4074
4192
|
const r = p.spec.reinforcement;
|
|
4075
4193
|
if (!r) return;
|
|
@@ -4357,7 +4475,7 @@ var createDestruction = (options = {}) => {
|
|
|
4357
4475
|
});
|
|
4358
4476
|
}
|
|
4359
4477
|
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 });
|
|
4478
|
+
emit({ ...base(o, src), type: "chip", part: p.spec.id, center: exit ?? entry, size: patch, rotation: q, fragments, torn: true });
|
|
4361
4479
|
};
|
|
4362
4480
|
const ballistic = (o, p, entry, n, d, E, caliber, pathLen, src, round = {}) => {
|
|
4363
4481
|
const mat = p.mat;
|
|
@@ -4416,12 +4534,13 @@ var createDestruction = (options = {}) => {
|
|
|
4416
4534
|
} else if (mat.ductility >= 0.5) {
|
|
4417
4535
|
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
4536
|
} else if (brittle) {
|
|
4419
|
-
addCrack(o, p, entry, n, crackLen, src);
|
|
4537
|
+
if (!p.spec.units) addCrack(o, p, entry, n, crackLen, src);
|
|
4420
4538
|
if (mat.fracture !== "shatter") addHole(o, p, entry, n, caliber / 1e3, false, void 0, src);
|
|
4421
4539
|
} else addHole(o, p, entry, n, caliber / 1e3, false, void 0, src);
|
|
4422
4540
|
debris(o, p, mat.hitDebris, entry, n, clamp2(Math.round(E / 60) + 2, 2, 14), clamp2(Math.sqrt(E) / 6, 1, 8), src);
|
|
4423
4541
|
wearJoints(o, p, (penetrated ? thr : E) * 0.02, void 0, 0, src, true, BULLET_JOINT_SPAN);
|
|
4424
|
-
const
|
|
4542
|
+
const hollowTear = mat.fracture === "tear" && p.spec.fill !== void 0 && p.spec.fill < 0.5;
|
|
4543
|
+
const absorbed = penetrated && (mat.ductility >= 0.5 && mat.fracture !== "tear" || hollowTear) ? Math.min(E, thr) : E;
|
|
4425
4544
|
const dmg = applyDamage(o, p, absorbed * DMG_PER_J * scale, "ballistic", entry, d, absorbed * 0.1, 12, src);
|
|
4426
4545
|
if (!isLost(p)) tearAt(o, p, "ballistic", entry, penetrated ? exitPoint : void 0, d, E, caliber / 1e3, src);
|
|
4427
4546
|
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 +4625,25 @@ var createDestruction = (options = {}) => {
|
|
|
4506
4625
|
if (dist <= BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1e3)) addBreach(o, p, wp, breachAreaOf(p, dealt, true), Ein, null, src);
|
|
4507
4626
|
return reach;
|
|
4508
4627
|
};
|
|
4628
|
+
const blastProbe = { partsTested: 0, partsNear: 0 };
|
|
4629
|
+
const blastCandidates = (o, point, radius) => {
|
|
4630
|
+
const local = toLocal(o.st.position, o.st.rotation, point);
|
|
4631
|
+
const near = [];
|
|
4632
|
+
for (const p of o.parts) {
|
|
4633
|
+
const reach = radius + p.bound;
|
|
4634
|
+
const dx = local[0] - p.pos[0];
|
|
4635
|
+
const dy = local[1] - p.pos[1];
|
|
4636
|
+
const dz = local[2] - p.pos[2];
|
|
4637
|
+
if (dx * dx + dy * dy + dz * dz < reach * reach) near.push(p);
|
|
4638
|
+
}
|
|
4639
|
+
blastProbe.partsTested += o.parts.length;
|
|
4640
|
+
blastProbe.partsNear += near.length;
|
|
4641
|
+
return near;
|
|
4642
|
+
};
|
|
4509
4643
|
const blastObject = (o, point, energy, radius, src) => {
|
|
4510
4644
|
const start = cur.length;
|
|
4511
4645
|
const res = { object: o.id, damage: 0, penetrated: false, exitEnergy: 0, events: [] };
|
|
4512
|
-
for (const p of o
|
|
4646
|
+
for (const p of blastCandidates(o, point, radius)) blastPart(o, p, point, energy, radius, src, res);
|
|
4513
4647
|
res.events = cur.slice(start);
|
|
4514
4648
|
return res;
|
|
4515
4649
|
};
|
|
@@ -4633,7 +4767,7 @@ var createDestruction = (options = {}) => {
|
|
|
4633
4767
|
let order = 0;
|
|
4634
4768
|
for (const o of inRange) {
|
|
4635
4769
|
if (only && only !== o) continue;
|
|
4636
|
-
for (const p of o
|
|
4770
|
+
for (const p of blastCandidates(o, point, radius)) {
|
|
4637
4771
|
if (isLost(p)) continue;
|
|
4638
4772
|
const dist = distToPart(o, p, point);
|
|
4639
4773
|
if (dist < radius) items.push({ dist, order: order++, o, p });
|
|
@@ -5180,6 +5314,7 @@ var createDestruction = (options = {}) => {
|
|
|
5180
5314
|
const p = getPart(o, partId);
|
|
5181
5315
|
p.pos = [position[0], position[1], position[2]];
|
|
5182
5316
|
p.q = q;
|
|
5317
|
+
poseVersion++;
|
|
5183
5318
|
updateBound(o);
|
|
5184
5319
|
},
|
|
5185
5320
|
remove(id) {
|
|
@@ -5198,6 +5333,7 @@ var createDestruction = (options = {}) => {
|
|
|
5198
5333
|
const o = getObj(id);
|
|
5199
5334
|
o.base = { pos: [position[0], position[1], position[2]], rot: [rotation[0], rotation[1], rotation[2], rotation[3]] };
|
|
5200
5335
|
applySoilPose(o);
|
|
5336
|
+
slideOffResting(o, rotation);
|
|
5201
5337
|
},
|
|
5202
5338
|
splitGroup(id, group, newId) {
|
|
5203
5339
|
if (impls.has(id)) throw new Error(`object "${id}" is a registered DestructibleImpl and cannot be split; its module owns its pieces`);
|
|
@@ -5221,7 +5357,7 @@ var createDestruction = (options = {}) => {
|
|
|
5221
5357
|
if (o.spec.name !== void 0) s.name = o.spec.name;
|
|
5222
5358
|
if (o.spec.tags) s.tags = [...o.spec.tags];
|
|
5223
5359
|
if (o.spec.soil !== void 0) s.soil = o.spec.soil;
|
|
5224
|
-
return
|
|
5360
|
+
return s;
|
|
5225
5361
|
};
|
|
5226
5362
|
const inNew = (pid) => moved.has(pid);
|
|
5227
5363
|
const inOld = (pid) => !moved.has(pid);
|
|
@@ -5248,7 +5384,12 @@ var createDestruction = (options = {}) => {
|
|
|
5248
5384
|
const p = getPart(o, partId);
|
|
5249
5385
|
return whole(() => doHit(o, h, p));
|
|
5250
5386
|
},
|
|
5387
|
+
blastProbe() {
|
|
5388
|
+
return { ...blastProbe };
|
|
5389
|
+
},
|
|
5251
5390
|
explode(point, energy, radius, source, blast) {
|
|
5391
|
+
blastProbe.partsTested = 0;
|
|
5392
|
+
blastProbe.partsNear = 0;
|
|
5252
5393
|
return withCollapses(run(() => blastWorld(point, energy, radius, source, blast)));
|
|
5253
5394
|
},
|
|
5254
5395
|
raycast(origin, direction, maxDistance = Infinity) {
|
|
@@ -5258,7 +5399,8 @@ var createDestruction = (options = {}) => {
|
|
|
5258
5399
|
sweepBox(box, direction, distance, options2 = {}) {
|
|
5259
5400
|
const d = vec.normalize(direction);
|
|
5260
5401
|
const ignored = options2.ignore === void 0 ? void 0 : objects.get(options2.ignore);
|
|
5261
|
-
const
|
|
5402
|
+
const hosted = options2.ignore === void 0 || ignored ? void 0 : impls.get(options2.ignore);
|
|
5403
|
+
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
5404
|
let best = null;
|
|
5263
5405
|
for (const origin of sweepOrigins(box, d, options2.spacing ?? 0.2)) {
|
|
5264
5406
|
const r = raycastInternal(origin, d, distance + SWEEP_BACK, ignore);
|