@adatechnology/game-destruction 0.13.2 → 0.15.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/README.md +5 -0
- package/dist/index.d.ts +46 -7
- package/dist/index.global.js +240 -20
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +115 -20
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -2796,6 +2796,7 @@ var createDestruction = (options = {}) => {
|
|
|
2796
2796
|
const ignitionRules = resolveIgnitionRules(options.ignition);
|
|
2797
2797
|
const breachBlastFactor = options.breach?.blastFactor ?? BREACH_BLAST_FACTOR;
|
|
2798
2798
|
const chipEnergy = options.breach?.chipEnergy ?? CHIP_ENERGY;
|
|
2799
|
+
const chainLinkCap = options.chainLinksPerUpdate !== void 0 && options.chainLinksPerUpdate >= 1 ? Math.floor(options.chainLinksPerUpdate) : Infinity;
|
|
2799
2800
|
const rng = createRng(options.seed ?? 1);
|
|
2800
2801
|
const rnd = () => rng.next();
|
|
2801
2802
|
let time = 0;
|
|
@@ -2818,7 +2819,13 @@ var createDestruction = (options = {}) => {
|
|
|
2818
2819
|
const typed = listeners.get(e.type);
|
|
2819
2820
|
if (typed) for (const fn of [...typed]) fn(e);
|
|
2820
2821
|
};
|
|
2821
|
-
|
|
2822
|
+
let blow;
|
|
2823
|
+
const base = (o, source) => ({
|
|
2824
|
+
object: o.id,
|
|
2825
|
+
time,
|
|
2826
|
+
...source === void 0 ? {} : { source },
|
|
2827
|
+
...blow === void 0 ? {} : { blow }
|
|
2828
|
+
});
|
|
2822
2829
|
const pendingCollapse = /* @__PURE__ */ new Map();
|
|
2823
2830
|
let runDepth = 0;
|
|
2824
2831
|
const drainBlasts = () => {
|
|
@@ -3743,7 +3750,7 @@ var createDestruction = (options = {}) => {
|
|
|
3743
3750
|
if (disc < 0) return true;
|
|
3744
3751
|
return -b - Math.sqrt(disc) > maxDist;
|
|
3745
3752
|
};
|
|
3746
|
-
const raycastInternal = (origin, dir, maxDist, ignore, worldOnly = false) => {
|
|
3753
|
+
const raycastInternal = (origin, dir, maxDist, ignore, worldOnly = false, precise = false) => {
|
|
3747
3754
|
const d = vec.normalize(dir);
|
|
3748
3755
|
let best = null;
|
|
3749
3756
|
for (const o of objects.values()) {
|
|
@@ -3758,13 +3765,25 @@ var createDestruction = (options = {}) => {
|
|
|
3758
3765
|
}
|
|
3759
3766
|
}
|
|
3760
3767
|
for (const im of worldOnly ? [] : impls.values()) {
|
|
3768
|
+
let boxHit = null;
|
|
3761
3769
|
for (const ps of im.impl.describe().parts) {
|
|
3762
3770
|
if (ignore?.has(`${im.impl.id}\0${ps.id}`)) continue;
|
|
3763
3771
|
const ov = im.poses.get(ps.id);
|
|
3764
3772
|
const r = rayPartRaw(im.position, im.rotation, ps, ov?.q ?? quatFromEuler(...ps.rotation ?? [0, 0, 0]), origin, d, ov?.pos);
|
|
3765
|
-
if (!r || r.
|
|
3766
|
-
if (
|
|
3773
|
+
if (!r || r.t1 < 0 || r.t0 > maxDist) continue;
|
|
3774
|
+
if (r.t0 < 0) {
|
|
3775
|
+
if (precise && im.impl.surfaceRay) boxHit = boxHit ?? { object: im.impl.id, part: ps.id, point: origin, normal: r.n, distance: 0, pathLen: r.t1 };
|
|
3776
|
+
continue;
|
|
3777
|
+
}
|
|
3778
|
+
if (!boxHit || r.t0 < boxHit.distance) boxHit = { object: im.impl.id, part: ps.id, point: vec.madd(origin, d, r.t0), normal: r.n, distance: r.t0, pathLen: r.t1 - r.t0 };
|
|
3767
3779
|
}
|
|
3780
|
+
if (!boxHit) continue;
|
|
3781
|
+
if (precise && im.impl.surfaceRay) {
|
|
3782
|
+
const far = best ? Math.min(maxDist, best.distance) : maxDist;
|
|
3783
|
+
const implId = im.impl.id;
|
|
3784
|
+
const s = im.impl.surfaceRay({ origin, direction: d, maxDistance: far, ...ignore ? { ignored: (part) => ignore.has(`${implId}\0${part}`) } : {} });
|
|
3785
|
+
if (s && (!best || s.distance < best.distance)) best = { object: implId, part: s.part, point: s.point, normal: s.normal, distance: s.distance, pathLen: s.pathLen };
|
|
3786
|
+
} else if (!best || boxHit.distance < best.distance) best = boxHit;
|
|
3768
3787
|
}
|
|
3769
3788
|
return best;
|
|
3770
3789
|
};
|
|
@@ -4951,7 +4970,17 @@ var createDestruction = (options = {}) => {
|
|
|
4951
4970
|
res.events = cur.slice(start);
|
|
4952
4971
|
return res;
|
|
4953
4972
|
};
|
|
4954
|
-
const
|
|
4973
|
+
const withBlow = (type, fn) => () => {
|
|
4974
|
+
const outer = blow;
|
|
4975
|
+
blow = type;
|
|
4976
|
+
try {
|
|
4977
|
+
return fn();
|
|
4978
|
+
} finally {
|
|
4979
|
+
blow = outer;
|
|
4980
|
+
}
|
|
4981
|
+
};
|
|
4982
|
+
const doHit = (o, hit, only) => withBlow(hit.type, () => resolveHit(o, hit, only))();
|
|
4983
|
+
const resolveHit = (o, hit, only) => {
|
|
4955
4984
|
let point = hit.point;
|
|
4956
4985
|
let dir = hit.direction;
|
|
4957
4986
|
if (hit.space === "local") {
|
|
@@ -5248,7 +5277,9 @@ var createDestruction = (options = {}) => {
|
|
|
5248
5277
|
};
|
|
5249
5278
|
const detonatePrimed = (until) => {
|
|
5250
5279
|
const end = time;
|
|
5251
|
-
|
|
5280
|
+
let fired = 0;
|
|
5281
|
+
for (let next = nextPrimed(until); next && fired < chainLinkCap; next = nextPrimed(until)) {
|
|
5282
|
+
fired++;
|
|
5252
5283
|
primed.delete(next.p);
|
|
5253
5284
|
time = Math.max(0, Math.min(end, next.p.rt.chainDue));
|
|
5254
5285
|
next.p.rt.chainDue = void 0;
|
|
@@ -5318,6 +5349,7 @@ var createDestruction = (options = {}) => {
|
|
|
5318
5349
|
updateBound(o);
|
|
5319
5350
|
},
|
|
5320
5351
|
remove(id) {
|
|
5352
|
+
impls.get(id)?.impl.dispose?.();
|
|
5321
5353
|
objects.delete(id);
|
|
5322
5354
|
impls.delete(id);
|
|
5323
5355
|
},
|
|
@@ -5387,13 +5419,51 @@ var createDestruction = (options = {}) => {
|
|
|
5387
5419
|
blastProbe() {
|
|
5388
5420
|
return { ...blastProbe };
|
|
5389
5421
|
},
|
|
5422
|
+
blastReach(point, target, options2 = {}) {
|
|
5423
|
+
const L = vec.distance(point, target);
|
|
5424
|
+
if (L < 1e-4) return 1;
|
|
5425
|
+
const shelter = { ...SHELTER_DEFAULTS, ...options2.shelter };
|
|
5426
|
+
const ignore = new Set(options2.ignore ?? []);
|
|
5427
|
+
const d = vec.scale(vec.sub(target, point), 1 / L);
|
|
5428
|
+
let t = 1;
|
|
5429
|
+
for (const o of objects.values()) {
|
|
5430
|
+
if (ignore.has(o.id) || raySphereMiss(point, d, toWorld(o.st.position, o.st.rotation, o.bc), o.br, L)) continue;
|
|
5431
|
+
for (const p of o.parts) {
|
|
5432
|
+
if (isLost(p) || p.st.stripped) continue;
|
|
5433
|
+
const r = rayPart(o, p, point, d);
|
|
5434
|
+
if (!r) continue;
|
|
5435
|
+
const t0 = Math.max(r.t0, 0);
|
|
5436
|
+
const path = Math.min(r.t1, L) - t0;
|
|
5437
|
+
if (path < shelter.minPath) continue;
|
|
5438
|
+
if (p.st.opening && insideOpening(o, p, toLocal(o.st.position, o.st.rotation, vec.madd(point, d, t0 + path / 2)))) continue;
|
|
5439
|
+
t *= Math.exp(-(p.mat.hpPerKg * p.mat.density * path * (p.mat.damageScale?.shelter ?? 1)) / shelter.k);
|
|
5440
|
+
if (t < 1e-4) return 0;
|
|
5441
|
+
}
|
|
5442
|
+
}
|
|
5443
|
+
for (const im of impls.values()) {
|
|
5444
|
+
if (ignore.has(im.impl.id)) continue;
|
|
5445
|
+
for (const ps of im.impl.describe().parts) {
|
|
5446
|
+
const mat = materials.get(ps.material);
|
|
5447
|
+
if (!mat) continue;
|
|
5448
|
+
const ov = im.poses.get(ps.id);
|
|
5449
|
+
const r = rayPartRaw(im.position, im.rotation, ps, ov?.q ?? quatFromEuler(...ps.rotation ?? [0, 0, 0]), point, d, ov?.pos);
|
|
5450
|
+
if (!r || r.t1 < 0 || r.t0 > L) continue;
|
|
5451
|
+
let path = Math.min(r.t1, L) - Math.max(r.t0, 0);
|
|
5452
|
+
if (ps.thickness !== void 0 && ps.thickness > 0) path = Math.min(path, 2 * ps.thickness);
|
|
5453
|
+
else if (path < shelter.minPath) continue;
|
|
5454
|
+
t *= Math.exp(-(mat.hpPerKg * mat.density * path * (mat.damageScale?.shelter ?? 1)) / shelter.k);
|
|
5455
|
+
if (t < 1e-4) return 0;
|
|
5456
|
+
}
|
|
5457
|
+
}
|
|
5458
|
+
return t;
|
|
5459
|
+
},
|
|
5390
5460
|
explode(point, energy, radius, source, blast) {
|
|
5391
5461
|
blastProbe.partsTested = 0;
|
|
5392
5462
|
blastProbe.partsNear = 0;
|
|
5393
5463
|
return withCollapses(run(() => blastWorld(point, energy, radius, source, blast)));
|
|
5394
5464
|
},
|
|
5395
5465
|
raycast(origin, direction, maxDistance = Infinity) {
|
|
5396
|
-
const r = raycastInternal(origin, direction, maxDistance);
|
|
5466
|
+
const r = raycastInternal(origin, direction, maxDistance, void 0, false, true);
|
|
5397
5467
|
return r ? { object: r.object, part: r.part, point: r.point, normal: r.normal, distance: r.distance } : null;
|
|
5398
5468
|
},
|
|
5399
5469
|
sweepBox(box, direction, distance, options2 = {}) {
|
|
@@ -5411,21 +5481,23 @@ var createDestruction = (options = {}) => {
|
|
|
5411
5481
|
},
|
|
5412
5482
|
shoot(origin, direction, energy, caliber, source, round) {
|
|
5413
5483
|
const extras = typeof round === "number" ? { piercing: round } : round ?? {};
|
|
5414
|
-
return withCollapses(run(() => {
|
|
5484
|
+
return withCollapses(run(withBlow("ballistic", () => {
|
|
5415
5485
|
const results = [];
|
|
5416
5486
|
const d = vec.normalize(direction);
|
|
5417
5487
|
const ignore = /* @__PURE__ */ new Set();
|
|
5418
5488
|
let org = origin;
|
|
5419
5489
|
let E = energy;
|
|
5420
5490
|
for (let i = 0; i < 4 && E > 0; i++) {
|
|
5421
|
-
const rh = raycastInternal(org, d, Infinity, ignore);
|
|
5491
|
+
const rh = raycastInternal(org, d, Infinity, ignore, false, true);
|
|
5422
5492
|
if (!rh) break;
|
|
5423
5493
|
const im = impls.get(rh.object);
|
|
5424
5494
|
if (im) {
|
|
5425
|
-
const
|
|
5495
|
+
const scaled = extras.penetration && E < energy ? { ...extras, penetration: Object.fromEntries(Object.entries(extras.penetration).map(([k, mm]) => [k, mm * (E / energy)])) } : extras;
|
|
5496
|
+
const r = implHit(im, { type: "ballistic", point: rh.point, part: rh.part, normal: rh.normal, direction: d, energy: E, caliber, ...scaled, ...source !== void 0 ? { source } : {} });
|
|
5426
5497
|
r.part = rh.part;
|
|
5427
5498
|
r.point = rh.point;
|
|
5428
|
-
|
|
5499
|
+
const left = r.events.find((e) => e.type === "hole" && e.energyLeft !== void 0);
|
|
5500
|
+
r.exitEnergy = r.penetrated ? left?.energyLeft ?? E * 0.5 : 0;
|
|
5429
5501
|
results.push(r);
|
|
5430
5502
|
ignore.add(`${im.impl.id}\0${rh.part}`);
|
|
5431
5503
|
if (!r.penetrated) break;
|
|
@@ -5444,7 +5516,7 @@ var createDestruction = (options = {}) => {
|
|
|
5444
5516
|
E = out.exitEnergy;
|
|
5445
5517
|
}
|
|
5446
5518
|
return results;
|
|
5447
|
-
}));
|
|
5519
|
+
})));
|
|
5448
5520
|
},
|
|
5449
5521
|
disassemble(objectId, jointId, tool, dt) {
|
|
5450
5522
|
const im = impls.get(objectId);
|
|
@@ -5683,6 +5755,9 @@ var createDestruction = (options = {}) => {
|
|
|
5683
5755
|
return world;
|
|
5684
5756
|
};
|
|
5685
5757
|
|
|
5758
|
+
// src/assemblies.ts
|
|
5759
|
+
import { applyPatches, mergeById, removeIds } from "@adatechnology/game-contracts";
|
|
5760
|
+
|
|
5686
5761
|
// src/data/assemblies.json
|
|
5687
5762
|
var assemblies_default = [
|
|
5688
5763
|
{
|
|
@@ -5748,17 +5823,34 @@ var assemblies_default = [
|
|
|
5748
5823
|
];
|
|
5749
5824
|
|
|
5750
5825
|
// src/assemblies.ts
|
|
5826
|
+
var SHIPPED = structuredClone(assemblies_default);
|
|
5751
5827
|
var ASSEMBLIES = assemblies_default;
|
|
5752
|
-
var
|
|
5753
|
-
const
|
|
5754
|
-
|
|
5755
|
-
|
|
5828
|
+
var assembliesOver = (defs) => {
|
|
5829
|
+
const get = (id) => defs.find((a) => a.id === id);
|
|
5830
|
+
return {
|
|
5831
|
+
list: () => defs,
|
|
5832
|
+
get,
|
|
5833
|
+
register(def) {
|
|
5834
|
+
const at = defs.findIndex((a) => a.id === def.id);
|
|
5835
|
+
if (at >= 0) defs[at] = def;
|
|
5836
|
+
else defs.push(def);
|
|
5837
|
+
},
|
|
5838
|
+
part: (assemblyId, options) => buildAssemblyPart(get(assemblyId), assemblyId, options)
|
|
5839
|
+
};
|
|
5840
|
+
};
|
|
5841
|
+
var createAssemblies = (options = {}) => {
|
|
5842
|
+
const entries = mergeById(SHIPPED.map((def) => structuredClone(def)), (options.packs ?? []).flat());
|
|
5843
|
+
applyPatches(entries, options.patch);
|
|
5844
|
+
removeIds(entries, options.remove);
|
|
5845
|
+
return assembliesOver([...entries.values()]);
|
|
5756
5846
|
};
|
|
5757
|
-
var
|
|
5847
|
+
var defaultSet;
|
|
5848
|
+
var defaultAssemblies = () => defaultSet ?? (defaultSet = assembliesOver(ASSEMBLIES));
|
|
5849
|
+
var registerAssembly = (def) => defaultAssemblies().register(def);
|
|
5850
|
+
var getAssembly = (id) => defaultAssemblies().get(id);
|
|
5758
5851
|
var faceCount = (layer) => layer.faces === "both" ? 2 : 1;
|
|
5759
5852
|
var assemblyDepth = (def) => def.depth ?? def.core.thickness + (def.layers ?? []).reduce((sum, l) => sum + l.thickness * faceCount(l), 0);
|
|
5760
|
-
var
|
|
5761
|
-
const def = getAssembly(assemblyId);
|
|
5853
|
+
var buildAssemblyPart = (def, assemblyId, options) => {
|
|
5762
5854
|
if (!def) throw new Error(`unknown assembly "${assemblyId}"`);
|
|
5763
5855
|
const densityOf = (id) => {
|
|
5764
5856
|
const m = options.materials?.get(id) ?? MATERIALS.find((x) => x.id === id);
|
|
@@ -5785,6 +5877,7 @@ var assemblyPart = (assemblyId, options) => {
|
|
|
5785
5877
|
...options.extra
|
|
5786
5878
|
};
|
|
5787
5879
|
};
|
|
5880
|
+
var assemblyPart = (assemblyId, options) => defaultAssemblies().part(assemblyId, options);
|
|
5788
5881
|
|
|
5789
5882
|
// src/frame.ts
|
|
5790
5883
|
var buildFrame = (o = {}) => {
|
|
@@ -6224,7 +6317,7 @@ var resolveStrings = (locale) => locales[locale ?? "en"] ?? locales.en;
|
|
|
6224
6317
|
import { checkDestructible as check } from "@adatechnology/game-contracts";
|
|
6225
6318
|
import { IMPACT_CONTRACT, checkHit } from "@adatechnology/game-contracts";
|
|
6226
6319
|
var checkDestructible = (impl, options = {}) => {
|
|
6227
|
-
const contractOptions = { materials: [...MATERIALS.map((m) => m.id), ...options.materials ?? []] };
|
|
6320
|
+
const contractOptions = { materials: [...MATERIALS.map((m) => m.id), ...options.materials ?? []], ...options.cost === void 0 ? {} : { cost: options.cost } };
|
|
6228
6321
|
return check(impl, contractOptions);
|
|
6229
6322
|
};
|
|
6230
6323
|
export {
|
|
@@ -6254,9 +6347,11 @@ export {
|
|
|
6254
6347
|
checkDestructible,
|
|
6255
6348
|
checkHit,
|
|
6256
6349
|
crackingMoment,
|
|
6350
|
+
createAssemblies,
|
|
6257
6351
|
createDestruction,
|
|
6258
6352
|
damperAmplification,
|
|
6259
6353
|
damperTuning,
|
|
6354
|
+
defaultAssemblies,
|
|
6260
6355
|
elasticEnergy,
|
|
6261
6356
|
explosivePart,
|
|
6262
6357
|
exposureOf,
|