@adatechnology/game-destruction 0.4.1 → 0.5.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 +32 -3
- package/dist/index.d.ts +72 -6
- package/dist/index.global.js +490 -22
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +490 -22
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -146,11 +146,40 @@ without any `structure` behave exactly as before.
|
|
|
146
146
|
`splitGroup`.
|
|
147
147
|
- `buildFrame({ spanX, spanZ, columnsX, columnsZ, height, floors, walls, roof, columnCapacity, ... })` returns a test structure: columns on
|
|
148
148
|
foundations (`rebar`), beams, a slab per floor, optional brick walls (`mortar`) with a door opening, and a roof that rests (`resting`) on the top beams.
|
|
149
|
-
- `sizeStructure(spec, { safety?, redundancy? })` returns a copy of the spec with `structure.capacity` set from the loads the world itself solves
|
|
149
|
+
- `sizeStructure(spec, { safety?, redundancy?, redundancyRoles?, safetyByRole? })` returns a copy of the spec with `structure.capacity` set from the loads the world itself solves
|
|
150
150
|
for the intact spec, so every structural part rests at stress `safety` (default 0.65). With `redundancy` (e.g. 0.97) the capacities are also
|
|
151
151
|
raised where needed so that losing any single `column` keeps every other part at or below that stress: the structure stands with one column
|
|
152
152
|
gone and, without help, falls with two neighbours gone. Raw material capacities are rarely a sensible design (a 54 t roof on 20 cm columns is
|
|
153
153
|
already over 1 at rest); size the structure instead of hand-tuning. Parts without `structure` or with role `none` are untouched.
|
|
154
|
+
`redundancyRoles` (default `['column']`) says which parts the N-1 check removes one at a time: a house uses `['column', 'wall']` so it also
|
|
155
|
+
stands with a bearing wall gone. `safetyByRole` overrides `safety` per role: `{ beam: 0.45, slab: 0.45, roof: 0.45, stair: 0.45 }` keeps the
|
|
156
|
+
floors well under their limit so they outlast the member that fails.
|
|
157
|
+
|
|
158
|
+
## Walls: layers, stages, breach and reinforcement
|
|
159
|
+
A wall is one part that opts in with `layers`, `units`, `reinforcement` or `breach` (`PartSpec`, all optional; parts without them behave as before).
|
|
160
|
+
`assemblyPart(id, { id, width, height, position, structure? })` builds one from the eight built-in **assemblies** (`ASSEMBLIES`, data in
|
|
161
|
+
`src/data/assemblies.json`; add or replace with `registerAssembly`): `brick_wall_plastered` (0.09 m brick, 2 x 0.02 m plaster, 0.23 x 0.075 x 0.11 m
|
|
162
|
+
bricks in running bond), `concrete_block_wall` (0.39 x 0.19 x 0.14 m hollow blocks), `reinforced_concrete` (0.2 m, rebar every 0.18 m, 0.6 x 0.42 m
|
|
163
|
+
panels), `drywall`, `wood_frame_wall`, `log_wall`, `sheet_metal_shack`, `glass_pane`.
|
|
164
|
+
|
|
165
|
+
- **Layers and spall.** A bullet spends `penetration x thickness` of every coat still on the faces it crosses, plus the core's. The outermost coat at the
|
|
166
|
+
impact comes off first (`spall` event, `area`), and a patch that spalled no longer stops anything: the same round that stops at fresh plaster can
|
|
167
|
+
go through once it has come off. A coat only spalls once per patch. Blunt hits spall the coat too.
|
|
168
|
+
- **Stages** (`PartState.stage`, `stage` event). 0 intact; 1 at the first hole, crack or spall; 2 when through damage within 0.55 m adds up to
|
|
169
|
+
`breach.area` (0.25 m²): the units around the hit come out as fragments the size of one unit (`stage.fragments`, laid in the assembly's bond), the part
|
|
170
|
+
stays with an `opening` (shots and rays pass through it, its mass and capacity drop) and nothing is hidden; 3 when the part fractures or collapses.
|
|
171
|
+
Through damage is the area of through holes plus, for blunt, slash and explosive damage, the volume the damage takes out (`damage / (hpPerKg x
|
|
172
|
+
density)`) over the thickness it crosses, times `breach.blastFactor` (6) for blasts. An opening as wide as the part cuts it instead (a pilaster, a column):
|
|
173
|
+
that is a fracture. So a 9 mm burst never leaves stage 1 on plastered brick (it does not even go through), a rifle never breaches reinforced
|
|
174
|
+
concrete, a sledgehammer opens plastered brick after ~47 swings and a C4 or RPG opens reinforced concrete at once. The engine stays in joules: the
|
|
175
|
+
game tunes energies, `breach: { radius, blastFactor }` and each assembly's `breach.area`.
|
|
176
|
+
- **Reinforced concrete.** At 0 hp the concrete crumbles (`fracture`, in panels when `units` is set) but the part does not go: it becomes its rebar cage
|
|
177
|
+
(`PartState.stripped`, `expose` with the bars in world space, stage 3), still part of the structure with `capacity x residualCapacity` (default 0.15).
|
|
178
|
+
A bare cage under load is overloaded in seconds (`overloadRate`), so the frame fails progressively: `expose`, `stress`, the cage is lost (`expose` with
|
|
179
|
+
no bars), then the neighbours and the slab (`collapse`). Bullets pass through a cage. The `rebar` joints of a reinforced part are not worn by blows:
|
|
180
|
+
only the cutting torch or a saw cuts them (or the cage giving way). A breach at stage 2 exposes only the bars inside the opening.
|
|
181
|
+
- **Holes stay on the pieces.** Every `fracture` and breach fragment carries `marks` (`FragmentMark`: point, normal and diameter in the fragment's own
|
|
182
|
+
axes) for the holes that fell inside it, at most 12 per fragment.
|
|
154
183
|
|
|
155
184
|
## Contracts: implement your own or use the default world
|
|
156
185
|
|
|
@@ -186,7 +215,7 @@ valid (unique ids, known materials, joints reference parts), a 500 J ballistic h
|
|
|
186
215
|
## Events
|
|
187
216
|
|
|
188
217
|
`damage`, `dent`, `hole`, `crack`, `ricochet`, `debris`, `fracture` (with oriented `fragments` in world space), `detach`, `disassemble_progress`,
|
|
189
|
-
`ignite`, `extinguish`, `burnout`, `melt`, `drip`, `leak`, `explode`, `primed`, `stress`, `collapse`, `destroyed`. All points are in world space. Subscribe with
|
|
218
|
+
`ignite`, `extinguish`, `burnout`, `melt`, `drip`, `leak`, `explode`, `primed`, `stress`, `collapse`, `spall`, `stage`, `expose`, `destroyed`. All points are in world space. Subscribe with
|
|
190
219
|
`world.on(type | '*', fn)` or the `onEvent` option; `hit` and `update` also return their events.
|
|
191
220
|
|
|
192
221
|
## Determinism and LAN
|
|
@@ -201,7 +230,7 @@ world continues with the same events as the original. The loading world must use
|
|
|
201
230
|
`raycast`, `shoot`, `disassemble`, `workableJoints`, `nearestJoint`, `extinguish`, `setLiters`, `update`, `state`, `part`, `reset`, `on`,
|
|
202
231
|
`register`, `serialize`, `load`, `time`. `state()` and `part()` return live views; do not mutate them.
|
|
203
232
|
|
|
204
|
-
Also exported: `buildFrame`, `sizeStructure`, `partCapacity`, `checkDestructible`, `checkHit`, `IMPACT_CONTRACT`, `MATERIALS`, `JOINT_DEFAULTS`, `JOINT_BY_MATERIALS`, `inferJoints`, `guessMaterial`, `partVolume`, `partMass`, `partThickness`, the
|
|
233
|
+
Also exported: `buildFrame`, `sizeStructure`, `assemblyPart`, `registerAssembly`, `getAssembly`, `ASSEMBLIES`, `assemblyDepth`, `partCapacity`, `checkDestructible`, `checkHit`, `IMPACT_CONTRACT`, `MATERIALS`, `JOINT_DEFAULTS`, `JOINT_BY_MATERIALS`, `inferJoints`, `guessMaterial`, `partVolume`, `partMass`, `partThickness`, the
|
|
205
234
|
helpers `vec`, `quat`, `quatFromEuler`, `rotateVec`, `toLocal`, `toWorld`, the locale (`locales`, `resolveStrings`, `DestructionStrings`) and all types.
|
|
206
235
|
|
|
207
236
|
The locale table has `en` and `pt-BR` strings for material names, part statuses, joint kinds, tools, damage types, event labels and fracture styles:
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Vec3, Quat, MaterialId, FractureStyle, DamageType, DebrisKind, DestructionEvent, DestructibleSpec, ObjectState, DestructibleImpl, Hit, HitResult, RayHit, ToolKind, JointState, PartState, DestructionEventType, ExplosionChain, PartSpec, JointKind, JointSpec, PartShape,
|
|
2
|
-
export { ChainDelay, Crack, DamageType, DebrisKind, Dent, DestructibleImpl, DestructibleSpec, DestructionEvent, DestructionEventType, ExplosionChain, FluidKind, FractureStyle, Fragment, Hit, HitResult, Hole, IMPACT_CONTRACT, ImpactContract, JointKind, JointSpec, JointState, MaterialId, ObjectState, PartShape, PartSpec, PartState, PartStatus, Quat, RayHit, StructureRole, ToolKind, Vec3, checkHit } from '@adatechnology/game-contracts';
|
|
1
|
+
import { Vec3, Quat, MaterialId, FractureStyle, DamageType, DebrisKind, DestructionEvent, DestructibleSpec, ObjectState, DestructibleImpl, Hit, HitResult, RayHit, ToolKind, JointState, PartState, DestructionEventType, StructureRole, ExplosionChain, PartSpec, JointKind, JointSpec, PartShape, SurfaceLayer, PartUnits, Reinforcement, PartBreach, PartStatus } from '@adatechnology/game-contracts';
|
|
2
|
+
export { ChainDelay, Crack, DamageStage, DamageType, DebrisKind, Dent, DestructibleImpl, DestructibleSpec, DestructionEvent, DestructionEventType, ExplosionChain, FluidKind, FractureStyle, Fragment, FragmentMark, Hit, HitResult, Hole, IMPACT_CONTRACT, ImpactContract, JointKind, JointSpec, JointState, MaterialId, ObjectState, PartBreach, PartShape, PartSpec, PartState, PartStatus, PartUnits, Quat, RayHit, Reinforcement, StructureRole, SurfaceLayer, ToolKind, Vec3, checkHit } from '@adatechnology/game-contracts';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Public types of @adatechnology/game-destruction.
|
|
@@ -95,12 +95,23 @@ interface DestructionOptions {
|
|
|
95
95
|
maxHoles?: number;
|
|
96
96
|
/** Distance at which a burning part heats parts of other objects, in metres (default 0.6). */
|
|
97
97
|
fireSpread?: number;
|
|
98
|
+
/** Breach of staged parts (see `PartSpec.breach`). */
|
|
99
|
+
breach?: {
|
|
100
|
+
/** Metres around a hit within which through damage adds up (default 0.55). */
|
|
101
|
+
radius?: number;
|
|
102
|
+
/** Multiplier of the breach area a blast makes over a blow of the same damage: a blast loads the whole crater (default 6). */
|
|
103
|
+
blastFactor?: number;
|
|
104
|
+
};
|
|
98
105
|
}
|
|
99
106
|
interface SizeStructureOptions {
|
|
100
107
|
/** Stress every structural part has at rest after sizing (`load / capacity`), 0..1 (default 0.65). */
|
|
101
108
|
safety?: number;
|
|
109
|
+
/** Stress at rest per structural role, over `safety` (a house: beams, slabs, roofs and stairs at 0.45 so they outlast a lost column). */
|
|
110
|
+
safetyByRole?: Partial<Record<StructureRole, number>>;
|
|
111
|
+
/** Roles whose parts are removed one at a time by the redundancy check (default `['column']`; a house adds `'wall'`). */
|
|
112
|
+
redundancyRoles?: readonly StructureRole[];
|
|
102
113
|
/**
|
|
103
|
-
* Redundancy target: when set, the capacity of a part is raised (never lowered) until losing any single `
|
|
114
|
+
* Redundancy target: when set, the capacity of a part is raised (never lowered) until losing any single part of `redundancyRoles` leaves every other
|
|
104
115
|
* structural part at this stress or below, e.g. 0.97 (an N-1 design: the building stands with one column gone). Omit to skip the check.
|
|
105
116
|
* Should be above `safety` and, to let the structure fall when a second column goes, below 1.
|
|
106
117
|
*/
|
|
@@ -206,6 +217,12 @@ interface PartRuntime {
|
|
|
206
217
|
stressT?: number;
|
|
207
218
|
/** World time at which a primed explosive part goes off (`explodes.chain`). */
|
|
208
219
|
chainDue?: number;
|
|
220
|
+
/** Patches of surface layers that came off (`layers.ts`). */
|
|
221
|
+
spalls?: Array<[number, number, number, number, number, number]>;
|
|
222
|
+
/** Through damage so far: `[x, y, z, area]` in object space, newest last. */
|
|
223
|
+
breach?: Array<[number, number, number, number]>;
|
|
224
|
+
/** Mass in kg that left the part in a breach. */
|
|
225
|
+
removed?: number;
|
|
209
226
|
}
|
|
210
227
|
/** Opaque bookkeeping of an object (see `PartRuntime`). `joints` holds the last disassembly step reported per joint id. */
|
|
211
228
|
interface ObjectRuntime {
|
|
@@ -297,6 +314,54 @@ declare const partCapacity: (part: PartSpec, material: MaterialDef) => number;
|
|
|
297
314
|
*/
|
|
298
315
|
declare const fragility: (ductility: number, thickness: number) => number;
|
|
299
316
|
|
|
317
|
+
/**
|
|
318
|
+
* A wall as a builder builds it: a core with coats, the masonry unit it is laid in, its rebar and when it breaches. Dimensions are metres (data in
|
|
319
|
+
* `src/data/assemblies.json`); `assemblyPart` turns one into a `PartSpec`. Extend or override with `registerAssembly`.
|
|
320
|
+
*/
|
|
321
|
+
interface AssemblyDef {
|
|
322
|
+
id: string;
|
|
323
|
+
name: string;
|
|
324
|
+
/** `thickness` is the core's, in metres: what a bullet has to get through besides the coats. */
|
|
325
|
+
core: {
|
|
326
|
+
material: MaterialId;
|
|
327
|
+
thickness: number;
|
|
328
|
+
};
|
|
329
|
+
/** Coats, outermost first. */
|
|
330
|
+
layers?: readonly SurfaceLayer[];
|
|
331
|
+
/** Physical depth of the wall when it is not core plus coats (a drywall partition is mostly air between the boards). */
|
|
332
|
+
depth?: number;
|
|
333
|
+
/** Solid fraction of the core (hollow blocks, round logs): scales its mass and the thickness a bullet crosses. Default 1. */
|
|
334
|
+
fill?: number;
|
|
335
|
+
units?: PartUnits;
|
|
336
|
+
reinforcement?: Reinforcement;
|
|
337
|
+
breach?: PartBreach;
|
|
338
|
+
}
|
|
339
|
+
interface AssemblyPartOptions {
|
|
340
|
+
id: string;
|
|
341
|
+
/** Along the part's x axis. */
|
|
342
|
+
width: number;
|
|
343
|
+
/** Along the part's y axis. */
|
|
344
|
+
height: number;
|
|
345
|
+
position: Vec3;
|
|
346
|
+
rotation?: Vec3;
|
|
347
|
+
structure?: PartSpec['structure'];
|
|
348
|
+
/** Other `PartSpec` fields (tags, anchored, hp...). */
|
|
349
|
+
extra?: Partial<PartSpec>;
|
|
350
|
+
/** Materials to read densities from (default the built-in `MATERIALS`). */
|
|
351
|
+
materials?: ReadonlyMap<MaterialId, MaterialDef>;
|
|
352
|
+
}
|
|
353
|
+
/** Built-in assemblies; `registerAssembly` adds to this list. */
|
|
354
|
+
declare const ASSEMBLIES: AssemblyDef[];
|
|
355
|
+
declare const registerAssembly: (def: AssemblyDef) => void;
|
|
356
|
+
declare const getAssembly: (id: string) => AssemblyDef | undefined;
|
|
357
|
+
/** Physical depth of the wall in metres. */
|
|
358
|
+
declare const assemblyDepth: (def: AssemblyDef) => number;
|
|
359
|
+
/**
|
|
360
|
+
* 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`)
|
|
361
|
+
* plus the coats; `thickness` is the core's, so each coat adds its own `penetration x thickness` to what a bullet must cross.
|
|
362
|
+
*/
|
|
363
|
+
declare const assemblyPart: (assemblyId: string, options: AssemblyPartOptions) => PartSpec;
|
|
364
|
+
|
|
300
365
|
interface FrameOptions {
|
|
301
366
|
/** Total length along x between the outer column centres, metres (default 8). */
|
|
302
367
|
spanX?: number;
|
|
@@ -337,8 +402,9 @@ declare const buildFrame: (o?: FrameOptions) => DestructibleSpec;
|
|
|
337
402
|
/**
|
|
338
403
|
* Sizes the load capacity of a structure the way an engineer would, from the loads the world itself computes. The intact spec goes through the
|
|
339
404
|
* same load solver `createDestruction` uses, and each structural part (`structure.role` other than `none`) gets `structure.capacity = load / safety`,
|
|
340
|
-
* so its at-rest stress is exactly `safety
|
|
341
|
-
*
|
|
405
|
+
* so its at-rest stress is exactly `safety` (`safetyByRole` overrides it per role). With `redundancy` set, every part whose role is in
|
|
406
|
+
* `redundancyRoles` (default `column`) is also removed in turn and the capacity of the parts that would carry more is raised so they stay at or below
|
|
407
|
+
* `redundancy`. Parts without `structure`, with role `none`, or with no support path to an
|
|
342
408
|
* anchored part are left as they are. The spec is not modified; a copy is returned.
|
|
343
409
|
*/
|
|
344
410
|
declare const sizeStructure: (spec: DestructibleSpec, options?: SizeStructureOptions) => DestructibleSpec;
|
|
@@ -410,4 +476,4 @@ declare const checkDestructible: (impl: DestructibleImpl, options?: CheckOptions
|
|
|
410
476
|
problems: string[];
|
|
411
477
|
};
|
|
412
478
|
|
|
413
|
-
export { type AddOptions, type ChainTrigger, type CheckOptions, type DestructionLocale, type DestructionOptions, type DestructionSnapshot, type DestructionStrings, type DestructionWorld, type ExplosivePartOptions, FIRE_PRIME_C, type FrameOptions, JOINT_BY_MATERIALS, JOINT_DEFAULTS, MATERIALS, type MaterialDef, type MaterialThermal, type ObjectRuntime, type PartRuntime, type SizeStructureOptions, type WorldExplosive, buildFrame, checkDestructible, createDestruction, explosivePart, fragility, guessMaterial, inferJoints, locales, partCapacity, partMass, partThickness, partVolume, quat, quatFromEuler, resolveStrings, rotateVec, sizeStructure, toLocal, toWorld, vec };
|
|
479
|
+
export { ASSEMBLIES, type AddOptions, type AssemblyDef, type AssemblyPartOptions, type ChainTrigger, type CheckOptions, type DestructionLocale, type DestructionOptions, type DestructionSnapshot, type DestructionStrings, type DestructionWorld, type ExplosivePartOptions, FIRE_PRIME_C, type FrameOptions, JOINT_BY_MATERIALS, JOINT_DEFAULTS, MATERIALS, type MaterialDef, type MaterialThermal, type ObjectRuntime, type PartRuntime, type SizeStructureOptions, type WorldExplosive, assemblyDepth, assemblyPart, buildFrame, checkDestructible, createDestruction, explosivePart, fragility, getAssembly, guessMaterial, inferJoints, locales, partCapacity, partMass, partThickness, partVolume, quat, quatFromEuler, registerAssembly, resolveStrings, rotateVec, sizeStructure, toLocal, toWorld, vec };
|