@adatechnology/game-destruction 0.13.2 → 0.14.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 +36 -7
- package/dist/index.global.js +179 -15
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +54 -15
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -383,6 +383,11 @@ helpers `vec`, `quat`, `quatFromEuler`, `rotateVec`, `toLocal`, `toWorld`, the l
|
|
|
383
383
|
The locale table has `en` and `pt-BR` strings for material names, part statuses, joint kinds, tools, damage types, event labels and fracture styles:
|
|
384
384
|
`resolveStrings('pt-BR').materialNames.glass === 'vidro'`. Unknown locales fall back to `en`.
|
|
385
385
|
|
|
386
|
+
## Assemblies by instance
|
|
387
|
+
|
|
388
|
+
`createAssemblies({ packs, patch, remove })` makes a set of assemblies of its own: the built-in ones plus `packs`. `packs` is a list of lists of `AssemblyDef` (`[[wallDef, doorDef], [extraDef]]`); a def with the id of a built-in replaces it.
|
|
389
|
+
`patch` merges fields by assembly id, `remove` lists ids to take out. The global `ASSEMBLIES`, `registerAssembly` and the rest are deprecated delegates of `defaultAssemblies()`.
|
|
390
|
+
|
|
386
391
|
## Português
|
|
387
392
|
|
|
388
393
|
Modelo de destruição independente de engine. Um objeto é um conjunto de peças (caixa, cilindro ou esfera com um material) unidas por juntas. O
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Vec3, Quat, MaterialId, FractureStyle, DamageType, DebrisKind, DestructionEvent, StructureRole, SoilProfile, WindExposure, IgnitionRules, BlastOptions, DestructibleSpec, ObjectState, DestructibleImpl, Hit, HitResult, RayHit, BallisticExtras, ToolKind, JointState, PartState, DestructionEventType, ConfinementOptions, FragmentHitOptions, ShelterOptions, ExplosionChain, PartSpec, JointKind, JointSpec, PartShape, SurfaceLayer, PartUnits, Reinforcement, PartBreach, PileSpec, PartStatus } from '@adatechnology/game-contracts';
|
|
1
|
+
import { Vec3, Quat, MaterialId, FractureStyle, DamageType, DebrisKind, DestructionEvent, StructureRole, SoilProfile, WindExposure, IgnitionRules, BlastOptions, DestructibleSpec, ObjectState, DestructibleImpl, Hit, HitResult, RayHit, BallisticExtras, ToolKind, JointState, PartState, DestructionEventType, ConfinementOptions, FragmentHitOptions, ShelterOptions, ExplosionChain, PartSpec, JointKind, JointSpec, PartShape, SurfaceLayer, PartUnits, Reinforcement, PartBreach, DeepPartial, PileSpec, PartStatus, CostOptions } from '@adatechnology/game-contracts';
|
|
2
2
|
export { BallisticExtras, BlastOptions, BlastReport, ChainDelay, ConfinementOptions, Crack, DamageStage, DamageType, DebrisKind, Dent, DestructibleImpl, DestructibleSpec, DestructionEvent, DestructionEventType, ExplosionChain, FluidKind, FractureStyle, Fragment, FragmentHitOptions, FragmentMark, Hit, HitIgnition, HitResult, Hole, IMPACT_CONTRACT, ImpactContract, JointKind, JointSpec, JointState, MaterialId, ObjectState, PartBreach, PartShape, PartSpec, PartState, PartStatus, PartUnits, PileSpec, Quat, RayHit, Reinforcement, ShelterOptions, SoilLayer, SoilProfile, SoilState, StructureRole, SurfaceLayer, TensionRebar, ToolKind, TunedMassDamper, Vec3, WindExposure, WindState, checkHit } from '@adatechnology/game-contracts';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -324,6 +324,11 @@ interface DestructionOptions {
|
|
|
324
324
|
maxDents?: number;
|
|
325
325
|
/** Maximum holes kept per part (default 32). */
|
|
326
326
|
maxHoles?: number;
|
|
327
|
+
/**
|
|
328
|
+
* Most primed explosives that go off in one `update` (default: no cap). The rest wait, ordered by due time, then older object, then part
|
|
329
|
+
* order, and go off in the next updates, so a long chain spreads over steps by count and not by the speed of the machine.
|
|
330
|
+
*/
|
|
331
|
+
chainLinksPerUpdate?: number;
|
|
327
332
|
/** Distance at which a burning part heats parts of other objects, in metres (default 0.6). */
|
|
328
333
|
fireSpread?: number;
|
|
329
334
|
/**
|
|
@@ -711,16 +716,38 @@ interface AssemblyPartOptions {
|
|
|
711
716
|
/** Materials to read densities from (default the built-in `MATERIALS`). */
|
|
712
717
|
materials?: ReadonlyMap<MaterialId, MaterialDef>;
|
|
713
718
|
}
|
|
714
|
-
/**
|
|
719
|
+
/**
|
|
720
|
+
* Built-in assemblies; `registerAssembly` adds to this list.
|
|
721
|
+
* @deprecated the list every page shares. Use `createAssemblies({ packs, patch, remove })`, or `defaultAssemblies()` for this one.
|
|
722
|
+
*/
|
|
715
723
|
declare const ASSEMBLIES: AssemblyDef[];
|
|
724
|
+
interface AssembliesOptions {
|
|
725
|
+
/** Assemblies added to the built-in ones; one with the id of a built-in replaces it. */
|
|
726
|
+
readonly packs?: readonly (readonly AssemblyDef[])[];
|
|
727
|
+
/** Changes by id, merged field by field over what is there. */
|
|
728
|
+
readonly patch?: Readonly<Record<string, DeepPartial<AssemblyDef>>>;
|
|
729
|
+
/** Ids taken out. */
|
|
730
|
+
readonly remove?: readonly string[];
|
|
731
|
+
}
|
|
732
|
+
interface Assemblies {
|
|
733
|
+
list(): readonly AssemblyDef[];
|
|
734
|
+
get(id: string): AssemblyDef | undefined;
|
|
735
|
+
/** Adds an assembly, or replaces the one with the same id. */
|
|
736
|
+
register(def: AssemblyDef): void;
|
|
737
|
+
/** The wall as a `PartSpec`; throws for an id this set does not have. */
|
|
738
|
+
part(assemblyId: string, options: AssemblyPartOptions): PartSpec;
|
|
739
|
+
}
|
|
740
|
+
/** A set of assemblies of its own: the built-in ones (copied) plus `packs`, `patch` and `remove`. Nothing is shared with any other set on the page. */
|
|
741
|
+
declare const createAssemblies: (options?: AssembliesOptions) => Assemblies;
|
|
742
|
+
/** The set behind `ASSEMBLIES`, `registerAssembly`, `getAssembly` and `assemblyPart`, created on first use. */
|
|
743
|
+
declare const defaultAssemblies: () => Assemblies;
|
|
744
|
+
/** @deprecated use `createAssemblies(...).register`. */
|
|
716
745
|
declare const registerAssembly: (def: AssemblyDef) => void;
|
|
746
|
+
/** @deprecated use `createAssemblies(...).get`. */
|
|
717
747
|
declare const getAssembly: (id: string) => AssemblyDef | undefined;
|
|
718
748
|
/** Physical depth of the wall in metres. */
|
|
719
749
|
declare const assemblyDepth: (def: AssemblyDef) => number;
|
|
720
|
-
/**
|
|
721
|
-
* The wall as a box `[width, height, depth]` (thin along local z) with the assembly's layers, units, rebar and breach. Mass is the core (times `fill`)
|
|
722
|
-
* plus the coats; `thickness` is the core's, so each coat adds its own `penetration x thickness` to what a bullet must cross.
|
|
723
|
-
*/
|
|
750
|
+
/** @deprecated use `createAssemblies(...).part`. */
|
|
724
751
|
declare const assemblyPart: (assemblyId: string, options: AssemblyPartOptions) => PartSpec;
|
|
725
752
|
|
|
726
753
|
interface FrameOptions {
|
|
@@ -1086,6 +1113,8 @@ declare const resolveStrings: (locale: string | undefined) => DestructionStrings
|
|
|
1086
1113
|
interface CheckOptions {
|
|
1087
1114
|
/** Ids of custom materials the impl uses besides the built-in `MATERIALS`. */
|
|
1088
1115
|
materials?: string[];
|
|
1116
|
+
/** Opt-in cost measurement of `state()` and `describe()` (D8). */
|
|
1117
|
+
cost?: boolean | CostOptions;
|
|
1089
1118
|
}
|
|
1090
1119
|
/**
|
|
1091
1120
|
* `checkDestructible` of `@adatechnology/game-contracts`, with the built-in `MATERIALS` (plus `options.materials`) as the known material ids.
|
|
@@ -1361,4 +1390,4 @@ declare const tensionCapacity: (dims: Vec3, o: {
|
|
|
1361
1390
|
tensileMPa?: number;
|
|
1362
1391
|
}) => number;
|
|
1363
1392
|
|
|
1364
|
-
export { ASSEMBLIES, type AddOptions, type AssemblyDef, type AssemblyPartOptions, type BearingWallOptions, type BendGeometry, type BendSection, CONFINEMENT_DEFAULTS, type ChainTrigger, type CheckOptions, type DestructionLocale, type DestructionOptions, type DestructionSnapshot, type DestructionStrings, type DestructionWorld, type ExplosivePartOptions, FIRE_PRIME_C, FLEXURE_DEFAULTS, FRAGMENT_HIT_DEFAULTS, type FlexureOptions, type FoundationSolve, type FrameOptions, GRAVITY, type Gust, JOINT_BY_MATERIALS, JOINT_DEFAULTS, MASONRY_DEFAULTS, MATERIALS, type MasonryOptions, type MaterialDef, type MaterialHit, type MaterialStrength, type MaterialThermal, type ObjectRuntime, type PartRuntime, type ResolvedWind, SHELTER_DEFAULTS, SOILS, SOIL_DEFAULTS, type SectionMoments, type SizeStructureOptions, type SoilDef, type SoilKind, type SoilOptions, type SoilSpring, type SwayState, type SwaySystem, type TensionSteel, WIND_DEFAULTS, WIND_TERRAIN, type WallFrameSolution, type WindAnalysis, type WindCase, type WindOptions, type WindPartInput, type WindTerrainDef, type WorldExplosive, analyzeWind, assemblyDepth, assemblyPart, bearingWallThickness, bendGeometry, blastImpulse, buildFrame, checkDestructible, crackingMoment, createDestruction, damperAmplification, damperTuning, elasticEnergy, explosivePart, exposureOf, footingArea, footingSoil, fragility, getAssembly, guessMaterial, gustAt, heightFactor, impulseEnergy, inferJoints, layersBetween, locales, makeGust, meanHeightFactor, momentNodes, momentOfEnergy, partCapacity, partMass, partThickness, partVolume, pileCapacity, pileLength, pileStiffness, profileOf, quat, quatFromEuler, registerAssembly, resolveStrings, resolveWind, rotateVec, sectionMoments, shapeAt, shearNodes, sizeRebar, sizeStructure, slendernessFactor, soilAt, solveFoundation, solveWallFrame, spanMoment, spanOf, steelMoment, stepSway, stiffnessCentre, subgradeModulus, tBeamInertia, tensionCapacity, tensionSteel, toLocal, toWorld, turbulenceIntensity, vec, windClass, windPressure };
|
|
1393
|
+
export { ASSEMBLIES, type AddOptions, type Assemblies, type AssembliesOptions, type AssemblyDef, type AssemblyPartOptions, type BearingWallOptions, type BendGeometry, type BendSection, CONFINEMENT_DEFAULTS, type ChainTrigger, type CheckOptions, type DestructionLocale, type DestructionOptions, type DestructionSnapshot, type DestructionStrings, type DestructionWorld, type ExplosivePartOptions, FIRE_PRIME_C, FLEXURE_DEFAULTS, FRAGMENT_HIT_DEFAULTS, type FlexureOptions, type FoundationSolve, type FrameOptions, GRAVITY, type Gust, JOINT_BY_MATERIALS, JOINT_DEFAULTS, MASONRY_DEFAULTS, MATERIALS, type MasonryOptions, type MaterialDef, type MaterialHit, type MaterialStrength, type MaterialThermal, type ObjectRuntime, type PartRuntime, type ResolvedWind, SHELTER_DEFAULTS, SOILS, SOIL_DEFAULTS, type SectionMoments, type SizeStructureOptions, type SoilDef, type SoilKind, type SoilOptions, type SoilSpring, type SwayState, type SwaySystem, type TensionSteel, WIND_DEFAULTS, WIND_TERRAIN, type WallFrameSolution, type WindAnalysis, type WindCase, type WindOptions, type WindPartInput, type WindTerrainDef, type WorldExplosive, analyzeWind, assemblyDepth, assemblyPart, bearingWallThickness, bendGeometry, blastImpulse, buildFrame, checkDestructible, crackingMoment, createAssemblies, createDestruction, damperAmplification, damperTuning, defaultAssemblies, elasticEnergy, explosivePart, exposureOf, footingArea, footingSoil, fragility, getAssembly, guessMaterial, gustAt, heightFactor, impulseEnergy, inferJoints, layersBetween, locales, makeGust, meanHeightFactor, momentNodes, momentOfEnergy, partCapacity, partMass, partThickness, partVolume, pileCapacity, pileLength, pileStiffness, profileOf, quat, quatFromEuler, registerAssembly, resolveStrings, resolveWind, rotateVec, sectionMoments, shapeAt, shearNodes, sizeRebar, sizeStructure, slendernessFactor, soilAt, solveFoundation, solveWallFrame, spanMoment, spanOf, steelMoment, stepSway, stiffnessCentre, subgradeModulus, tBeamInertia, tensionCapacity, tensionSteel, toLocal, toWorld, turbulenceIntensity, vec, windClass, windPressure };
|
package/dist/index.global.js
CHANGED
|
@@ -47,9 +47,11 @@ var GameDestruction = (() => {
|
|
|
47
47
|
checkDestructible: () => checkDestructible2,
|
|
48
48
|
checkHit: () => checkHit,
|
|
49
49
|
crackingMoment: () => crackingMoment,
|
|
50
|
+
createAssemblies: () => createAssemblies,
|
|
50
51
|
createDestruction: () => createDestruction,
|
|
51
52
|
damperAmplification: () => damperAmplification,
|
|
52
53
|
damperTuning: () => damperTuning,
|
|
54
|
+
defaultAssemblies: () => defaultAssemblies,
|
|
53
55
|
elasticEnergy: () => elasticEnergy,
|
|
54
56
|
explosivePart: () => explosivePart,
|
|
55
57
|
exposureOf: () => exposureOf,
|
|
@@ -2780,6 +2782,28 @@ var GameDestruction = (() => {
|
|
|
2780
2782
|
};
|
|
2781
2783
|
|
|
2782
2784
|
// ../game-contracts/dist/index.js
|
|
2785
|
+
var DEFAULT_COST_READS = 1e4;
|
|
2786
|
+
var DEFAULT_COST_CEILING_MS = 50;
|
|
2787
|
+
var DEFAULT_COST_ALLOCATION_BYTES = 1024 * 1024;
|
|
2788
|
+
var heapUsedBytes = () => {
|
|
2789
|
+
const nodeProcess = globalThis.process;
|
|
2790
|
+
return nodeProcess?.memoryUsage?.().heapUsed;
|
|
2791
|
+
};
|
|
2792
|
+
var checkReadCost = ({ name, read, options, problems }) => {
|
|
2793
|
+
const reads = options.reads ?? DEFAULT_COST_READS;
|
|
2794
|
+
const ceilingMs = options.ceilingMs ?? DEFAULT_COST_CEILING_MS;
|
|
2795
|
+
const allocationBytes = options.allocationBytes ?? DEFAULT_COST_ALLOCATION_BYTES;
|
|
2796
|
+
if (read() !== read()) problems.push(`${name}() returns a new object on each read: cache it between changes (cost contract)`);
|
|
2797
|
+
for (let i = 0; i < reads; i++) read();
|
|
2798
|
+
const heapBefore = heapUsedBytes();
|
|
2799
|
+
const started = performance.now();
|
|
2800
|
+
for (let i = 0; i < reads; i++) read();
|
|
2801
|
+
const elapsedMs = performance.now() - started;
|
|
2802
|
+
const heapAfter = heapUsedBytes();
|
|
2803
|
+
if (elapsedMs > ceilingMs) problems.push(`${name}() took ${elapsedMs.toFixed(1)} ms for ${reads} reads, over the ${ceilingMs} ms ceiling (cost contract)`);
|
|
2804
|
+
if (heapBefore !== void 0 && heapAfter !== void 0 && heapAfter - heapBefore > allocationBytes)
|
|
2805
|
+
problems.push(`${name}() grew the heap by ${heapAfter - heapBefore} bytes over ${reads} reads, over the ${allocationBytes} byte ceiling (cost contract)`);
|
|
2806
|
+
};
|
|
2783
2807
|
var IMPACT_CONTRACT = {
|
|
2784
2808
|
ballistic: { required: ["type", "point", "direction", "energy", "caliber"], optional: ["space", "source"], note: "bullets and pellets: joules and diameter in millimetres" },
|
|
2785
2809
|
blunt: { required: ["type", "point", "energy"], optional: ["direction", "radius", "space", "source"], note: "contact radius in metres (default 3 cm)" },
|
|
@@ -2885,6 +2909,15 @@ var GameDestruction = (() => {
|
|
|
2885
2909
|
} catch (e) {
|
|
2886
2910
|
problems.push(`reset() threw: ${String(e)}`);
|
|
2887
2911
|
}
|
|
2912
|
+
if (options.cost) {
|
|
2913
|
+
const cost = options.cost === true ? {} : options.cost;
|
|
2914
|
+
try {
|
|
2915
|
+
checkReadCost({ name: "state", read: () => impl.state(), options: cost, problems });
|
|
2916
|
+
checkReadCost({ name: "describe", read: () => impl.describe(), options: cost, problems });
|
|
2917
|
+
} catch (e) {
|
|
2918
|
+
problems.push(`cost measurement threw: ${String(e)}`);
|
|
2919
|
+
}
|
|
2920
|
+
}
|
|
2888
2921
|
return { ok: problems.length === 0, problems };
|
|
2889
2922
|
};
|
|
2890
2923
|
var DEFAULT_IGNITION_RULES = {
|
|
@@ -2930,6 +2963,103 @@ var GameDestruction = (() => {
|
|
|
2930
2963
|
const flame = flameBase * (1 - rules.flameFillInfluence * (1 - k));
|
|
2931
2964
|
return 1 - (1 - Math.min(1, Math.max(0, spark))) * (1 - Math.min(1, Math.max(0, flame)));
|
|
2932
2965
|
};
|
|
2966
|
+
var DEFERRED_QUEUE_ID = {
|
|
2967
|
+
DESTRUCTION_EVENTS: "destruction.events",
|
|
2968
|
+
BREACH_PAINT: "floorplan.breach-paint",
|
|
2969
|
+
AUDIO_VOICES: "audio.voices",
|
|
2970
|
+
VEHICLE_CREASE: "vehicles.crease"
|
|
2971
|
+
};
|
|
2972
|
+
var DEFERRED_PRIORITY = {
|
|
2973
|
+
[DEFERRED_QUEUE_ID.DESTRUCTION_EVENTS]: { priority: 300, phase: "present" },
|
|
2974
|
+
[DEFERRED_QUEUE_ID.BREACH_PAINT]: { priority: 250, phase: "present" },
|
|
2975
|
+
[DEFERRED_QUEUE_ID.AUDIO_VOICES]: { priority: 200, phase: "idle", reserveMs: 1 },
|
|
2976
|
+
[DEFERRED_QUEUE_ID.VEHICLE_CREASE]: { priority: 100, phase: "idle" }
|
|
2977
|
+
};
|
|
2978
|
+
var WARNED_KEY = /* @__PURE__ */ Symbol.for("@adatechnology/game-contracts.warned");
|
|
2979
|
+
var warnedKeys = () => {
|
|
2980
|
+
const holder = globalThis;
|
|
2981
|
+
return holder[WARNED_KEY] ?? (holder[WARNED_KEY] = /* @__PURE__ */ new Set());
|
|
2982
|
+
};
|
|
2983
|
+
var isProduction = () => {
|
|
2984
|
+
try {
|
|
2985
|
+
return process.env.NODE_ENV === "production";
|
|
2986
|
+
} catch {
|
|
2987
|
+
return false;
|
|
2988
|
+
}
|
|
2989
|
+
};
|
|
2990
|
+
var isQuiet = () => globalThis.__GAME_KIT_QUIET__ === true;
|
|
2991
|
+
var warnOnce = (key, message) => {
|
|
2992
|
+
if (isQuiet() || isProduction()) return;
|
|
2993
|
+
const seen = warnedKeys();
|
|
2994
|
+
if (seen.has(key)) return;
|
|
2995
|
+
seen.add(key);
|
|
2996
|
+
console.warn(`[game-kit] ${message}`);
|
|
2997
|
+
};
|
|
2998
|
+
var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
2999
|
+
var isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
|
|
3000
|
+
var deepMerge = (base, patch) => {
|
|
3001
|
+
if (!patch) return base;
|
|
3002
|
+
const result = { ...base };
|
|
3003
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
3004
|
+
if (value === void 0 || UNSAFE_KEYS.has(key)) continue;
|
|
3005
|
+
const current = result[key];
|
|
3006
|
+
result[key] = isPlainObject(current) && isPlainObject(value) ? deepMerge(current, value) : value;
|
|
3007
|
+
}
|
|
3008
|
+
return result;
|
|
3009
|
+
};
|
|
3010
|
+
var mergeById = (shipped, extra) => {
|
|
3011
|
+
const entries = /* @__PURE__ */ new Map();
|
|
3012
|
+
for (const entry of [...shipped, ...extra ?? []]) entries.set(entry.id, entry);
|
|
3013
|
+
return entries;
|
|
3014
|
+
};
|
|
3015
|
+
var applyPatches = (entries, patches) => {
|
|
3016
|
+
for (const [id, patch] of Object.entries(patches ?? {})) {
|
|
3017
|
+
const entry = entries.get(id);
|
|
3018
|
+
if (entry) entries.set(id, deepMerge(entry, patch));
|
|
3019
|
+
else warnOnce(`registry.patch.${id}`, `patch for "${id}" ignored: no entry has that id`);
|
|
3020
|
+
}
|
|
3021
|
+
};
|
|
3022
|
+
var removeIds = (entries, ids) => {
|
|
3023
|
+
for (const id of ids ?? []) {
|
|
3024
|
+
if (!entries.delete(id)) warnOnce(`registry.remove.${id}`, `remove of "${id}" ignored: no entry has that id`);
|
|
3025
|
+
}
|
|
3026
|
+
};
|
|
3027
|
+
var SURFACE_IDS = ["concrete", "asphalt", "wood", "tile", "dirt", "grass", "gravel", "sand", "metal", "water", "glass", "carpet"];
|
|
3028
|
+
var GAIT_IDS = ["walk", "run"];
|
|
3029
|
+
var LANDING_IDS = ["light", "heavy"];
|
|
3030
|
+
var BODY_SOUND_IDS = [
|
|
3031
|
+
"jump",
|
|
3032
|
+
"cloth_rustle",
|
|
3033
|
+
"body_fall",
|
|
3034
|
+
"fall_damage",
|
|
3035
|
+
"player_hurt",
|
|
3036
|
+
"player_breath_run",
|
|
3037
|
+
"player_death",
|
|
3038
|
+
"bite",
|
|
3039
|
+
"grab",
|
|
3040
|
+
"punch_swing",
|
|
3041
|
+
"punch_hit_body",
|
|
3042
|
+
"punch_hit_face",
|
|
3043
|
+
"punch_hit_object",
|
|
3044
|
+
"kick_swing",
|
|
3045
|
+
"kick_hit",
|
|
3046
|
+
"kick_hit_object",
|
|
3047
|
+
"shove_two_hands",
|
|
3048
|
+
"knife_swing",
|
|
3049
|
+
"knife_stab",
|
|
3050
|
+
"knife_slash",
|
|
3051
|
+
"knife_hit_object",
|
|
3052
|
+
"blunt_swing",
|
|
3053
|
+
"blunt_hit",
|
|
3054
|
+
"blunt_hit_object",
|
|
3055
|
+
"axe_swing",
|
|
3056
|
+
"axe_chop",
|
|
3057
|
+
"axe_hit_object"
|
|
3058
|
+
];
|
|
3059
|
+
var footstepSoundId = (surface, gait) => `footstep_${surface}_${gait}`;
|
|
3060
|
+
var FOOTSTEP_SOUND_IDS = SURFACE_IDS.flatMap((surface) => GAIT_IDS.map((gait) => footstepSoundId(surface, gait)));
|
|
3061
|
+
var LAND_SOUND_IDS = SURFACE_IDS.flatMap((surface) => LANDING_IDS.map((landing) => `land_${surface}_${landing}`));
|
|
3062
|
+
var BODY_FOLEY_IDS = [...FOOTSTEP_SOUND_IDS, ...LAND_SOUND_IDS, ...BODY_SOUND_IDS];
|
|
2933
3063
|
|
|
2934
3064
|
// src/world.ts
|
|
2935
3065
|
var THIN_SHEET_DISHING = 5e-3;
|
|
@@ -3057,6 +3187,7 @@ var GameDestruction = (() => {
|
|
|
3057
3187
|
const ignitionRules = resolveIgnitionRules(options.ignition);
|
|
3058
3188
|
const breachBlastFactor = options.breach?.blastFactor ?? BREACH_BLAST_FACTOR;
|
|
3059
3189
|
const chipEnergy = options.breach?.chipEnergy ?? CHIP_ENERGY;
|
|
3190
|
+
const chainLinkCap = options.chainLinksPerUpdate !== void 0 && options.chainLinksPerUpdate >= 1 ? Math.floor(options.chainLinksPerUpdate) : Infinity;
|
|
3060
3191
|
const rng = createRng(options.seed ?? 1);
|
|
3061
3192
|
const rnd = () => rng.next();
|
|
3062
3193
|
let time = 0;
|
|
@@ -4004,7 +4135,7 @@ var GameDestruction = (() => {
|
|
|
4004
4135
|
if (disc < 0) return true;
|
|
4005
4136
|
return -b - Math.sqrt(disc) > maxDist;
|
|
4006
4137
|
};
|
|
4007
|
-
const raycastInternal = (origin, dir, maxDist, ignore, worldOnly = false) => {
|
|
4138
|
+
const raycastInternal = (origin, dir, maxDist, ignore, worldOnly = false, precise = false) => {
|
|
4008
4139
|
const d = vec.normalize(dir);
|
|
4009
4140
|
let best = null;
|
|
4010
4141
|
for (const o of objects.values()) {
|
|
@@ -4019,13 +4150,25 @@ var GameDestruction = (() => {
|
|
|
4019
4150
|
}
|
|
4020
4151
|
}
|
|
4021
4152
|
for (const im of worldOnly ? [] : impls.values()) {
|
|
4153
|
+
let boxHit = null;
|
|
4022
4154
|
for (const ps of im.impl.describe().parts) {
|
|
4023
4155
|
if (ignore?.has(`${im.impl.id}\0${ps.id}`)) continue;
|
|
4024
4156
|
const ov = im.poses.get(ps.id);
|
|
4025
4157
|
const r = rayPartRaw(im.position, im.rotation, ps, ov?.q ?? quatFromEuler(...ps.rotation ?? [0, 0, 0]), origin, d, ov?.pos);
|
|
4026
|
-
if (!r || r.
|
|
4027
|
-
if (
|
|
4158
|
+
if (!r || r.t1 < 0 || r.t0 > maxDist) continue;
|
|
4159
|
+
if (r.t0 < 0) {
|
|
4160
|
+
if (precise && im.impl.surfaceRay) boxHit = boxHit ?? { object: im.impl.id, part: ps.id, point: origin, normal: r.n, distance: 0, pathLen: r.t1 };
|
|
4161
|
+
continue;
|
|
4162
|
+
}
|
|
4163
|
+
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 };
|
|
4028
4164
|
}
|
|
4165
|
+
if (!boxHit) continue;
|
|
4166
|
+
if (precise && im.impl.surfaceRay) {
|
|
4167
|
+
const far = best ? Math.min(maxDist, best.distance) : maxDist;
|
|
4168
|
+
const implId = im.impl.id;
|
|
4169
|
+
const s = im.impl.surfaceRay({ origin, direction: d, maxDistance: far, ...ignore ? { ignored: (part) => ignore.has(`${implId}\0${part}`) } : {} });
|
|
4170
|
+
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 };
|
|
4171
|
+
} else if (!best || boxHit.distance < best.distance) best = boxHit;
|
|
4029
4172
|
}
|
|
4030
4173
|
return best;
|
|
4031
4174
|
};
|
|
@@ -5509,7 +5652,9 @@ var GameDestruction = (() => {
|
|
|
5509
5652
|
};
|
|
5510
5653
|
const detonatePrimed = (until) => {
|
|
5511
5654
|
const end = time;
|
|
5512
|
-
|
|
5655
|
+
let fired = 0;
|
|
5656
|
+
for (let next = nextPrimed(until); next && fired < chainLinkCap; next = nextPrimed(until)) {
|
|
5657
|
+
fired++;
|
|
5513
5658
|
primed.delete(next.p);
|
|
5514
5659
|
time = Math.max(0, Math.min(end, next.p.rt.chainDue));
|
|
5515
5660
|
next.p.rt.chainDue = void 0;
|
|
@@ -5579,6 +5724,7 @@ var GameDestruction = (() => {
|
|
|
5579
5724
|
updateBound(o);
|
|
5580
5725
|
},
|
|
5581
5726
|
remove(id) {
|
|
5727
|
+
impls.get(id)?.impl.dispose?.();
|
|
5582
5728
|
objects.delete(id);
|
|
5583
5729
|
impls.delete(id);
|
|
5584
5730
|
},
|
|
@@ -5654,7 +5800,7 @@ var GameDestruction = (() => {
|
|
|
5654
5800
|
return withCollapses(run(() => blastWorld(point, energy, radius, source, blast)));
|
|
5655
5801
|
},
|
|
5656
5802
|
raycast(origin, direction, maxDistance = Infinity) {
|
|
5657
|
-
const r = raycastInternal(origin, direction, maxDistance);
|
|
5803
|
+
const r = raycastInternal(origin, direction, maxDistance, void 0, false, true);
|
|
5658
5804
|
return r ? { object: r.object, part: r.part, point: r.point, normal: r.normal, distance: r.distance } : null;
|
|
5659
5805
|
},
|
|
5660
5806
|
sweepBox(box, direction, distance, options2 = {}) {
|
|
@@ -5679,11 +5825,11 @@ var GameDestruction = (() => {
|
|
|
5679
5825
|
let org = origin;
|
|
5680
5826
|
let E = energy;
|
|
5681
5827
|
for (let i = 0; i < 4 && E > 0; i++) {
|
|
5682
|
-
const rh = raycastInternal(org, d, Infinity, ignore);
|
|
5828
|
+
const rh = raycastInternal(org, d, Infinity, ignore, false, true);
|
|
5683
5829
|
if (!rh) break;
|
|
5684
5830
|
const im = impls.get(rh.object);
|
|
5685
5831
|
if (im) {
|
|
5686
|
-
const r = implHit(im, { type: "ballistic", point: rh.point, direction: d, energy: E, caliber, ...extras, ...source !== void 0 ? { source } : {} });
|
|
5832
|
+
const r = implHit(im, { type: "ballistic", point: rh.point, part: rh.part, normal: rh.normal, direction: d, energy: E, caliber, ...extras, ...source !== void 0 ? { source } : {} });
|
|
5687
5833
|
r.part = rh.part;
|
|
5688
5834
|
r.point = rh.point;
|
|
5689
5835
|
r.exitEnergy = r.penetrated ? E * 0.5 : 0;
|
|
@@ -6009,17 +6155,34 @@ var GameDestruction = (() => {
|
|
|
6009
6155
|
];
|
|
6010
6156
|
|
|
6011
6157
|
// src/assemblies.ts
|
|
6158
|
+
var SHIPPED = structuredClone(assemblies_default);
|
|
6012
6159
|
var ASSEMBLIES = assemblies_default;
|
|
6013
|
-
var
|
|
6014
|
-
const
|
|
6015
|
-
|
|
6016
|
-
|
|
6160
|
+
var assembliesOver = (defs) => {
|
|
6161
|
+
const get = (id) => defs.find((a) => a.id === id);
|
|
6162
|
+
return {
|
|
6163
|
+
list: () => defs,
|
|
6164
|
+
get,
|
|
6165
|
+
register(def) {
|
|
6166
|
+
const at = defs.findIndex((a) => a.id === def.id);
|
|
6167
|
+
if (at >= 0) defs[at] = def;
|
|
6168
|
+
else defs.push(def);
|
|
6169
|
+
},
|
|
6170
|
+
part: (assemblyId, options) => buildAssemblyPart(get(assemblyId), assemblyId, options)
|
|
6171
|
+
};
|
|
6172
|
+
};
|
|
6173
|
+
var createAssemblies = (options = {}) => {
|
|
6174
|
+
const entries = mergeById(SHIPPED.map((def) => structuredClone(def)), (options.packs ?? []).flat());
|
|
6175
|
+
applyPatches(entries, options.patch);
|
|
6176
|
+
removeIds(entries, options.remove);
|
|
6177
|
+
return assembliesOver([...entries.values()]);
|
|
6017
6178
|
};
|
|
6018
|
-
var
|
|
6179
|
+
var defaultSet;
|
|
6180
|
+
var defaultAssemblies = () => defaultSet ?? (defaultSet = assembliesOver(ASSEMBLIES));
|
|
6181
|
+
var registerAssembly = (def) => defaultAssemblies().register(def);
|
|
6182
|
+
var getAssembly = (id) => defaultAssemblies().get(id);
|
|
6019
6183
|
var faceCount = (layer) => layer.faces === "both" ? 2 : 1;
|
|
6020
6184
|
var assemblyDepth = (def) => def.depth ?? def.core.thickness + (def.layers ?? []).reduce((sum, l) => sum + l.thickness * faceCount(l), 0);
|
|
6021
|
-
var
|
|
6022
|
-
const def = getAssembly(assemblyId);
|
|
6185
|
+
var buildAssemblyPart = (def, assemblyId, options) => {
|
|
6023
6186
|
if (!def) throw new Error(`unknown assembly "${assemblyId}"`);
|
|
6024
6187
|
const densityOf = (id) => {
|
|
6025
6188
|
const m = options.materials?.get(id) ?? MATERIALS.find((x) => x.id === id);
|
|
@@ -6046,6 +6209,7 @@ var GameDestruction = (() => {
|
|
|
6046
6209
|
...options.extra
|
|
6047
6210
|
};
|
|
6048
6211
|
};
|
|
6212
|
+
var assemblyPart = (assemblyId, options) => defaultAssemblies().part(assemblyId, options);
|
|
6049
6213
|
|
|
6050
6214
|
// src/frame.ts
|
|
6051
6215
|
var buildFrame = (o = {}) => {
|
|
@@ -6483,7 +6647,7 @@ var GameDestruction = (() => {
|
|
|
6483
6647
|
|
|
6484
6648
|
// src/contracts.ts
|
|
6485
6649
|
var checkDestructible2 = (impl, options = {}) => {
|
|
6486
|
-
const contractOptions = { materials: [...MATERIALS.map((m) => m.id), ...options.materials ?? []] };
|
|
6650
|
+
const contractOptions = { materials: [...MATERIALS.map((m) => m.id), ...options.materials ?? []], ...options.cost === void 0 ? {} : { cost: options.cost } };
|
|
6487
6651
|
return checkDestructible(impl, contractOptions);
|
|
6488
6652
|
};
|
|
6489
6653
|
return __toCommonJS(index_exports);
|