@adatechnology/game-floorplan-structure 1.0.4 → 1.1.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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/registry.ts","../src/geometry.ts","../src/presets.ts","../src/construction.ts","../src/locales/en.json","../src/locales/pt-BR.json","../src/types.ts","../src/density.ts","../src/structure/builder.ts","../src/structure/legacy-key.ts","../src/structure/context.ts","../src/structure/balconies.ts","../src/structure/canvas.ts","../src/structure/extras.ts","../src/structure/floor-deck.ts","../src/structure/foundation.ts","../src/structure/plates.ts","../src/structure/porch.ts","../src/structure/porch-roof.ts","../src/structure/roof.ts","../src/structure/stairs.ts","../src/structure/openings.ts","../src/structure/steps.ts","../src/structure/tank-parts.ts","../src/structure/upper-floor.ts","../src/structure/walls.ts","../src/structure/index.ts","../src/utilities/content-tables.ts","../src/utilities/content.ts","../src/utilities/shared.ts","../src/utilities/wall-points.ts","../src/utilities/electrical-outlets.ts","../src/utilities/electrical-entrance.ts","../src/utilities/electrical-circuits.ts","../src/utilities/electrical.ts","../src/utilities/gas.ts","../src/utilities/plumbing.ts","../src/utilities/solar.ts","../src/utilities/index.ts","../src/utilities/outbuildings.ts","../src/water-tank.ts","../src/viewer-layer.ts","../src/register.ts","../../game-destruction/src/chain.ts","../../game-destruction/src/math.ts","../../game-destruction/src/fracture.ts","../../game-destruction/src/breach.ts","../../game-destruction/src/layers.ts","../../game-destruction/src/rebar.ts","../../game-destruction/src/data/materials.json","../../game-destruction/src/data/material-hints.json","../../game-destruction/src/materials.ts","../../game-destruction/src/world.ts","../../game-destruction/src/piercing.ts","../../game-destruction/src/data/assemblies.json","../../game-destruction/src/assemblies.ts","../../game-destruction/src/frame.ts","../../game-destruction/src/size.ts","../../game-destruction/src/locale.ts","../../game-destruction/src/contracts.ts","../src/loads.ts","../src/wall-detail/apply.ts","../src/wall-detail/courses.ts","../src/wall-detail/panels.ts","../src/wall-detail/index.ts","../src/to-destructible-spec.ts","../src/wall-specimen.ts"],"sourcesContent":["export const version = '0.1.0'\n\nexport { register } from './register'\nexport type { StructurePackOptions } from './register'\nexport { buildStructure } from './structure'\nexport { toDestructibleSpec } from './to-destructible-spec'\nexport type { DestructibleSpecOptions } from './to-destructible-spec'\nexport { buildWallSpecimen } from './wall-specimen'\nexport type { WallSpecimenOptions } from './wall-specimen'\nexport { planWaterTank } from './water-tank'\nexport type { TankPlanOptions } from './water-tank'\nexport {\n CONSTRUCTION_SYSTEMS, CONSTRUCTIONS, ROOF_COVERINGS, registerConstruction, registerConstructionSystem, registerRoofCovering,\n} from './registry'\nexport type { ConstructionBuild, ConstructionBuilder, ConstructionSystemDef, RoofCoveringDef } from './registry'\nexport { campConstruction, chaletConstruction, constructionOfSystem, logCabinConstruction, masonryConstruction, shackConstruction, woodFrameConstruction } from './presets'\nexport type { ChaletOptions, ShackOptions, WoodFrameOptions } from './presets'\nexport { structureLayer } from './viewer-layer'\nexport { DENSITY } from './density'\nexport { GROUND } from './types'\nexport type * from './types'\n","import type { JointKind } from '@adatechnology/game-contracts'\n\nimport type { Construction, ConstructionSystem, PlanContext, StructureExtras } from './types'\n\n/** What a wall system is made of and how its parts are tied. Timber systems sit on joists, carry the roof on timber plates and have wooden porch posts. */\nexport interface ConstructionSystemDef {\n /** Wall assembly of `game-destruction` (`registerAssembly`) the detailed wall is built from. Empty: no walls (a tent). */\n walls: string\n joints: Record<'wall' | 'slab' | 'beam' | 'column' | 'truss', JointKind>\n /** Thickness of the structural floor under each storey (m). */\n slabThickness: number\n /** Height of the top plate or bond beam (m). */\n plateThickness: number\n timber: boolean\n /** `rules`: bearing when external, under another wall or beside a porch; `bearing`: every wall (logs); `partition`: none (posts carry the roof). */\n wallRole: 'rules' | 'bearing' | 'partition'\n /** Solid fraction of a bearing wall in the structure weight (studs and air). */\n wallFill: number\n studs?: { spacing: number; section: string }\n}\n\nconst uniform = (joint: JointKind): ConstructionSystemDef['joints'] => ({ wall: joint, slab: joint, beam: joint, column: joint, truss: joint })\n\nexport const CONSTRUCTION_SYSTEMS = new Map<string, ConstructionSystemDef>([\n ['masonry', { walls: 'brick_wall_plastered', joints: { wall: 'mortar', slab: 'rebar', beam: 'mortar', column: 'rebar', truss: 'bolt' }, slabThickness: 0.12, plateThickness: 0.2, timber: false, wallRole: 'rules', wallFill: 1 }],\n ['wood_frame', { walls: 'wood_frame_wall', joints: uniform('nail'), slabThickness: 0.28, plateThickness: 0.1, timber: true, wallRole: 'rules', wallFill: 0.35, studs: { spacing: 0.4, section: '38x89' } }],\n ['log', { walls: 'log_wall', joints: { wall: 'bolt', slab: 'nail', beam: 'bolt', column: 'bolt', truss: 'bolt' }, slabThickness: 0.2, plateThickness: 0.1, timber: true, wallRole: 'bearing', wallFill: 1 }],\n ['improvised', { walls: 'sheet_metal_shack', joints: uniform('nail'), slabThickness: 0.2, plateThickness: 0.1, timber: true, wallRole: 'partition', wallFill: 1 }],\n ['canvas', { walls: '', joints: uniform('tie'), slabThickness: 0, plateThickness: 0, timber: false, wallRole: 'partition', wallFill: 1 }],\n])\n\n/** Adds or replaces a construction system (`id` is a `ConstructionSystem` or any name a construction refers to). */\nexport function registerConstructionSystem(id: ConstructionSystem | string, def: ConstructionSystemDef): void {\n CONSTRUCTION_SYSTEMS.set(id, def)\n}\n\nexport interface RoofCoveringDef {\n material: string\n /** How the covering is fixed to the trusses. */\n joint: JointKind\n}\n\nexport const ROOF_COVERINGS = new Map<string, RoofCoveringDef>([\n ['colonial', { material: 'ceramic', joint: 'resting' }],\n ['fiber_cement', { material: 'concrete', joint: 'bolt' }],\n ['slab', { material: 'concrete', joint: 'rebar' }],\n ['asphalt', { material: 'plastic', joint: 'nail' }],\n ['zinc', { material: 'steel', joint: 'nail' }],\n ['wood', { material: 'wood_soft', joint: 'nail' }],\n ['canvas', { material: 'fabric', joint: 'tie' }],\n ['thatch', { material: 'foliage', joint: 'tie' }],\n])\n\nexport function registerRoofCovering(id: string, def: RoofCoveringDef): void {\n ROOF_COVERINGS.set(id, def)\n}\n\nexport interface ConstructionBuild {\n construction: Construction\n extras?: StructureExtras\n}\nexport type ConstructionBuilder = (context: PlanContext) => ConstructionBuild\n\nexport const CONSTRUCTIONS = new Map<string, ConstructionBuilder>()\n\n/** Registers how a template's building is made: `TemplateDef.construction` names it. A template without one gets the masonry default. */\nexport function registerConstruction(id: string, builder: ConstructionBuilder): void {\n CONSTRUCTIONS.set(id, builder)\n}\n","import type { Rect, SourceWall } from './types'\n\nexport const WALL_THICKNESS = 0.15\n\nexport const round2 = (value: number): number => Math.round(value * 100) / 100\n\nexport function touches(a: Rect, b: Rect, tolerance: number): boolean {\n return a[0] < b[2] + tolerance && a[2] > b[0] - tolerance && a[1] < b[3] + tolerance && a[3] > b[1] - tolerance\n}\n\nexport function distanceBetween(a: Rect, b: Rect): number {\n return Math.hypot(Math.max(a[0] - b[2], b[0] - a[2], 0), Math.max(a[1] - b[3], b[1] - a[3], 0))\n}\n\nexport function unionOf(rects: readonly Rect[]): Rect {\n const out: Rect = [1e9, 1e9, -1e9, -1e9]\n for (const rect of rects) {\n out[0] = Math.min(out[0], rect[0])\n out[1] = Math.min(out[1], rect[1])\n out[2] = Math.max(out[2], rect[2])\n out[3] = Math.max(out[3], rect[3])\n }\n return out\n}\n\n/** The wall's centre line thickened to its box in the plan. */\nexport function wallBox(wall: Pick<SourceWall, 'u0' | 'v0' | 'u1' | 'v1' | 'thickness'>): Rect {\n const half = (wall.thickness ?? WALL_THICKNESS) / 2\n return [Math.min(wall.u0, wall.u1) - half, Math.min(wall.v0, wall.v1) - half, Math.max(wall.u0, wall.u1) + half, Math.max(wall.v0, wall.v1) + half]\n}\n\nexport const centreOf = (rect: Rect): [number, number] => [(rect[0] + rect[2]) / 2, (rect[1] + rect[3]) / 2]\n\n/** The nearest `count` of `candidates` to `target`, nearest first. */\nexport function nearestTo<T extends { aabb: Rect }>(target: Rect, candidates: readonly T[], count: number): T[] {\n return candidates.slice().sort((a, b) => distanceBetween(target, a.aabb) - distanceBetween(target, b.aabb)).slice(0, count)\n}\n","import type { Construction, FoundationType, StructureSource } from './types'\nimport { WALL_THICKNESS } from './geometry'\nimport { ROOF_COVERINGS } from './registry'\n\nconst SLAB_COVERING = 'slab'\nconst PLASTERED_FINISHES = ['plaster', 'partial_plaster']\n\n/** Masonry house of the engine's own templates: brick with plaster, concrete frame, tiles by facade; a unit in a building gets a flat slab roof. */\nexport function masonryConstruction(source: StructureSource): Construction {\n const unit = source.floorNumber !== undefined\n const covering = unit ? SLAB_COVERING : (source.facade.roof ?? 'colonial')\n const finish = source.facade.finish ?? 'roughcast'\n const budget = source.style === 'budget'\n const flat = unit || covering === SLAB_COVERING\n return {\n system: 'masonry',\n walls: { material: 'brick', cladding: PLASTERED_FINISHES.includes(finish) ? 'plaster' : null, finish, thickness: WALL_THICKNESS, ...(finish === 'exposed_block' ? { assembly: 'concrete_block_wall' } : {}) },\n floor: { material: budget ? 'concrete' : 'ceramic', finish: budget ? 'burnt_cement' : 'ceramic_tile' },\n roof: { material: ROOF_COVERINGS.get(covering)?.material ?? 'ceramic', covering, shape: flat ? 'slab' : 'gable', pitch: flat ? 0 : covering === 'colonial' ? 30 : 15, timber: 'wood_soft' },\n frame: { material: 'concrete', pillars: 'concrete', beams: 'concrete', slabs: 'concrete', timber: 'wood_soft', rebar: 'steel' },\n foundation: { type: unit ? 'building' : 'strip_footing', material: 'concrete', elevation: 0 },\n }\n}\n\nexport interface WoodFrameOptions {\n foundation?: 'basement' | 'crawl_space' | 'raft'\n covering?: string\n finish?: string\n /** Cladding of the outer face (default soft wood). */\n cladding?: string\n}\n\nconst FOUNDATIONS: Record<NonNullable<WoodFrameOptions['foundation']>, Construction['foundation']> = {\n basement: { type: 'basement', material: 'concrete', elevation: 0.5, depth: 2.4 },\n crawl_space: { type: 'crawl_space', material: 'concrete', elevation: 0.6 },\n raft: { type: 'raft', material: 'concrete', elevation: 0.2 },\n}\n\nconst TIMBER_FRAME: Construction['frame'] = { material: 'wood_soft', pillars: 'wood_soft', beams: 'wood_soft', slabs: 'plywood', timber: 'wood_soft', rebar: null }\n\n/** American wood frame house: 38x89 studs every 40 cm, plaster inside, wood outside, asphalt shingles. */\nexport function woodFrameConstruction(options: WoodFrameOptions = {}): Construction {\n const covering = options.covering ?? 'asphalt'\n return {\n system: 'wood_frame',\n walls: { material: 'wood_soft', interior: 'plaster', cladding: options.cladding ?? 'wood_soft', finish: options.finish ?? 'wood_siding', thickness: WALL_THICKNESS, studs: '38x89 every 40 cm', insulation: 'foam' },\n floor: { material: 'wood_hard', finish: 'wood_boards' },\n roof: { material: ROOF_COVERINGS.get(covering)?.material ?? 'plastic', covering, shape: 'gable', pitch: 28, timber: 'wood_soft', eave: 0.5 },\n frame: { ...TIMBER_FRAME },\n foundation: { ...FOUNDATIONS[options.foundation ?? 'raft'] },\n }\n}\n\nexport interface ChaletOptions {\n covering?: string\n finish?: string\n piles?: boolean\n}\n\n/** Mountain chalet: A-frame roof at 52 degrees with gables front and back, 38x140 studs. */\nexport function chaletConstruction(options: ChaletOptions = {}): Construction {\n const covering = options.covering ?? 'colonial'\n return {\n system: 'wood_frame',\n walls: { material: 'wood_soft', interior: 'wood_soft', cladding: 'wood_hard', finish: options.finish ?? 'vertical_boards', thickness: WALL_THICKNESS, studs: '38x140 every 40 cm' },\n floor: { material: 'wood_hard', finish: 'wood_boards' },\n roof: { material: ROOF_COVERINGS.get(covering)?.material ?? 'wood_soft', covering, shape: 'gable', pitch: 52, timber: 'wood_soft', eave: 0.8, axis: 'v', profile: 'a_frame', gables: ['front', 'back'] },\n frame: { ...TIMBER_FRAME },\n foundation: options.piles ? { type: 'piles', material: 'stone', elevation: 0.9 } : { type: 'raft', material: 'concrete', elevation: 0.2 },\n }\n}\n\n/** Log cabin: every wall is a stack of 26 cm logs, notched at the corners, on stone piles. */\nexport function logCabinConstruction(options: { covering?: string } = {}): Construction {\n const covering = options.covering ?? 'wood'\n return {\n system: 'log',\n walls: { material: 'wood_hard', interior: 'wood_hard', cladding: null, finish: 'log', thickness: WALL_THICKNESS, logDiameter: 0.26, joint: 'notched_corners' },\n floor: { material: 'wood_hard', finish: 'wood_boards' },\n roof: { material: ROOF_COVERINGS.get(covering)?.material ?? 'wood_soft', covering, shape: 'gable', pitch: 32, timber: 'wood_hard', eave: 0.6 },\n frame: { material: 'wood_hard', pillars: 'wood_hard', beams: 'wood_hard', slabs: 'wood_hard', timber: 'wood_hard', rebar: null },\n foundation: { type: 'piles', material: 'stone', elevation: 0.5 },\n }\n}\n\nexport interface ShackOptions {\n material?: 'wood' | 'zinc' | 'mixed'\n floor?: 'soil' | 'concrete'\n}\n\nconst MIXED_SCRAP = ['wood_soft', 'steel', 'plywood', 'steel', 'wood_soft']\n\n/** Shack of scrap boards and zinc sheets: timber posts carry the roof, the walls only close. */\nexport function shackConstruction(options: ShackOptions = {}): Construction {\n const material = options.material === 'zinc' ? 'steel' : 'wood_soft'\n const onSoil = options.floor === 'soil'\n return {\n system: 'improvised',\n walls: { material, interior: options.material === 'zinc' ? 'plywood' : material, cladding: null, finish: 'scrap', thickness: WALL_THICKNESS, ...(options.material === 'mixed' ? { mixed: MIXED_SCRAP } : {}) },\n floor: onSoil ? { material: 'soil', finish: 'packed_earth' } : { material: 'concrete', finish: 'burnt_cement' },\n roof: { material: 'steel', covering: 'zinc', shape: 'gable', pitch: 12, timber: 'wood_soft', eave: 0.3, fastening: 'nails_and_stones' },\n frame: { material: 'wood_soft', pillars: 'wood_soft', beams: 'wood_soft', slabs: 'concrete', timber: 'wood_soft', rebar: null },\n foundation: onSoil ? { type: 'ground', material: 'soil', elevation: 0 } : { type: 'raft', material: 'concrete', elevation: 0.08 },\n }\n}\n\n/** Camping: canvas over aluminium poles on the ground; there are no walls. */\nexport function campConstruction(): Construction {\n return {\n system: 'canvas',\n walls: { material: 'fabric', interior: 'fabric', cladding: null, finish: 'nylon', thickness: 0.002 },\n floor: { material: 'plastic', finish: 'waterproof_mat' },\n roof: { material: 'fabric', covering: 'canvas', shape: 'tent', pitch: 0, timber: 'aluminium', eave: 0 },\n frame: { material: 'aluminium', pillars: 'aluminium', beams: 'aluminium', slabs: 'plastic', timber: 'aluminium', rebar: null },\n foundation: { type: 'ground', material: 'soil', elevation: 0 },\n }\n}\n\n/** The construction a system gets on any plan when the options force it (`options.construction`). */\nexport function constructionOfSystem(system: string, source: StructureSource): Construction | undefined {\n const covering = source.facade.roof\n const keep = covering && covering !== SLAB_COVERING ? { covering } : {}\n switch (system) {\n case 'masonry':\n return masonryConstruction(source)\n case 'wood_frame':\n return woodFrameConstruction(keep)\n case 'log':\n return logCabinConstruction(keep)\n case 'improvised':\n return shackConstruction()\n case 'canvas':\n return campConstruction()\n default:\n return undefined\n }\n}\n\nexport type { FoundationType }\n","import { CONSTRUCTIONS } from './registry'\nimport type { ConstructionBuild } from './registry'\nimport { constructionOfSystem, masonryConstruction } from './presets'\nimport type { PlanContext, StructureSource, Tent } from './types'\n\n/** The construction of a plan: the one it already carries, else the masonry default of the engine's templates. */\nexport function resolveConstruction(source: StructureSource): ConstructionBuild {\n const extras = source.structureExtras ?? {}\n return { construction: source.construction ?? masonryConstruction(source), extras }\n}\n\nconst TENT_LABEL = /^tent_(dome|tunnel)(?:_|$)/\n\n/**\n * Tents of a plan whose template names the `canvas` construction and registers none of its own: one per room of type `tent`, standing on the room's footprint\n * (a label `tent_<kind>_<people>` names the kind, any other is a long tunnel) as high as the room's ceiling.\n */\nexport function tentsOf(source: StructureSource): Tent[] {\n const tents: Tent[] = []\n for (const room of source.rooms) {\n if (room.type !== 'tent' || room.floor !== 0 || !room.parts[0]) continue\n const { label } = room as { label?: unknown }\n tents.push({ id: room.id, kind: TENT_LABEL.exec(typeof label === 'string' ? label : '')?.[1] ?? 'tunnel', height: room.ceiling ?? source.floors[0]?.ceiling ?? 2.4, aabb: room.parts[0] })\n }\n return tents\n}\n\n/**\n * Picks the construction for a plan being generated: `options.construction` (a registered construction or a system name) wins over the template's\n * own (`TemplateDef.construction`), which wins over the masonry default.\n */\nexport function constructionFor(context: PlanContext): ConstructionBuild {\n const forced = context.options?.construction\n const named = typeof forced === 'string' ? forced : (context.template?.construction as string | undefined)\n if (named === undefined) return { construction: masonryConstruction(context.result) }\n const registered = CONSTRUCTIONS.get(named)\n if (registered) return registered(context)\n const preset = constructionOfSystem(named, context.result)\n if (preset) return { construction: preset, ...(named === 'canvas' ? { extras: { tents: tentsOf(context.result) } } : {}) }\n throw new Error(`Unknown construction \"${named}\": register it with registerConstruction`)\n}\n","{\n \"ui\": {\n \"structure_layer\": \"Structure\",\n \"structure_column_concrete\": \"Concrete pillar\",\n \"structure_column_steel\": \"Steel post\",\n \"structure_column_masonry\": \"Masonry pillar\",\n \"structure_column_wood\": \"Wood post\",\n \"structure_beam_concrete\": \"Bond beam / beam (concrete)\",\n \"structure_beam_wood\": \"Plate / beam (wood)\",\n \"structure_roof_frame\": \"Trusses, rafters and ridge (roof view)\"\n }\n}\n","{\n \"ui\": {\n \"structure_layer\": \"Estrutura\",\n \"structure_column_concrete\": \"Pilar de concreto\",\n \"structure_column_steel\": \"Poste de aço\",\n \"structure_column_masonry\": \"Pilar de alvenaria\",\n \"structure_column_wood\": \"Pilar de madeira\",\n \"structure_beam_concrete\": \"Cinta / viga (concreto)\",\n \"structure_beam_wood\": \"Prato / viga (madeira)\",\n \"structure_roof_frame\": \"Tesouras, caibros e cumeeira (vista do telhado)\"\n }\n}\n","import type { JointKind, MaterialId, StructureRole } from '@adatechnology/game-contracts'\n\n/** Axis-aligned rectangle `[u0, v0, u1, v1]` in the plan (metres). */\nexport type Rect = [number, number, number, number]\n\nexport type ConstructionSystem = 'masonry' | 'wood_frame' | 'log' | 'improvised' | 'canvas'\nexport type WallDetail = 'coarse' | 'panels' | 'units'\n/** What a structural part is called in a plan: a column is a pillar, `wall` is a bearing wall, `partition` a wall that only closes. */\nexport type PartRole = Exclude<StructureRole, 'foundation'>\n\nexport const GROUND = 'ground'\n\n/** A piece of the structure with its box in the plan, its height range and the mass it weighs. `y` is absolute: the ground floor sits at `foundation.elevation`. */\nexport interface StructurePart {\n id: string\n role: PartRole\n material: MaterialId\n aabb: Rect\n y0: number\n y1: number\n floor: number\n mass: number\n /** Part this one is cut out of (a pier of a wall in `panels` detail). */\n host?: string\n /** Wall assembly of `game-destruction` the part is built from in the destructible spec (layers, units, rebar, breach). */\n assembly?: string\n /** A brick, block or log: the unit of a wall (`units` detail, log courses), not a piece of it. */\n unit?: true\n /** Distance between repeated members (joists, ceiling joists). */\n spacing?: number\n /** `plate` (timber top plate) or `bond_beam` (masonry bond beam). */\n beamKind?: 'plate' | 'bond_beam'\n steps?: number\n door?: string\n /** Slab that is the roof (flat roof). */\n cover?: boolean\n /** Litres a tank holds. */\n liters?: number\n studs?: { spacing: number; section: string }\n pitch?: number\n tent?: string\n form?: string\n}\n\n/** `part` rests on `on` (`GROUND` or another part) through `joint`. `bears: false` ties the two without carrying load. */\nexport interface Support {\n part: string\n on: string\n joint: JointKind\n bears?: false\n}\n\nexport interface RoofPane {\n id: string\n aabb: Rect\n y0: number\n y1: number\n flat?: true\n}\n\nexport type RoofShape = 'gable' | 'slab' | 'tent'\n\nexport interface Roof {\n shape: RoofShape\n covering: string\n material: MaterialId\n pitch: number\n /** Floor the roof rests on. */\n bearingFloor: number\n panes: (RoofPane | string)[]\n trusses: number\n axis?: 'u' | 'v'\n ridge?: number\n eave?: number\n y0?: number\n aabb?: Rect\n}\n\n/** A window in a wall (the doors are gaps between walls: a lintel part bridges them). Heights are absolute. */\nexport interface Opening {\n id: string\n kind: 'window' | 'door'\n wall: string\n /** Along the wall (u for a wall along u, v for one along v). */\n from: number\n to: number\n y0: number\n y1: number\n}\n\nexport interface Structure {\n parts: StructurePart[]\n supports: Support[]\n openings: Opening[]\n /** Absolute height of the floor level of each storey. */\n levels: number[]\n elevation: number\n roof: Roof\n construction: Construction\n /** A reinforced concrete frame carries the building (apartments, commercial buildings, three storeys or more); the walls are infill. */\n framed: boolean\n}\n\nexport interface WallMaterials {\n material: MaterialId\n interior?: MaterialId\n cladding?: MaterialId | null\n finish?: string\n /** Wall assembly of `game-destruction` (default by system, and by finish in masonry). */\n assembly?: string\n thickness: number\n studs?: string\n /** Materials drawn per wall by a hash of its legacy key (the improvised shack). */\n mixed?: MaterialId[]\n [extra: string]: unknown\n}\n\nexport interface Construction {\n system: ConstructionSystem\n walls: WallMaterials\n floor: { material: MaterialId; finish: string }\n roof: {\n material: MaterialId\n covering: string\n shape: RoofShape\n pitch: number\n timber: MaterialId\n eave?: number\n axis?: 'u' | 'v'\n bearingFloor?: number\n profile?: string\n gables?: string[]\n fastening?: string\n }\n frame: { material: MaterialId; pillars: MaterialId; beams: MaterialId; slabs: MaterialId; timber: MaterialId; rebar: MaterialId | null }\n foundation: { type: FoundationType; material: MaterialId; elevation: number; depth?: number }\n guard?: MaterialId\n stairs?: MaterialId\n}\n\nexport type FoundationType = 'strip_footing' | 'building' | 'raft' | 'crawl_space' | 'piles' | 'basement' | 'ground'\n\nexport interface Chimney {\n kind: 'fireplace' | 'flue'\n material: MaterialId\n aabb: Rect\n flue?: boolean\n top?: number\n height?: number\n}\n\nexport interface Tent {\n id: string\n kind: string\n height: number\n aabb: Rect\n}\n\n/** What a construction needs besides walls and roof, from the template: a chimney, a well, an attic floor, tents. */\nexport interface StructureExtras {\n chimney?: Chimney\n well?: { aabb: Rect; height?: number }\n attic?: boolean\n tents?: Tent[]\n [extra: string]: unknown\n}\n\nexport interface TankPlatform {\n aabb: Rect\n baseY: number\n height: number\n thickness: number\n topY: number\n pillars: { u: number; v: number; side: number }[]\n ladder: boolean\n}\n\nexport interface WaterTank {\n id: 'water_tank'\n kind: 'water_tank'\n itemType: string\n place: 'slab' | 'attic' | 'raised_slab' | 'trestle' | string\n floor: number\n room: string\n u: number\n v: number\n y: number\n w: number\n d: number\n h: number\n capacity: number\n material?: MaterialId\n aabb: Rect\n platform?: TankPlatform\n /** Trestle tank (a stand of its own: rural water). */\n stand?: { pillars: { u: number; v: number; side: number }[]; material: MaterialId; height: number; baseJoint?: JointKind; joint?: JointKind; tie?: JointKind; braces?: boolean }\n}\n\n/** The fields of a generated plan the structure reads. */\nexport interface StructureSource {\n floors: { y0: number; ceiling: number }[]\n rooms: { id: string; type: string; floor: number; parts: Rect[]; ceiling?: number | null }[]\n walls: SourceWall[]\n doors: SourceDoor[]\n windows?: SourceWindow[]\n items: { id?: string; type: string; category?: string; floor: number; aabb?: Rect; link?: { from: number; to: number } | null }[]\n facade: { roof?: string; finish?: string; [extra: string]: unknown }\n style?: string\n template?: string\n lot?: unknown\n w: number\n d: number\n floorNumber?: number\n waterTank?: WaterTank | null\n construction?: Construction\n structureExtras?: StructureExtras\n [extra: string]: unknown\n}\n\nexport interface SourceWall {\n floor: number\n axis: 'u' | 'v'\n u0: number\n v0: number\n u1: number\n v1: number\n thickness?: number\n sides: string[]\n exterior: boolean\n type: string\n h?: number\n /** Gable wall: the plate does not sit on top of it. */\n gable?: boolean\n structureHeight?: number\n}\n\nexport interface SourceWindow {\n id: string\n floor: number\n axis: 'u' | 'v'\n /** Coordinate of the wall line across its axis. */\n pos: number\n /** Centre along the wall. */\n at: number\n width: number\n y0: number\n y1: number\n}\n\nexport interface SourceDoor {\n id: string\n floor: number\n a: string\n b: string\n exterior?: boolean\n model?: string\n type?: string\n u: number\n v: number\n width: number\n side?: string\n axis: 'u' | 'v'\n steps?: number\n}\n\nexport interface StructureOptions {\n construction?: Construction\n extras?: StructureExtras\n tank?: WaterTank | null\n /** The porch roof is carried by its posts alone (the tie to the house wall carries nothing). Default: when the detail is not `coarse`. */\n porchRoofOnPostsOnly?: boolean\n /** Gable roofs as rafters of each side and a ridge beam (a side falls with the wall it rests on) instead of whole trusses. Default: when the detail is not `coarse`. */\n rafterRoof?: boolean\n wallDetail?: WallDetail\n}\n\n/** What a construction builder and the tank get to see: the generated plan, its seed and the template. */\nexport interface PlanContext {\n result: StructureSource\n seed: number | string\n /** The template definition (`TemplateDef`) when known: it may carry `tank` and `tankLocation` hooks. */\n template?: Record<string, unknown>\n options?: { floors?: number; [extra: string]: unknown }\n}\n","import type { MaterialId } from '@adatechnology/game-contracts'\n\n/** kg/m3 the plan structure weighs its parts with (the table of the Visor de casas 3D; a material outside it weighs like soft wood). */\nexport const DENSITY: Readonly<Record<string, number>> = {\n steel: 7850, cast_iron: 7200, aluminium: 2700, copper: 8900, wood_soft: 500, wood_hard: 800, plywood: 600, mdf: 750, glass: 2500,\n tempered_glass: 2500, ceramic: 2000, concrete: 2400, brick: 1800, plaster: 1000, stone: 2600, plastic: 950, rubber: 1100, fabric: 400,\n foam: 30, leather: 900, paper: 800, foliage: 100, green_wood: 900, cactus: 700, flesh_fruit: 900, wax: 900, soil: 1600,\n}\nexport const DEFAULT_DENSITY = 500\n\nexport const densityOf = (material: MaterialId): number => DENSITY[material] ?? DEFAULT_DENSITY\n","import type { JointKind, MaterialId } from '@adatechnology/game-contracts'\n\nimport { densityOf } from '../density'\nimport { round2 } from '../geometry'\nimport { GROUND } from '../types'\nimport type { PartRole, Rect, StructurePart, Support } from '../types'\n\nexport type PartExtras = Partial<Pick<StructurePart, 'host' | 'spacing' | 'beamKind' | 'steps' | 'door' | 'cover' | 'studs' | 'pitch' | 'tent' | 'form' | 'liters' | 'assembly'>>\nexport interface PartOptions extends PartExtras {\n floor?: number\n /** Solid fraction of the box (studs, trusses, tile roofs). */\n fill?: number\n}\n\nexport interface PartDraft {\n id: string\n role: PartRole\n material: MaterialId\n aabb: Rect\n y0: number\n y1: number\n}\n\n/** Collects the parts and what each rests on. A part id is unique: a second one is a bug of the builder. */\nexport class StructureBuilder {\n readonly parts: StructurePart[] = []\n readonly supports: Support[] = []\n private readonly ids = new Set<string>()\n\n add(draft: PartDraft, options: PartOptions = {}): StructurePart {\n const { id, role, material, aabb, y0, y1 } = draft\n if (this.ids.has(id)) throw new Error(`Part repeated in the structure: ${id}`)\n this.ids.add(id)\n const { floor, fill, ...extras } = options\n const volume = Math.max(0, (aabb[2] - aabb[0]) * (aabb[3] - aabb[1]) * (y1 - y0)) * (fill ?? 1)\n const part: StructurePart = {\n id, role, material, aabb: aabb.map(round2) as Rect, y0: round2(y0), y1: round2(y1), floor: floor ?? 0,\n mass: Math.max(1, Math.round(volume * densityOf(material))),\n }\n for (const [key, value] of Object.entries(extras)) if (value !== undefined) (part as unknown as Record<string, unknown>)[key] = value\n this.parts.push(part)\n return part\n }\n\n rest(part: StructurePart | string, on: StructurePart | string, joint: JointKind): void {\n const id = typeof part === 'string' ? part : part.id\n const base = typeof on === 'string' ? on : on.id\n this.supports.push({ part: id, on: base === GROUND ? GROUND : base, joint })\n }\n\n has(id: string): boolean {\n return this.ids.has(id)\n }\n\n find(id: string): StructurePart | undefined {\n return this.parts.find((part) => part.id === id)\n }\n}\n","/** The string hash of the floor plan engine (`engine.hashString`), copied so that this package never imports the engine at run time. */\nexport function hashLegacyKey(key: string): number {\n let hash = 1779033703 ^ key.length\n for (let i = 0; i < key.length; i++) {\n hash = Math.imul(hash ^ key.charCodeAt(i), 3432918353)\n hash = (hash << 13) | (hash >>> 19)\n }\n hash = Math.imul(hash ^ (hash >>> 16), 2246822507)\n hash = Math.imul(hash ^ (hash >>> 13), 3266489909)\n return (hash ^ (hash >>> 16)) >>> 0\n}\n","import type { MaterialId } from '@adatechnology/game-contracts'\n\nimport { unionOf, wallBox, round2 } from '../geometry'\nimport { CONSTRUCTION_SYSTEMS } from '../registry'\nimport type { ConstructionSystemDef } from '../registry'\nimport { GROUND } from '../types'\nimport type { Construction, PartRole, Rect, Roof, StructureExtras, StructurePart, StructureSource, WaterTank, SourceWall } from '../types'\nimport { StructureBuilder } from './builder'\nimport { hashLegacyKey } from './legacy-key'\n\nexport const OPEN_ROOM_TYPES: readonly string[] = ['balcony', 'terrace', 'porch']\nconst GUARD_HEIGHT = 1.1\n\nexport interface BuildWall extends SourceWall {\n id: string\n /** The id the Visor de casas 3D gave the wall (`w<floor>_<index>`); seeded choices hash it so old seeds keep their draws. */\n legacyKey: string\n role: PartRole\n material: MaterialId\n box: Rect\n}\n\nexport interface PorchPosts {\n posts: StructurePart[]\n ceilingY: number\n}\n\ntype Base = StructurePart | typeof GROUND | undefined\n\n/** Everything the steps that build the structure share: the plan, the construction, the parts so far and what each storey rests on. */\nexport interface BuildContext {\n source: StructureSource\n construction: Construction\n system: ConstructionSystemDef\n extras: StructureExtras\n tank: WaterTank | null\n builder: StructureBuilder\n porchRoofOnPostsOnly: boolean\n /** Gable roofs are built as rafters of each side plus a ridge beam, so a side falls with the wall it rests on. */\n rafterRoof: boolean\n floorCount: number\n isUnit: boolean\n elevation: number\n isTimber: boolean\n walls: BuildWall[]\n wallParts: Map<string, StructurePart>\n carriers: Map<number, StructurePart[]>\n plates: Map<number, StructurePart[]>\n pillars: Map<number, StructurePart[]>\n porches: Map<string, PorchPosts>\n base0: Base\n houseBox: Rect\n topBox: Rect\n hasBasement: boolean\n topSlab?: StructurePart\n ceilingJoists?: StructurePart[]\n roof: Roof\n level(floor: number): number\n ceilingOf(floor: number): number\n topOf(floor: number): number\n rectsOf(floor: number, exclude?: readonly string[]): Rect[]\n baseOf(floor: number): Base\n}\n\nexport interface ContextOptions {\n porchRoofOnPostsOnly: boolean\n rafterRoof: boolean\n}\n\nexport function createContext(source: StructureSource, construction: Construction, extras: StructureExtras, tank: WaterTank | null, options: ContextOptions): BuildContext {\n const system = CONSTRUCTION_SYSTEMS.get(construction.system)\n if (!system) throw new Error(`Unknown construction system \"${construction.system}\"`)\n const floorCount = source.floors.length\n const isUnit = source.floorNumber !== undefined\n const elevation = construction.foundation.elevation || 0\n const level = (floor: number): number => round2(elevation + (source.floors[floor]?.y0 ?? 0))\n const ceilingOf = (floor: number): number => source.floors[floor]?.ceiling ?? 0\n const topOf = (floor: number): number => (floor < floorCount - 1 && !isUnit ? level(floor + 1) - system.slabThickness : level(floor) + ceilingOf(floor))\n const rectsOf = (floor: number, exclude: readonly string[] = []): Rect[] =>\n source.rooms.filter((room) => room.floor === floor && !exclude.includes(room.type)).flatMap((room) => room.parts)\n const builder = new StructureBuilder()\n const context: BuildContext = {\n source, construction, system, extras, tank, builder, porchRoofOnPostsOnly: options.porchRoofOnPostsOnly, rafterRoof: options.rafterRoof, floorCount, isUnit, elevation, isTimber: system.timber,\n walls: [], wallParts: new Map(), carriers: new Map(), plates: new Map(), pillars: new Map(), porches: new Map(), base0: GROUND,\n houseBox: [0, 0, 0, 0], topBox: [0, 0, 0, 0], hasBasement: false,\n roof: { shape: 'slab', covering: '', material: '', pitch: 0, bearingFloor: 0, panes: [], trusses: 0 },\n level, ceilingOf, topOf, rectsOf,\n baseOf: (floor) => (floor === 0 ? context.base0 : builder.find(`slab_${floor}`)),\n }\n const closed = rectsOf(0, ['balcony', 'porch'])\n context.houseBox = unionOf(closed.length ? closed : rectsOf(0))\n context.walls = classifyWalls(context)\n return context\n}\n\nconst isBearingOnTop = (wall: BuildWall, walls: readonly BuildWall[]): boolean => {\n const along = (w: SourceWall, pick: (a: number, b: number) => number): number => (w.axis === 'u' ? pick(w.u0, w.u1) : pick(w.v0, w.v1))\n const across = (w: SourceWall): number => (w.axis === 'u' ? w.v0 : w.u0)\n return walls.some(\n (other) =>\n other.floor === wall.floor + 1 && other.type === 'wall' && other.axis === wall.axis && Math.abs(across(other) - across(wall)) < 0.2 &&\n Math.min(along(wall, Math.max), along(other, Math.max)) - Math.max(along(wall, Math.min), along(other, Math.min)) > 0.3,\n )\n}\n\nfunction roleOf(context: BuildContext, wall: BuildWall, walls: readonly BuildWall[], porchIds: ReadonlySet<string>): PartRole {\n if (wall.type === 'railing') return 'partition'\n const { wallRole } = context.system\n if (wallRole === 'bearing') return 'wall'\n if (wallRole === 'partition') return 'partition'\n const bearingFloor = context.construction.roof.bearingFloor ?? context.floorCount - 1\n if (wall.floor > bearingFloor) return 'partition'\n if (wall.exterior || wall.sides.some((id) => porchIds.has(id))) return 'wall'\n return wall.floor < context.floorCount - 1 && isBearingOnTop(wall, walls) ? 'wall' : 'partition'\n}\n\nfunction materialOf(context: BuildContext, wall: BuildWall): MaterialId {\n const { walls, guard } = context.construction\n if (wall.type === 'railing') return guard ?? (context.isTimber ? 'wood_soft' : 'steel')\n if (walls.mixed?.length) return walls.mixed[hashLegacyKey(wall.legacyKey) % walls.mixed.length] as MaterialId\n return wall.exterior ? walls.material : (walls.interior ?? walls.material)\n}\n\nfunction classifyWalls(context: BuildContext): BuildWall[] {\n const countByFloor = new Map<number, number>()\n const all: BuildWall[] = context.source.walls.map((wall) => {\n const index = countByFloor.get(wall.floor) ?? 0\n countByFloor.set(wall.floor, index + 1)\n return { ...wall, id: `wall_${wall.floor}_${index}`, legacyKey: `w${wall.floor}_${index}`, role: 'wall', material: '', box: wallBox(wall) }\n })\n const built = all.filter((wall) => wall.type === 'wall' || wall.type === 'railing')\n const porchIds = new Set(context.source.rooms.filter((room) => room.type === 'porch').map((room) => room.id))\n for (const wall of built) {\n wall.role = roleOf(context, wall, built, porchIds)\n wall.material = materialOf(context, wall)\n }\n return built\n}\n\nexport const guardHeightOf = (wall: BuildWall): number => wall.h || GUARD_HEIGHT\n","import { GROUND } from '../types'\nimport { unionOf } from '../geometry'\nimport type { BuildContext } from './context'\n\n/** Cantilevered balconies: a slab tied to the floor of its storey, or on a pillar of its own when it is at ground level. */\nexport function addBalconies(context: BuildContext): void {\n const { builder, construction, system } = context\n for (const room of context.source.rooms.filter((r) => r.type === 'balcony' && r.floor >= 0)) {\n const floor = room.floor\n const box = unionOf(room.parts)\n const base = floor === 0 ? undefined : context.baseOf(floor)\n const deck = builder.add({ id: `slab_${floor}_${room.id}`, role: 'slab', material: construction.frame.slabs, aabb: box, y0: context.level(floor) - system.slabThickness, y1: context.level(floor) }, { floor })\n if (base) {\n builder.rest(deck, base, system.joints.slab)\n continue\n }\n const pillar = builder.add({ id: `balcony_column_${room.id}`, role: 'column', material: construction.frame.pillars, aabb: [box[0] - 0.08, box[1] - 0.08, box[0] + 0.08, box[1] + 0.08], y0: 0, y1: context.level(floor) - system.slabThickness }, { floor: 0 })\n builder.rest(pillar, GROUND, 'rebar')\n builder.rest(deck, pillar, 'rebar')\n }\n}\n","import { GROUND } from '../types'\nimport type { Construction, Rect, Roof, Structure, StructureExtras } from '../types'\nimport { StructureBuilder } from './builder'\n\nconst GROUNDSHEET = 0.02\n\n/** Camping tents: canvas over aluminium poles, a plastic groundsheet and pegs with guy ropes; no walls. */\nexport function buildCanvasStructure(construction: Construction, extras: StructureExtras): Structure {\n const builder = new StructureBuilder()\n const panes: string[] = []\n for (const tent of extras.tents ?? []) {\n const [u0, v0, u1, v1] = tent.aabb\n const centreU = (u0 + u1) / 2\n const centreV = (v0 + v1) / 2\n const sheet = builder.add({ id: `groundsheet_${tent.id}`, role: 'slab', material: 'plastic', aabb: tent.aabb, y0: 0, y1: GROUNDSHEET }, { floor: 0, tent: tent.id })\n builder.rest(sheet, GROUND, 'resting')\n const canvas = builder.add({ id: `canvas_${tent.id}`, role: 'roof', material: 'fabric', aabb: tent.aabb, y0: GROUNDSHEET, y1: tent.height }, { floor: 0, fill: 0.04, tent: tent.id, form: tent.kind })\n panes.push(canvas.id)\n const poles: [Rect, number][] =\n tent.kind === 'tunnel'\n ? [0.25, 0.75].map((fraction, k): [Rect, number] => [[u0 + (u1 - u0) * fraction - 0.015, v0 + 0.05, u0 + (u1 - u0) * fraction + 0.015, v1 - 0.05], k])\n : [[[u0 + 0.05, centreV - 0.015, u1 - 0.05, centreV + 0.015], 0], [[centreU - 0.015, v0 + 0.05, centreU + 0.015, v1 - 0.05], 1]]\n for (const [aabb, k] of poles) {\n const pole = builder.add({ id: `pole_${tent.id}_${k}`, role: 'column', material: construction.frame.pillars, aabb, y0: GROUNDSHEET, y1: tent.height - GROUNDSHEET }, { floor: 0, fill: 0.05, tent: tent.id })\n builder.rest(pole, GROUND, 'resting')\n builder.rest(canvas, pole, 'tie')\n }\n const corners: [number, number][] = [[u0 - 0.2, v0 - 0.2], [u1 + 0.2, v0 - 0.2], [u0 - 0.2, v1 + 0.2], [u1 + 0.2, v1 + 0.2]]\n corners.forEach(([u, v], k) => {\n const peg = builder.add({ id: `peg_${tent.id}_${k}`, role: 'column', material: 'wood_soft', aabb: [u - 0.02, v - 0.02, u + 0.02, v + 0.02], y0: 0, y1: 0.2 }, { floor: 0 })\n builder.rest(peg, GROUND, 'nail')\n builder.rest(canvas, peg, 'tie')\n })\n }\n const roof: Roof = { shape: 'tent', covering: 'canvas', material: 'fabric', pitch: 0, bearingFloor: 0, panes, trusses: 0 }\n return { parts: builder.parts, supports: builder.supports, levels: [0], elevation: 0, roof, construction, framed: false, openings: [] }\n}\n","import { GROUND } from '../types'\nimport { round2, touches } from '../geometry'\nimport type { BuildContext } from './context'\n\nconst CHIMNEY_CLEARANCE_ABOVE_RIDGE = 0.6\n\n/** A masonry chimney or a stove flue next to the house, tied to the wall it touches, rising above the ridge. */\nexport function addChimney(context: BuildContext): void {\n const chimney = context.extras.chimney\n if (!chimney) return\n const { builder } = context\n const top = context.floorCount - 1\n const ridge = context.roof.ridge || context.level(top) + context.ceilingOf(top)\n const height = Math.max(ridge, chimney.top || 0) + CHIMNEY_CLEARANCE_ABOVE_RIDGE\n const part = builder.add({ id: 'chimney', role: 'column', material: chimney.material || 'brick', aabb: chimney.aabb, y0: chimney.flue ? context.level(0) : 0, y1: height }, { floor: 0, fill: chimney.flue ? 0.15 : 0.7 })\n if (chimney.flue) builder.rest(part, context.base0 ?? GROUND, 'resting')\n else builder.rest(part, GROUND, 'mortar')\n const walls = builder.parts.filter((wall) => wall.role === 'wall' && wall.floor === 0 && !wall.id.startsWith('basement') && touches(wall.aabb, part.aabb, 0.1))\n for (const wall of walls) builder.rest(part, wall, 'bolt')\n chimney.height = round2(height)\n}\n\n/** The stone mouth of a well. */\nexport function addWell(context: BuildContext): void {\n const well = context.extras.well\n if (!well) return\n const part = context.builder.add({ id: 'well', role: 'column', material: 'stone', aabb: well.aabb, y0: -0.5, y1: well.height || 0.9 }, { floor: 0, fill: 0.5 })\n context.builder.rest(part, GROUND, 'mortar')\n}\n","import type { JointKind, MaterialId } from '@adatechnology/game-contracts'\n\nimport { distanceBetween, touches } from '../geometry'\nimport type { Rect, StructurePart } from '../types'\nimport type { BuildContext } from './context'\n\nexport interface JoistOptions {\n floor: number\n box: Rect\n thickness: number\n carriers: readonly StructurePart[]\n material: MaterialId\n joint: JointKind\n suffix?: string\n}\n\nconst JOIST_PITCH = 0.6\n\n/** Joists every 0.6 m under the floor of `floor`, each resting on what touches it from below (or the nearest carrier). */\nexport function addJoists(context: BuildContext, options: JoistOptions): StructurePart[] {\n const { floor, box, thickness, carriers, material, joint, suffix = '' } = options\n const length = box[2] - box[0]\n const depth = box[3] - box[1]\n const alongU = length >= depth\n const span = alongU ? length : depth\n const count = Math.max(2, Math.round(span / JOIST_PITCH) + 1)\n const top = context.level(floor) - thickness * 0.15\n const out: StructurePart[] = []\n for (let k = 0; k < count; k++) {\n const centre = (alongU ? box[0] : box[1]) + 0.05 + (k * (span - 0.1)) / (count - 1)\n const aabb: Rect = alongU ? [centre - 0.025, box[1], centre + 0.025, box[3]] : [box[0], centre - 0.025, box[2], centre + 0.025]\n const joist = context.builder.add({ id: `joist_${floor}${suffix}_${k}`, role: 'beam', material, aabb, y0: context.level(floor) - thickness, y1: top }, { floor, fill: 1, spacing: JOIST_PITCH })\n out.push(joist)\n const below = carriers.filter((carrier) => carrier.y0 <= top + 0.05)\n const touching = below.filter((carrier) => touches(aabb, carrier.aabb, 0.2))\n const pool = below.length ? below : carriers\n const chosen = touching.length ? touching : pool.slice().sort((a, b) => distanceBetween(aabb, a.aabb) - distanceBetween(aabb, b.aabb)).slice(0, 1)\n for (const carrier of chosen) context.builder.rest(joist, carrier, joint)\n }\n return out\n}\n\n/** The deck (floor boards, slab) of `floor` on its joists. */\nexport function addDeck(context: BuildContext, id: string, material: MaterialId, options: Pick<JoistOptions, 'floor' | 'box' | 'thickness' | 'joint'>, joists: readonly StructurePart[]): StructurePart {\n const { floor, box, thickness, joint } = options\n const deck = context.builder.add({ id, role: 'slab', material, aabb: box, y0: context.level(floor) - thickness * 0.15, y1: context.level(floor) }, { floor })\n for (const joist of joists) context.builder.rest(deck, joist, joint)\n return deck\n}\n","import type { StructurePart, Rect } from '../types'\nimport { GROUND } from '../types'\nimport type { BuildContext } from './context'\nimport { addDeck, addJoists } from './floor-deck'\n\nconst raft = (context: BuildContext, thickness: number, material: string): StructurePart => {\n const [u0, v0, u1, v1] = context.houseBox\n const part = context.builder.add({ id: 'foundation_raft', role: 'slab', material, aabb: [u0 - 0.1, v0 - 0.1, u1 + 0.1, v1 + 0.1], y0: 0, y1: thickness }, { floor: 0 })\n context.builder.rest(part, GROUND, 'resting')\n return part\n}\n\n/** A unit in a building: the building's pillars go down to the ground and carry a slab under the unit. */\nfunction addBuildingBase(context: BuildContext): void {\n const { builder, construction, houseBox: box } = context\n const corners: [number, number][] = [[box[0], box[1]], [box[2], box[1]], [box[0], box[3]], [box[2], box[3]]]\n const top = context.level(0) - context.system.slabThickness\n const pillars = corners.map(([u, v], k) => {\n const pillar = builder.add({ id: `building_column_${k}`, role: 'column', material: construction.frame.pillars, aabb: [u - 0.15, v - 0.15, u + 0.15, v + 0.15], y0: 0, y1: top }, { floor: 0 })\n builder.rest(pillar, GROUND, 'rebar')\n return pillar\n })\n const slab = builder.add({ id: 'slab_base', role: 'slab', material: construction.frame.slabs, aabb: box, y0: top, y1: context.level(0) }, { floor: 0 })\n for (const pillar of pillars) builder.rest(slab, pillar, 'rebar')\n context.base0 = slab\n}\n\nfunction addBasement(context: BuildContext): StructurePart[] {\n const { builder, houseBox: box, elevation } = context\n const depth = context.construction.foundation.depth || 2.4\n const floor = builder.add({ id: 'basement_slab', role: 'slab', material: 'concrete', aabb: box, y0: -depth - 0.15, y1: -depth }, { floor: -1 })\n builder.rest(floor, GROUND, 'resting')\n const sides: [string, Rect][] = [\n ['front', [box[0], box[1] - 0.1, box[2], box[1] + 0.1]], ['back', [box[0], box[3] - 0.1, box[2], box[3] + 0.1]],\n ['left', [box[0] - 0.1, box[1], box[0] + 0.1, box[3]]], ['right', [box[2] - 0.1, box[1], box[2] + 0.1, box[3]]],\n ]\n const carried: StructurePart[] = []\n for (const [name, aabb] of sides) {\n const wall = builder.add({ id: `basement_wall_${name}`, role: 'wall', material: 'concrete', aabb, y0: -depth, y1: elevation }, { floor: -1 })\n builder.rest(wall, GROUND, 'rebar')\n builder.rest(wall, floor, 'rebar')\n carried.push(wall)\n }\n const count = Math.max(1, Math.floor((box[2] - box[0]) / 3.0))\n for (let k = 0; k < count; k++) {\n const u = box[0] + ((k + 0.5) * (box[2] - box[0])) / count\n const v = (box[1] + box[3]) / 2\n const column = builder.add({ id: `basement_column_${k}`, role: 'column', material: 'concrete', aabb: [u - 0.15, v - 0.15, u + 0.15, v + 0.15], y0: -depth, y1: elevation - 0.3 }, { floor: -1 })\n builder.rest(column, floor, 'rebar')\n builder.rest(column, GROUND, 'rebar')\n carried.push(column)\n }\n context.hasBasement = true\n return carried\n}\n\n/** Pier footings every ~2 m with a base beam through each line of them (crawl space, piles). */\nfunction addPiers(context: BuildContext): StructurePart[] {\n const { builder, houseBox: box, elevation, construction } = context\n const columns = Math.max(2, Math.ceil((box[2] - box[0]) / 2.0) + 1)\n const rows = Math.max(2, Math.ceil((box[3] - box[1]) / 2.0) + 1)\n const height = Math.max(0.1, elevation - context.system.slabThickness - 0.15)\n const piers: StructurePart[] = []\n for (let j = 0; j < rows; j++) {\n for (let i = 0; i < columns; i++) {\n const u = box[0] + (i * (box[2] - box[0])) / (columns - 1)\n const v = box[1] + (j * (box[3] - box[1])) / (rows - 1)\n const pier = builder.add({ id: `footing_pier_${j}_${i}`, role: 'column', material: construction.foundation.material || 'concrete', aabb: [u - 0.12, v - 0.12, u + 0.12, v + 0.12], y0: 0, y1: height }, { floor: 0 })\n builder.rest(pier, GROUND, 'resting')\n piers.push(pier)\n }\n }\n const alongU = box[2] - box[0] >= box[3] - box[1]\n const beams: StructurePart[] = []\n const lines = alongU ? rows : columns\n for (let line = 0; line < lines; line++) {\n const at = alongU ? box[1] + (line * (box[3] - box[1])) / (rows - 1) : box[0] + (line * (box[2] - box[0])) / (columns - 1)\n const aabb: Rect = alongU ? [box[0], at - 0.07, box[2], at + 0.07] : [at - 0.07, box[1], at + 0.07, box[3]]\n const beam = builder.add({ id: `base_beam_${line}`, role: 'beam', material: construction.frame.timber, aabb, y0: height, y1: elevation - context.system.slabThickness }, { floor: 0 })\n const centre = (q: StructurePart): number => (alongU ? (q.aabb[1] + q.aabb[3]) / 2 : (q.aabb[0] + q.aabb[2]) / 2)\n for (const pier of piers.filter((q) => Math.abs(centre(q) - at) < 0.05)) builder.rest(beam, pier, 'bolt')\n beams.push(beam)\n }\n return beams\n}\n\nfunction addRaisedFloor(context: BuildContext): void {\n const { construction, system, houseBox: box } = context\n const carriers = construction.foundation.type === 'basement' ? addBasement(context) : addPiers(context)\n const thickness = system.slabThickness\n const joists = addJoists(context, { floor: 0, box, thickness, carriers, material: construction.frame.timber, joint: construction.foundation.type === 'basement' ? 'bolt' : 'nail' })\n const deckMaterial = context.isTimber ? (construction.floor.material === 'wood_hard' ? 'wood_hard' : 'plywood') : construction.frame.slabs\n context.base0 = addDeck(context, 'slab_0', deckMaterial, { floor: 0, box, thickness, joint: 'nail' }, joists)\n}\n\n/** Foundation and floor of the ground storey: raft, crawl space, piles, basement, a unit's building base or nothing (strip footing). */\nexport function addFoundation(context: BuildContext): void {\n const { type, material } = context.construction.foundation\n if (context.isUnit) return addBuildingBase(context)\n if (type === 'raft') context.base0 = raft(context, Math.max(0.1, context.elevation), material || 'concrete')\n else if (type === 'crawl_space' || type === 'piles' || type === 'basement') addRaisedFloor(context)\n else if (context.isTimber && type !== 'ground') context.base0 = raft(context, Math.max(0.12, context.elevation), 'concrete')\n}\n","import { GROUND } from '../types'\nimport type { Rect, StructurePart } from '../types'\nimport { round2, touches } from '../geometry'\nimport type { BuildContext, BuildWall } from './context'\n\nconst MAX_GAP_WITHIN_RUN = 3.2\nconst POST_SPACING = 2.4\nconst POST_SIDE = 0.05\n\ninterface Run {\n from: number\n to: number\n walls: BuildWall[]\n}\n\nconst alongOf = (wall: BuildWall, pick: (a: number, b: number) => number): number => (wall.axis === 'u' ? pick(wall.u0, wall.u1) : pick(wall.v0, wall.v1))\nconst acrossOf = (wall: BuildWall): number => (wall.axis === 'u' ? wall.v0 : wall.u0)\n\n/** Continuous runs of exterior wall on one line and height: a plate or bond beam runs along each. */\nfunction runsOf(context: BuildContext, walls: readonly BuildWall[], floor: number): Run[][] {\n const lines = new Map<string, BuildWall[]>()\n for (const wall of walls) {\n if (!wall.exterior || wall.type !== 'wall') continue\n const top = round2(context.wallParts.get(wall.id)!.y1)\n const key = `${floor}|${wall.axis}|${acrossOf(wall).toFixed(2)}|${top.toFixed(2)}`\n lines.set(key, [...(lines.get(key) ?? []), wall])\n }\n return [...lines.values()].map((line) => {\n const sorted = line.slice().sort((a, b) => alongOf(a, Math.min) - alongOf(b, Math.min))\n const runs: Run[] = []\n for (const wall of sorted) {\n const from = alongOf(wall, Math.min)\n const to = alongOf(wall, Math.max)\n const last = runs[runs.length - 1]\n if (last && from - last.to <= MAX_GAP_WITHIN_RUN) {\n last.to = Math.max(last.to, to)\n last.walls.push(wall)\n } else runs.push({ from, to, walls: [wall] })\n }\n return runs\n })\n}\n\n/** Timber posts of a shack: the corner and every ~2.4 m carry the plate; the sheet walls only close. */\nfunction addShackPosts(context: BuildContext, run: Run, plate: StructurePart, floor: number, index: number): StructurePart[] {\n const first = run.walls[0]!\n const across = acrossOf(first)\n const top = context.wallParts.get(first.id)!.y1\n const count = Math.max(1, Math.ceil((run.to - run.from) / POST_SPACING))\n const posts: StructurePart[] = []\n for (let k = 0; k <= count; k++) {\n const along = run.from + ((run.to - run.from) * k) / count\n const [u, v] = first.axis === 'u' ? [along, across] : [across, along]\n const half = 0.05 + POST_SIDE / 2\n const post = context.builder.add({ id: `post_${floor}_${index}_${k}`, role: 'column', material: 'wood_soft', aabb: [u - half, v - half, u + half, v + half], y0: context.level(floor), y1: top }, { floor })\n const base = context.baseOf(floor)\n if (base === GROUND || !base) context.builder.rest(post, GROUND, 'tie')\n else context.builder.rest(post, base, 'nail')\n context.builder.rest(plate, post, 'nail')\n posts.push(post)\n }\n return posts\n}\n\nexport interface PlatesResult {\n plates: StructurePart[]\n pillars: StructurePart[]\n}\n\nfunction addPlates(context: BuildContext, walls: readonly BuildWall[], floor: number): PlatesResult {\n const { builder, system, construction } = context\n const plates: StructurePart[] = []\n const pillars: StructurePart[] = []\n let counter = 0\n for (const runs of runsOf(context, walls, floor)) {\n for (const run of runs) {\n const first = run.walls[0]!\n const half = (first.thickness ?? 0.15) / 2\n const across = acrossOf(first)\n const top = context.wallParts.get(first.id)!.y1\n const aabb: Rect = first.axis === 'u' ? [run.from - half, across - half, run.to + half, across + half] : [across - half, run.from - half, across + half, run.to + half]\n const material = context.isTimber ? construction.frame.timber : construction.frame.beams\n const plate = builder.add({ id: `plate_${floor}_${counter++}`, role: 'beam', material, aabb, y0: top, y1: top + system.plateThickness }, { floor, beamKind: context.isTimber ? 'plate' : 'bond_beam' })\n if (construction.system === 'improvised') pillars.push(...addShackPosts(context, run, plate, floor, counter))\n else for (const wall of run.walls) builder.rest(plate, context.wallParts.get(wall.id)!, system.joints.beam)\n plates.push(plate)\n }\n }\n return { plates, pillars }\n}\n\nfunction cornerPoints(walls: readonly BuildWall[]): [number, number][] {\n const ends = walls\n .filter((wall) => wall.exterior && wall.type === 'wall')\n .flatMap((wall): [number, number, string][] =>\n wall.axis === 'u'\n ? [[Math.min(wall.u0, wall.u1), wall.v0, 'u'], [Math.max(wall.u0, wall.u1), wall.v0, 'u']]\n : [[wall.u0, Math.min(wall.v0, wall.v1), 'v'], [wall.u0, Math.max(wall.v0, wall.v1), 'v']],\n )\n const points: [number, number][] = []\n for (const a of ends) {\n const joinsOtherAxis = ends.some((b) => b[2] !== a[2] && Math.hypot(a[0] - b[0], a[1] - b[1]) < 0.12)\n if (joinsOtherAxis && !points.some((q) => Math.hypot(q[0] - a[0], q[1] - a[1]) < 0.12)) points.push([a[0], a[1]])\n }\n return points\n}\n\n/** Concrete corner pillars of a masonry storey where two exterior walls of different axes meet; they run up to the highest plate they touch. */\nfunction addCornerPillars(context: BuildContext, walls: readonly BuildWall[], floor: number, plates: readonly StructurePart[]): StructurePart[] {\n const { builder } = context\n const topOfFloor = context.topOf(floor)\n return cornerPoints(walls).map(([u, v], k) => {\n const box: Rect = [u - 0.1, v - 0.1, u + 0.1, v + 0.1]\n const top = Math.max(topOfFloor, ...plates.filter((plate) => touches(plate.aabb, box, 0.05)).map((plate) => plate.y0))\n const pillar = builder.add({ id: `column_${floor}_${k}`, role: 'column', material: context.construction.frame.pillars, aabb: box, y0: context.level(floor), y1: top }, { floor })\n const base = context.baseOf(floor)\n builder.rest(pillar, base === GROUND || !base ? GROUND : base, 'rebar')\n for (const plate of plates.filter((p) => touches(p.aabb, pillar.aabb, 0.05))) builder.rest(plate, pillar, 'rebar')\n return pillar\n })\n}\n\n/** Plates (bond beams) over the exterior walls of a storey and, in masonry, the corner pillars; records what carries the storey above. */\nexport function addPlatesAndPillars(context: BuildContext, floor: number): void {\n const walls = context.walls.filter((wall) => wall.floor === floor)\n const { plates, pillars } = addPlates(context, walls, floor)\n if (context.construction.system === 'masonry') pillars.push(...addCornerPillars(context, walls, floor, plates))\n context.pillars.set(floor, pillars)\n context.plates.set(floor, plates)\n const innerBearing = walls.filter((wall) => wall.role === 'wall' && !wall.exterior).map((wall) => context.wallParts.get(wall.id)!)\n context.carriers.set(floor, [...plates, ...pillars, ...innerBearing])\n}\n","import { GROUND } from '../types'\nimport type { Rect, StructurePart } from '../types'\nimport { touches } from '../geometry'\nimport type { BuildContext } from './context'\n\nconst POST_HALF = 0.08\nconst FOOTING_HALF = 0.12\nconst BEAM_DEPTH = 0.2\nconst BEAM_WIDTH = 0.16\n\n/** Footings and posts under the porch roof: two at the front corners and one more in the middle of a wide porch. */\nfunction addPosts(context: BuildContext, porchId: string, rect: Rect, deck: StructurePart, floor: number): StructurePart[] {\n const { builder, construction } = context\n const hasUpperFloor = floor < context.floorCount - 1\n const ceilingY = hasUpperFloor ? context.level(floor + 1) - context.system.slabThickness : context.level(floor) + context.ceilingOf(floor)\n const deckDepth = Math.min(0.2, Math.max(0.06, context.elevation * 0.5))\n const spots: [number, number][] = [[rect[0] + 0.1, rect[1] + 0.1], [rect[2] - 0.1, rect[1] + 0.1]]\n if (rect[2] - rect[0] > 4.5) spots.push([(rect[0] + rect[2]) / 2, rect[1] + 0.1])\n const posts = spots.map(([u, v], k) => {\n const footing = builder.add({ id: `porch_footing_${porchId}_${k}`, role: 'column', material: 'concrete', aabb: [u - FOOTING_HALF, v - FOOTING_HALF, u + FOOTING_HALF, v + FOOTING_HALF], y0: 0, y1: context.level(floor) - deckDepth }, { floor: 0 })\n builder.rest(footing, GROUND, 'resting')\n builder.rest(deck, footing, 'resting')\n const material = context.isTimber ? construction.frame.timber : construction.frame.pillars\n const post = builder.add({ id: `porch_post_${porchId}_${k}`, role: 'column', material, aabb: [u - POST_HALF, v - POST_HALF, u + POST_HALF, v + POST_HALF], y0: context.level(floor), y1: hasUpperFloor ? ceilingY - BEAM_DEPTH : ceilingY }, { floor })\n builder.rest(post, deck, context.isTimber ? 'nail' : 'rebar')\n return post\n })\n context.porches.set(porchId, { posts, ceilingY })\n return posts\n}\n\n/** With a storey above the porch, a head beam over the posts and two side beams carry the floor of that storey. */\nfunction addUpperBeams(context: BuildContext, porchId: string, rect: Rect, posts: StructurePart[], floor: number): void {\n const { builder, construction } = context\n const material = context.isTimber ? construction.frame.timber : construction.frame.beams\n const joint = context.isTimber ? 'nail' : 'rebar'\n const ceilingY = context.porches.get(porchId)!.ceilingY\n const y0 = ceilingY - BEAM_DEPTH\n const carriers = context.carriers.get(floor)!\n const head = builder.add({ id: `porch_beam_${porchId}`, role: 'beam', material, aabb: [rect[0], rect[1], rect[2], rect[1] + BEAM_WIDTH], y0, y1: ceilingY }, { floor })\n for (const post of posts) builder.rest(head, post, joint)\n carriers.push(head)\n const sides: [string, Rect, StructurePart][] = [['e', [rect[0], rect[1], rect[0] + BEAM_WIDTH, rect[3]], posts[0]!], ['d', [rect[2] - BEAM_WIDTH, rect[1], rect[2], rect[3]], posts[1]!]]\n for (const [name, aabb, post] of sides) {\n const side = builder.add({ id: `porch_beam_${porchId}_${name}`, role: 'beam', material, aabb, y0, y1: ceilingY }, { floor })\n builder.rest(side, post, joint)\n builder.rest(side, head, joint)\n for (const wall of context.walls.filter((w) => w.floor === floor && w.role === 'wall' && touches(w.box, side.aabb, 0.3))) builder.rest(side, context.wallParts.get(wall.id)!, joint)\n carriers.push(side)\n }\n}\n\n/** Deck, footings, posts (concrete in masonry, wood in timber houses) and, with a storey above, the beams of every porch of the storey. */\nexport function addPorches(context: BuildContext, floor: number): void {\n const { builder, construction } = context\n for (const room of context.source.rooms.filter((r) => r.type === 'porch' && r.floor === floor)) {\n const rect = room.parts[0]!\n const base = context.baseOf(floor)\n const deckDepth = Math.min(0.2, Math.max(0.06, context.elevation * 0.5))\n const deck = builder.add({ id: `porch_floor_${room.id}`, role: 'slab', material: context.isTimber ? 'wood_soft' : construction.frame.slabs, aabb: rect, y0: context.level(floor) - deckDepth, y1: context.level(floor) }, { floor })\n if (base && base !== GROUND) builder.rest(deck, base, context.isTimber ? 'nail' : context.system.joints.slab)\n const posts = addPosts(context, room.id, rect, deck, floor)\n if (floor < context.floorCount - 1) addUpperBeams(context, room.id, rect, posts, floor)\n }\n}\n","import { ROOF_COVERINGS } from '../registry'\nimport type { BuildContext } from './context'\n\nconst ROOF_RISE = 0.6\n\n/** A porch under the top storey has a roof of its own, resting on its posts and on the wall of the house. */\nexport function addPorchRoofs(context: BuildContext): void {\n const { builder, construction } = context\n for (const room of context.source.rooms.filter((r) => r.type === 'porch')) {\n const floor = room.floor\n const rect = room.parts[0]!\n const posts = context.porches.get(room.id)\n if (floor !== context.floorCount - 1 || !posts) continue\n const material = ROOF_COVERINGS.get(construction.roof.covering)?.material ?? 'ceramic'\n const roof = builder.add({ id: `porch_roof_${room.id}`, role: 'roof', material, aabb: [rect[0] - 0.3, rect[1] - 0.5, rect[2] + 0.3, rect[3]], y0: posts.ceilingY, y1: posts.ceilingY + ROOF_RISE }, { floor })\n for (const post of posts.posts) builder.rest(roof, post, context.isTimber ? 'nail' : 'bolt')\n const housewalls = context.walls.filter((w) => w.floor === floor && !w.exterior && w.sides.includes(room.id) && w.type === 'wall')\n for (const wall of housewalls) {\n if (context.porchRoofOnPostsOnly) builder.supports.push({ part: roof.id, on: wall.id, joint: 'nail', bears: false })\n else builder.rest(roof, context.wallParts.get(wall.id)!, 'nail')\n }\n }\n}\n","import type { JointKind } from '@adatechnology/game-contracts'\n\nimport { distanceBetween, round2, touches, unionOf } from '../geometry'\nimport { ROOF_COVERINGS } from '../registry'\nimport type { Rect, RoofPane, StructurePart } from '../types'\nimport type { BuildContext } from './context'\nimport { OPEN_ROOM_TYPES } from './context'\n\nconst TRUSS_PITCH = 1.2\nconst DEFAULT_PITCH = 20\nconst DEFAULT_EAVE = 0.4\nconst CLOSED_ONLY: readonly string[] = [...OPEN_ROOM_TYPES, 'void']\n\ninterface RoofUnit {\n suffix: string\n box: Rect\n floor: number\n annex: boolean\n}\n\n/** The main roof, plus an own roof for every room of a lower storey that the storey above does not cover (a ground floor wider than the upper one). */\nfunction roofUnits(context: BuildContext, bearing: number): RoofUnit[] {\n const units: RoofUnit[] = [{ suffix: '', box: context.topBox, floor: bearing, annex: false }]\n if (context.floorCount <= 1 || context.isUnit || bearing !== context.floorCount - 1) return units\n for (let floor = 0; floor < context.floorCount - 1; floor++) {\n const above = context.source.rooms.filter((room) => room.floor === floor + 1).flatMap((room) => room.parts)\n const rooms = context.source.rooms.filter((room) => room.floor === floor && !OPEN_ROOM_TYPES.includes(room.type) && room.type !== 'void' && room.type !== 'elevator')\n for (const room of rooms) {\n const area = room.parts.reduce((total, part) => total + (part[2] - part[0]) * (part[3] - part[1]), 0)\n const covered = room.parts.reduce((total, part) => total + above.reduce((sum, other) => sum + Math.max(0, Math.min(part[2], other[2]) - Math.max(part[0], other[0])) * Math.max(0, Math.min(part[3], other[3]) - Math.max(part[1], other[1])), 0), 0)\n if (covered < area * 0.7) units.push({ suffix: `_${room.id}`, box: unionOf(room.parts), floor, annex: true })\n }\n }\n return units\n}\n\n/** Everything that carries the roof of one unit: the plates at its height, the pillars and the inner bearing walls under it. */\nfunction roofCarriers(context: BuildContext, unit: RoofUnit): StructurePart[] {\n const platesHere = context.plates.get(unit.floor) ?? []\n const allPlates = [...context.plates.values()].flat()\n const eaveHeight = platesHere.length ? Math.max(...platesHere.map((plate) => plate.y1)) : 0\n const plates = allPlates.filter((plate) => Math.abs(plate.y1 - eaveHeight) < 0.4 && touches(plate.aabb, unit.box, 0.3))\n const pillars = (context.pillars.get(unit.floor) ?? []).filter((pillar) => touches(pillar.aabb, unit.box, 0.3))\n const walls = context.walls.filter((wall) => wall.floor === unit.floor && wall.role === 'wall' && !wall.exterior && touches(wall.box, unit.box, 0.2)).map((wall) => context.wallParts.get(wall.id)!)\n return [...plates, ...pillars, ...walls]\n}\n\nfunction addFlatRoof(context: BuildContext, unit: RoofUnit, carriers: StructurePart[]): RoofPane {\n const { builder, construction, system } = context\n const top = context.level(unit.floor) + context.ceilingOf(unit.floor)\n const [u0, v0, u1, v1] = unit.box\n const slab = builder.add({ id: `slab_top${unit.suffix}`, role: 'slab', material: construction.frame.slabs, aabb: [u0 - 0.15, v0 - 0.15, u1 + 0.15, v1 + 0.15], y0: top, y1: top + 0.12 }, { floor: unit.floor, cover: true })\n for (const carrier of carriers.length ? carriers : (context.plates.get(unit.floor) ?? [])) builder.rest(slab, carrier, system.joints.slab)\n if (unit.suffix === '') context.topSlab = slab\n return { id: slab.id, aabb: slab.aabb, y0: slab.y0, y1: slab.y1, flat: true }\n}\n\nfunction addTrusses(context: BuildContext, unit: RoofUnit, carriers: StructurePart[], geometry: GableGeometry): StructurePart[] {\n const { builder, construction, system } = context\n const { box } = unit\n const { axis, length, eave, rise, eaveY } = geometry\n const count = Math.max(2, Math.ceil(length / TRUSS_PITCH) + 1)\n const trusses: StructurePart[] = []\n for (let k = 0; k < count; k++) {\n const at = (axis === 'u' ? box[0] : box[1]) + (k * length) / (count - 1)\n const aabb: Rect = axis === 'u' ? [at - 0.04, box[1] - eave * 0.5, at + 0.04, box[3] + eave * 0.5] : [box[0] - eave * 0.5, at - 0.04, box[2] + eave * 0.5, at + 0.04]\n const truss = builder.add({ id: `truss${unit.suffix}_${k}`, role: 'beam', material: construction.frame.timber, aabb, y0: eaveY, y1: eaveY + rise }, { floor: unit.floor, fill: 0.25 })\n const touching = carriers.filter((carrier) => touches(aabb, carrier.aabb, 0.2) && carrier.role !== 'slab')\n const chosen = touching.length ? touching : carriers.slice().sort((a, b) => distanceBetween(aabb, a.aabb) - distanceBetween(aabb, b.aabb)).slice(0, 2)\n for (const carrier of chosen) builder.rest(truss, carrier, system.joints.truss)\n trusses.push(truss)\n }\n return trusses\n}\n\ninterface GableGeometry {\n axis: 'u' | 'v'\n length: number\n eave: number\n rise: number\n eaveY: number\n}\n\nfunction geometryOf(context: BuildContext, unit: RoofUnit): GableGeometry {\n const { box } = unit\n const roof = context.construction.roof\n const platesHere = context.plates.get(unit.floor) ?? []\n const width = box[2] - box[0]\n const depth = box[3] - box[1]\n const axis = roof.axis ?? (width >= depth ? 'u' : 'v')\n const span = axis === 'u' ? depth : width\n const pitch = unit.annex ? Math.min(roof.pitch || DEFAULT_PITCH, 20) : roof.pitch || DEFAULT_PITCH\n const eaveY = platesHere.length ? Math.max(...platesHere.map((plate) => plate.y1)) : context.level(unit.floor) + context.ceilingOf(unit.floor)\n return { axis, length: axis === 'u' ? width : depth, eave: roof.eave ?? DEFAULT_EAVE, rise: round2((span / 2) * Math.tan((pitch * Math.PI) / 180)), eaveY }\n}\n\ninterface Frames {\n all: StructurePart[]\n sideA: StructurePart[]\n sideB: StructurePart[]\n}\n\n/** Rafters of each side at the truss positions, each resting only on what is under its own side, and a ridge beam that rests on all of them. */\nfunction addRafters(context: BuildContext, unit: RoofUnit, carriers: StructurePart[], geometry: GableGeometry): Frames {\n const { builder, construction, system } = context\n const { box } = unit\n const { axis, length, eave, rise, eaveY } = geometry\n const count = Math.max(2, Math.ceil(length / TRUSS_PITCH) + 1)\n const middle = axis === 'u' ? (box[1] + box[3]) / 2 : (box[0] + box[2]) / 2\n const frames: Frames = { all: [], sideA: [], sideB: [] }\n for (let k = 0; k < count; k++) {\n const at = (axis === 'u' ? box[0] : box[1]) + (k * length) / (count - 1)\n const halves: [string, Rect][] =\n axis === 'u'\n ? [['a', [at - 0.04, box[1] - eave * 0.5, at + 0.04, middle]], ['b', [at - 0.04, middle, at + 0.04, box[3] + eave * 0.5]]]\n : [['a', [box[0] - eave * 0.5, at - 0.04, middle, at + 0.04]], ['b', [middle, at - 0.04, box[2] + eave * 0.5, at + 0.04]]]\n for (const [side, aabb] of halves) {\n const rafter = builder.add({ id: `rafter${unit.suffix}_${side}_${k}`, role: 'beam', material: construction.frame.timber, aabb, y0: eaveY, y1: eaveY + rise }, { floor: unit.floor, fill: 0.25 })\n const touching = carriers.filter((carrier) => touches(aabb, carrier.aabb, 0.2) && carrier.role !== 'slab')\n const chosen = touching.length ? touching : carriers.slice().sort((x, y) => distanceBetween(aabb, x.aabb) - distanceBetween(aabb, y.aabb)).slice(0, 2)\n for (const carrier of chosen) builder.rest(rafter, carrier, system.joints.truss)\n frames.all.push(rafter)\n if (side === 'a') frames.sideA.push(rafter)\n else frames.sideB.push(rafter)\n }\n }\n if (!unit.annex) {\n const ridgeBox: Rect = axis === 'u' ? [box[0] - eave, middle - 0.05, box[2] + eave, middle + 0.05] : [middle - 0.05, box[1] - eave, middle + 0.05, box[3] + eave]\n const ridge = builder.add({ id: `ridge${unit.suffix}`, role: 'beam', material: construction.frame.timber, aabb: ridgeBox, y0: eaveY + rise - 0.12, y1: eaveY + rise }, { floor: unit.floor })\n for (const rafter of frames.all) builder.rest(ridge, rafter, system.joints.truss)\n }\n context.roof.trusses += count\n return frames\n}\n\nfunction panesOf(unit: RoofUnit, geometry: GableGeometry): Rect[] {\n const [u0, v0, u1, v1] = unit.box\n const { eave, axis } = geometry\n if (unit.annex) return [[u0 - eave, v0 - eave, u1 + eave, v1 + eave]]\n const midV = (v0 + v1) / 2\n const midU = (u0 + u1) / 2\n return axis === 'u'\n ? [[u0 - eave, v0 - eave, u1 + eave, midV], [u0 - eave, midV, u1 + eave, v1 + eave]]\n : [[u0 - eave, v0 - eave, midU, v1 + eave], [midU, v0 - eave, u1 + eave, v1 + eave]]\n}\n\nfunction coarseFrames(context: BuildContext, unit: RoofUnit, carriers: StructurePart[], geometry: GableGeometry): Frames {\n const trusses = addTrusses(context, unit, carriers, geometry)\n context.roof.trusses += trusses.length\n return { all: trusses, sideA: trusses, sideB: trusses }\n}\n\nfunction addGableRoof(context: BuildContext, unit: RoofUnit, carriers: StructurePart[], covering: JointKind): RoofPane[] {\n const { builder, construction } = context\n const geometry = geometryOf(context, unit)\n const frames: Frames = context.rafterRoof ? addRafters(context, unit, carriers, geometry) : coarseFrames(context, unit, carriers, geometry)\n const panes: RoofPane[] = []\n panesOf(unit, geometry).forEach((aabb, k) => {\n const name = unit.annex ? 'annex' : k === 0 ? 'a' : 'b'\n const options = { floor: unit.floor, fill: construction.roof.covering === 'colonial' ? 0.12 : 0.05, ...(construction.roof.pitch === undefined ? {} : { pitch: construction.roof.pitch }) }\n const pane = builder.add({ id: `roof${unit.suffix}_${name}`, role: 'roof', material: construction.roof.material, aabb, y0: geometry.eaveY, y1: geometry.eaveY + geometry.rise + 0.05 }, options)\n const carried = unit.annex || !context.rafterRoof ? frames.all : k === 0 ? frames.sideA : frames.sideB\n for (const frame of carried) builder.rest(pane, frame, covering)\n panes.push({ id: pane.id, aabb: pane.aabb, y0: pane.y0, y1: pane.y1 })\n })\n if (!unit.annex) {\n const roof = context.roof\n roof.axis = geometry.axis\n roof.ridge = round2(geometry.eaveY + geometry.rise)\n roof.eave = geometry.eave\n roof.y0 = round2(geometry.eaveY)\n roof.aabb = [unit.box[0] - geometry.eave, unit.box[1] - geometry.eave, unit.box[2] + geometry.eave, unit.box[3] + geometry.eave].map(round2) as Rect\n }\n return panes\n}\n\n/** Roof of a timber house: ceiling joists every 0.6 m tie the trusses and carry the attic floor. */\nfunction addCeilingJoists(context: BuildContext): void {\n const { builder, construction } = context\n const bearing = context.roof.bearingFloor\n const rects = context.rectsOf(bearing, CLOSED_ONLY)\n const box = unionOf(rects.length ? rects : [context.topBox])\n const carriers = [...(context.plates.get(bearing) ?? []), ...context.walls.filter((w) => w.floor === bearing && w.role === 'wall' && !w.exterior).map((w) => context.wallParts.get(w.id)!)]\n const length = box[2] - box[0]\n const depth = box[3] - box[1]\n const alongU = length >= depth\n const span = alongU ? length : depth\n const count = Math.max(2, Math.round(span / 0.6) + 1)\n const beamTops = carriers.filter((carrier) => carrier.role === 'beam').map((carrier) => carrier.y0)\n const y0 = carriers.length ? Math.max(...beamTops, context.level(bearing) + 1) : context.topOf(bearing)\n const joists: StructurePart[] = []\n for (let k = 0; k < count; k++) {\n const at = (alongU ? box[0] : box[1]) + 0.05 + (k * (span - 0.1)) / (count - 1)\n const aabb: Rect = alongU ? [at - 0.025, box[1], at + 0.025, box[3]] : [box[0], at - 0.025, box[2], at + 0.025]\n const joist = builder.add({ id: `ceiling_joist_${k}`, role: 'beam', material: construction.frame.timber, aabb, y0: y0 - 0.02, y1: y0 + context.system.plateThickness - 0.02 }, { floor: bearing, spacing: 0.6 })\n const beams = carriers.filter((carrier) => carrier.role === 'beam' && touches(aabb, carrier.aabb, 0.2))\n for (const carrier of beams.length ? beams : carriers.slice(0, 2)) builder.rest(joist, carrier, 'nail')\n joists.push(joist)\n }\n context.ceilingJoists = joists\n}\n\n/** The roof over the top storey: a flat slab or trusses and two panes, and the ceiling joists of a timber house. */\nexport function addRoof(context: BuildContext): void {\n const { construction } = context\n const covering = ROOF_COVERINGS.get(construction.roof.covering)\n const bearing = construction.roof.bearingFloor ?? context.floorCount - 1\n const open = context.rectsOf(context.floorCount - 1, OPEN_ROOM_TYPES)\n const topRects = context.rectsOf(context.floorCount - 1, CLOSED_ONLY)\n const body = unionOf(open.length ? open : topRects)\n context.topBox = context.floorCount - 1 === bearing ? body : unionOf(context.rectsOf(bearing, OPEN_ROOM_TYPES))\n context.roof = { shape: construction.roof.shape, covering: construction.roof.covering, material: construction.roof.material, pitch: construction.roof.pitch || 0, bearingFloor: bearing, panes: [], trusses: 0 }\n for (const unit of roofUnits(context, bearing)) {\n const carriers = roofCarriers(context, unit)\n if (construction.roof.shape === 'slab') context.roof.panes.push(addFlatRoof(context, unit, carriers))\n else context.roof.panes.push(...addGableRoof(context, unit, carriers, covering?.joint ?? 'nail'))\n }\n if (context.isTimber && construction.roof.shape !== 'slab') addCeilingJoists(context)\n}\n","import { GROUND } from '../types'\nimport type { StructureSource } from '../types'\nimport type { BuildContext } from './context'\n\ntype StairItem = StructureSource['items'][number]\n\n/** One flight per pair of linked storeys, taken from the item of the lower storey when both are present. */\nfunction flightsOf(items: readonly StairItem[]): Map<string, StairItem> {\n const flights = new Map<string, StairItem>()\n for (const item of items.filter((it) => it.category === 'stairs' && it.link)) {\n const key = `${item.link!.from}_${item.link!.to}`\n if (!flights.has(key) || item.floor === item.link!.from) flights.set(key, item)\n }\n return flights\n}\n\n/** Interior stairs between storeys, resting on the floor below and tied to the one above, plus the basement stairs. */\nexport function addStairs(context: BuildContext): void {\n const { builder, construction } = context\n const material = context.isTimber ? construction.frame.timber : (construction.stairs ?? 'concrete')\n for (const [key, item] of flightsOf(context.source.items)) {\n const { from, to } = item.link!\n const flight = builder.add({ id: `stairs_${key}`, role: 'stair', material, aabb: item.aabb!, y0: context.level(from), y1: context.level(to) }, { floor: from, steps: Math.round((context.level(to) - context.level(from)) / 0.18) })\n const base = context.baseOf(from)\n builder.rest(flight, !base || base === GROUND ? GROUND : base, !base || base === GROUND ? 'resting' : context.isTimber ? 'nail' : 'mortar')\n const upper = context.baseOf(to)\n if (upper && upper !== GROUND) builder.rest(flight, upper, context.isTimber ? 'nail' : 'bolt')\n }\n if (!context.hasBasement) return\n const item = context.source.items.find((it) => it.type === 'basement_stairs')\n if (!item?.aabb) return\n const depth = construction.foundation.depth || 2.4\n const flight = builder.add({ id: 'basement_stairs', role: 'stair', material: 'wood_soft', aabb: item.aabb, y0: -depth, y1: context.level(0) }, { floor: -1, steps: Math.round((context.level(0) + depth) / 0.18) })\n builder.rest(flight, builder.find('basement_slab')!, 'resting')\n if (context.base0 && context.base0 !== GROUND) builder.rest(flight, context.base0, 'nail')\n}\n","import type { Opening, Rect, StructurePart } from '../types'\nimport type { BuildContext, BuildWall } from './context'\n\nconst TOLERANCE = 0.02\n/** Height of a door leaf, which the plan does not store (m). */\nexport const DOOR_HEIGHT = 2.1\nconst LINTEL_DEPTH = 0.2\nconst LINTEL_BEARING = 0.2\n\nconst crossOf = (wall: BuildWall): number => (wall.axis === 'u' ? wall.v0 : wall.u0)\nconst alongRange = (wall: BuildWall): [number, number] => (wall.axis === 'u' ? [Math.min(wall.u0, wall.u1), Math.max(wall.u0, wall.u1)] : [Math.min(wall.v0, wall.v1), Math.max(wall.v0, wall.v1)])\n\n/** The windows of the plan, each in the wall it sits in. */\nexport function findOpenings(context: BuildContext): Opening[] {\n const openings: Opening[] = []\n for (const window of context.source.windows ?? []) {\n const from = window.at - window.width / 2\n const to = window.at + window.width / 2\n const wall = context.walls.find((w) => {\n if (w.floor !== window.floor || w.axis !== window.axis || w.type !== 'wall' || Math.abs(crossOf(w) - window.pos) > TOLERANCE) return false\n const [low, high] = alongRange(w)\n return from >= low - TOLERANCE && to <= high + TOLERANCE\n })\n if (!wall) continue\n const base = context.level(window.floor)\n openings.push({ id: window.id, kind: 'window', wall: wall.id, from, to, y0: base + window.y0, y1: base + window.y1 })\n }\n return openings\n}\n\n/**\n * A lintel over every door gap, 0.2 m deep, bearing 0.2 m on the wall at each side (a concrete beam in masonry, a header in timber houses). The bond beam or\n * plate over the door rests on it as well as on the walls beside it.\n */\nexport function addDoorLintels(context: BuildContext): void {\n const { builder, construction, system } = context\n for (const door of context.source.doors.filter((d) => d.a !== undefined && d.type !== 'zipper')) {\n const along = door.axis === 'u' ? door.u : door.v\n const cross = door.axis === 'u' ? door.v : door.u\n const from = along - door.width / 2\n const to = along + door.width / 2\n const beside = context.walls.filter((w) => w.floor === door.floor && w.axis === door.axis && w.type === 'wall' && Math.abs(crossOf(w) - cross) <= TOLERANCE && (Math.abs(alongRange(w)[1] - from) <= 0.05 || Math.abs(alongRange(w)[0] - to) <= 0.05))\n if (!beside.length) continue\n const half = (beside[0]!.thickness ?? 0.15) / 2\n const lo = from - LINTEL_BEARING\n const hi = to + LINTEL_BEARING\n const box: Rect = door.axis === 'u' ? [lo, cross - half, hi, cross + half] : [cross - half, lo, cross + half, hi]\n const y0 = context.level(door.floor) + DOOR_HEIGHT\n const lintel = builder.add({ id: `lintel_${door.id}`, role: 'beam', material: system.timber ? construction.frame.timber : 'concrete', aabb: box, y0, y1: y0 + LINTEL_DEPTH }, { floor: door.floor, ...(system.timber ? {} : { assembly: 'reinforced_concrete' }) })\n for (const wall of beside) builder.rest(lintel, context.wallParts.get(wall.id) as StructurePart, system.joints.beam)\n for (const plate of context.plates.get(door.floor) ?? []) if (overlapsInPlan(plate.aabb, box)) builder.rest(plate, lintel, system.joints.beam)\n }\n}\n\nconst overlapsInPlan = (a: Rect, b: Rect): boolean => a[0] < b[2] && a[2] > b[0] && a[1] < b[3] && a[3] > b[1]\n","import { GROUND } from '../types'\nimport type { Rect } from '../types'\nimport type { BuildContext } from './context'\n\nconst RISER = 0.18\nconst TREAD = 0.28\n\nconst stepCount = (elevation: number): number => Math.max(1, Math.ceil(elevation / RISER))\n\n/** Steps from each porch door down to the ground: concrete in masonry, wood otherwise, resting on the porch floor. */\nfunction addPorchSteps(context: BuildContext): void {\n const { builder } = context\n for (const room of context.source.rooms.filter((r) => r.type === 'porch')) {\n const deck = builder.find(`porch_floor_${room.id}`)\n for (const door of context.source.doors.filter((d) => d.floor === room.floor && d.b === 'outside' && d.a === room.id)) {\n const count = stepCount(context.elevation)\n const depth = count * TREAD\n const aabb: Rect = [door.u - door.width / 2, door.v - depth, door.u + door.width / 2, door.v]\n const flight = builder.add({ id: `steps_${door.id}`, role: 'stair', material: context.isTimber ? 'wood_soft' : 'concrete', aabb, y0: 0, y1: context.level(room.floor) }, { floor: 0, steps: count, door: door.id })\n builder.rest(flight, GROUND, 'resting')\n if (deck) builder.rest(flight, deck, context.isTimber ? 'nail' : 'mortar')\n }\n }\n}\n\nfunction boxOfSteps(door: { u: number; v: number; width: number; axis: string; side?: string }, depth: number): Rect {\n const direction = door.axis === 'u' ? (door.side === 'front' ? -1 : 1) : door.side === 'left' ? -1 : 1\n if (door.axis === 'u') return [door.u - door.width / 2, Math.min(door.v, door.v + direction * depth), door.u + door.width / 2, Math.max(door.v, door.v + direction * depth)]\n return [Math.min(door.u, door.u + direction * depth), door.v - door.width / 2, Math.max(door.u, door.u + direction * depth), door.v + door.width / 2]\n}\n\n/** Steps at the other outside doors of the ground storey when the floor sits above the ground. */\nfunction addDoorSteps(context: BuildContext): void {\n if (context.elevation <= 0.1) return\n const { builder } = context\n const doors = context.source.doors.filter((d) => d.floor === 0 && d.exterior && d.model !== 'steel' && d.type !== 'steps' && d.type !== 'zipper')\n for (const door of doors) {\n const count = stepCount(context.elevation)\n const depth = Math.min(TREAD * count, 0.9)\n const flight = builder.add({ id: `steps_${door.id}`, role: 'stair', material: context.isTimber ? 'wood_soft' : 'concrete', aabb: boxOfSteps(door, depth), y0: 0, y1: context.level(0) }, { floor: 0, steps: count, door: door.id })\n builder.rest(flight, GROUND, 'resting')\n const base = context.base0\n if (base && base !== GROUND) builder.rest(flight, base, context.isTimber ? 'nail' : 'mortar')\n }\n}\n\nexport function addExteriorSteps(context: BuildContext): void {\n addPorchSteps(context)\n addDoorSteps(context)\n}\n","import { GROUND } from '../types'\nimport type { Rect, StructurePart, WaterTank } from '../types'\nimport { touches } from '../geometry'\nimport type { BuildContext } from './context'\n\nconst TANK_FILL = 0.08\n\nconst squareAround = (u: number, v: number, side: number): Rect => [u - side / 2, v - side / 2, u + side / 2, v + side / 2]\n\nfunction addTank(context: BuildContext, tank: WaterTank, floor: number, y0: number): StructurePart {\n return context.builder.add({ id: 'water_tank', role: 'none', material: tank.material ?? 'plastic', aabb: tank.aabb, y0, y1: y0 + tank.h }, { floor, fill: TANK_FILL, liters: tank.capacity })\n}\n\n/** The slab under the roof that carries a tank in the attic or on a raised platform: a ceiling slab on the top plates, pillars and bearing walls. */\nfunction ensureCeilingSlab(context: BuildContext, y: number): StructurePart {\n const { builder, construction, system } = context\n const existing = builder.find('slab_ceiling')\n if (existing) return existing\n const top = context.floorCount - 1\n const box = context.topBox\n const carriers = builder.parts.filter(\n (part) =>\n ((part.role === 'beam' && part.id.startsWith(`plate_${top}_`)) || (part.role === 'column' && part.floor === top) || (part.role === 'wall' && part.floor === top && !part.id.startsWith('basement'))) &&\n touches(box, part.aabb, 0.1),\n )\n const slab = builder.add({ id: 'slab_ceiling', role: 'slab', material: construction.frame.slabs, aabb: box, y0: y - 0.12, y1: y }, { floor: top })\n for (const carrier of carriers) builder.rest(slab, carrier, system.joints.slab)\n return slab\n}\n\nfunction addRaisedPlatform(context: BuildContext, tank: WaterTank): void {\n const { builder, construction } = context\n const platform = tank.platform!\n const top = context.floorCount - 1\n const ceiling = ensureCeilingSlab(context, platform.baseY)\n const pillars = platform.pillars.map((q, k) => {\n const pillar = builder.add({ id: `tank_column_${k}`, role: 'column', material: construction.frame.pillars, aabb: squareAround(q.u, q.v, q.side), y0: platform.baseY, y1: platform.topY - platform.thickness }, { floor: top })\n builder.rest(pillar, ceiling, 'rebar')\n return pillar\n })\n const slab = builder.add({ id: 'tank_slab', role: 'slab', material: construction.frame.slabs, aabb: platform.aabb, y0: platform.topY - platform.thickness, y1: platform.topY }, { floor: top })\n for (const pillar of pillars) builder.rest(slab, pillar, 'rebar')\n builder.rest(addTank(context, tank, top, tank.y), slab, 'resting')\n}\n\nfunction addAtticTank(context: BuildContext, tank: WaterTank): void {\n const { builder } = context\n const top = context.floorCount - 1\n if (!context.isTimber) {\n const ceiling = ensureCeilingSlab(context, tank.y)\n builder.rest(addTank(context, tank, top, tank.y), ceiling, 'resting')\n return\n }\n const supports = context.topSlab ? [context.topSlab] : (context.ceilingJoists ?? builder.parts.filter((part) => part.role === 'beam' && part.id.startsWith(`plate_${top}_`)))\n const y0 = supports[0] ? supports[0].y1 : tank.y - 0.03\n const floor = builder.add({ id: 'attic_floor', role: 'slab', material: 'plywood', aabb: context.topBox, y0, y1: y0 + 0.03 }, { floor: top })\n for (const support of supports) if (touches(floor.aabb, support.aabb, 0.1)) builder.rest(floor, support, 'nail')\n builder.rest(addTank(context, tank, top, tank.y), floor, 'resting')\n}\n\nfunction addSlabTank(context: BuildContext, tank: WaterTank): void {\n const { builder } = context\n const supports = builder.parts.filter((part) => part.role === 'slab' && Math.abs(part.y1 - tank.y) < 0.3 && touches(part.aabb, tank.aabb, 0.1))\n const carrier = supports.sort((a, b) => Math.abs(a.y1 - tank.y) - Math.abs(b.y1 - tank.y))[0] ?? context.topSlab\n const part = addTank(context, tank, tank.floor, tank.y)\n builder.rest(part, carrier ?? GROUND, 'resting')\n}\n\nfunction addTrestleTank(context: BuildContext, tank: WaterTank): void {\n const { builder } = context\n const stand = tank.stand!\n const columns = stand.pillars.map((q, k) => {\n const column = builder.add({ id: `trestle_column_${k}`, role: 'column', material: stand.material, aabb: squareAround(q.u, q.v, q.side), y0: 0, y1: stand.height }, { floor: 0 })\n builder.rest(column, GROUND, stand.baseJoint ?? 'resting')\n return column\n })\n const [u0, v0, u1, v1] = tank.aabb\n const beams = ([[u0 - 0.1, v0 - 0.1, u1 + 0.1, v0 + 0.05], [u0 - 0.1, v1 - 0.05, u1 + 0.1, v1 + 0.1]] as Rect[]).map((aabb, k) => {\n const beam = builder.add({ id: `trestle_beam_${k}`, role: 'beam', material: stand.material, aabb, y0: stand.height - 0.12, y1: stand.height }, { floor: 0 })\n for (const column of columns.filter((c) => touches(beam.aabb, c.aabb, 0.15))) builder.rest(beam, column, stand.joint ?? 'nail')\n return beam\n })\n const part = addTank(context, tank, 0, stand.height)\n for (const beam of beams) builder.rest(part, beam, stand.tie ?? 'resting')\n}\n\n/** The water tank as a part (role `none`: it weighs on what holds it and carries nothing) with whatever holds it up. */\nexport function addWaterTank(context: BuildContext): void {\n const tank = context.tank\n if (!tank) return\n switch (tank.place) {\n case 'slab':\n return addSlabTank(context, tank)\n case 'raised_slab':\n return addRaisedPlatform(context, tank)\n case 'attic':\n return addAtticTank(context, tank)\n case 'trestle':\n return addTrestleTank(context, tank)\n }\n}\n","import { touches, unionOf } from '../geometry'\nimport type { BuildContext } from './context'\nimport { addDeck, addJoists } from './floor-deck'\n\n/** The floor of the storey above `floor`: a concrete slab, or joists and boards in timber, resting on what carries `floor`. */\nexport function addUpperFloor(context: BuildContext, floor: number): void {\n if (floor >= context.floorCount - 1 || context.isUnit) return\n const next = floor + 1\n const rects = context.rectsOf(next, ['balcony', 'porch', 'void'])\n const box = rects.length ? unionOf(rects) : context.houseBox\n const carriers = context.carriers.get(floor)!\n const { system, construction, builder } = context\n const thickness = system.slabThickness\n if (context.isTimber) {\n const joists = addJoists(context, { floor: next, box, thickness, carriers, material: construction.frame.timber, joint: system.joints.beam })\n addDeck(context, `slab_${next}`, construction.frame.slabs, { floor: next, box, thickness, joint: system.joints.slab }, joists)\n return\n }\n const slab = builder.add({ id: `slab_${next}`, role: 'slab', material: construction.frame.slabs, aabb: box, y0: context.level(next) - thickness, y1: context.level(next) }, { floor: next })\n const below = carriers.filter((carrier) => carrier.y0 <= slab.y0 + 0.05)\n const touching = below.filter((carrier) => touches(slab.aabb, carrier.aabb, 0.2))\n for (const carrier of touching.length ? touching : below) builder.rest(slab, carrier, system.joints.slab)\n}\n","import { GROUND } from '../types'\nimport type { StructurePart } from '../types'\nimport type { BuildContext, BuildWall } from './context'\nimport { guardHeightOf, OPEN_ROOM_TYPES } from './context'\n\n/** Highest ceiling among the rooms the wall touches (a double-height room lifts its outer wall to the eave). */\nexport function wallCeiling(context: BuildContext, wall: BuildWall): number {\n const rooms = wall.sides.map((id) => context.source.rooms.find((room) => room.id === id && room.floor === wall.floor)).filter((room) => room !== undefined)\n return Math.max(context.ceilingOf(wall.floor), ...rooms.map((room) => room.ceiling || 0))\n}\n\nfunction wallTop(context: BuildContext, wall: BuildWall, floor: number): number {\n const y0 = context.level(floor)\n if (wall.type === 'railing') return y0 + guardHeightOf(wall)\n const ceiling = wallCeiling(context, wall)\n const height = wall.structureHeight || wall.h || context.ceilingOf(floor)\n if (wall.exterior && floor < context.floorCount - 1 && !context.isUnit && ceiling > context.ceilingOf(floor) + 0.01) return y0 + ceiling\n if (floor === context.floorCount - 1 || context.isUnit) return y0 + Math.max(height, ceiling)\n const top = context.topOf(floor)\n return Math.max(y0 + height, y0 + ceiling > top ? top : y0 + ceiling)\n}\n\n/** What a railing rests on: the slab of its own balcony or the floor of its porch. */\nfunction railingBase(context: BuildContext, wall: BuildWall, floor: number): StructurePart | string | undefined {\n const open = wall.sides\n .map((id) => context.source.rooms.find((room) => room.id === id && room.floor === floor))\n .find((room) => room && (room.type === 'balcony' || room.type === 'porch'))\n if (!open) return context.baseOf(floor)\n return open.type === 'porch' ? `porch_floor_${open.id}` : `slab_${floor}_${open.id}`\n}\n\nconst assemblyOf = (context: BuildContext): string | undefined => context.construction.walls.assembly ?? (context.system.walls || undefined)\n\nfunction addWallPart(context: BuildContext, wall: BuildWall, floor: number): void {\n const { system, builder } = context\n const isRailing = wall.type === 'railing'\n const y0 = context.level(floor)\n const top = wallTop(context, wall, floor)\n const y1 = isRailing ? top : wall.exterior && !wall.gable ? top - system.plateThickness : top\n const framed = system.studs !== undefined && !isRailing\n const part = builder.add(\n { id: wall.id, role: wall.role, material: wall.material, aabb: wall.box, y0, y1: Math.max(y1, y0 + 0.2) },\n { floor, fill: context.isTimber && wall.role === 'wall' ? system.wallFill : 1, ...(framed ? { studs: system.studs } : {}), ...(isRailing ? {} : { assembly: assemblyOf(context) }) },\n )\n context.wallParts.set(wall.id, part)\n const base = isRailing ? railingBase(context, wall, floor) : context.baseOf(floor)\n const joint = isRailing ? 'nail' : system.joints.wall\n if (base === GROUND || (floor === 0 && !base)) builder.rest(part, GROUND, joint)\n else if (base) builder.rest(part, base, joint)\n}\n\n/** One part per wall of the storey, resting on the floor below it (or the ground). */\nexport function addWalls(context: BuildContext, floor: number): void {\n for (const wall of context.walls.filter((w) => w.floor === floor)) addWallPart(context, wall, floor)\n}\n\nexport const isOpenRoomType = (type: string): boolean => OPEN_ROOM_TYPES.includes(type)\n","import { createContext } from './context'\nimport type { BuildContext } from './context'\nimport { addBalconies } from './balconies'\nimport { buildCanvasStructure } from './canvas'\nimport { addChimney, addWell } from './extras'\nimport { addFoundation } from './foundation'\nimport { addPlatesAndPillars } from './plates'\nimport { addPorches } from './porch'\nimport { addPorchRoofs } from './porch-roof'\nimport { addRoof } from './roof'\nimport { addStairs } from './stairs'\nimport { addDoorLintels, findOpenings } from './openings'\nimport { addExteriorSteps } from './steps'\nimport { addWaterTank } from './tank-parts'\nimport { addUpperFloor } from './upper-floor'\nimport { addWalls } from './walls'\nimport { resolveConstruction } from '../construction'\nimport type { Structure, StructureOptions, StructureSource } from '../types'\n\nfunction buildFloors(context: BuildContext): void {\n for (let floor = 0; floor < context.floorCount; floor++) {\n addWalls(context, floor)\n addPlatesAndPillars(context, floor)\n addPorches(context, floor)\n addUpperFloor(context, floor)\n }\n}\n\n/**\n * The structure of a generated plan: every part that carries load (foundation, floors, walls, plates and bond beams, pillars, porch posts, trusses,\n * roof, stairs, tank) with what each rests on. The plan itself is not modified.\n */\nexport function buildStructure(source: StructureSource, options: StructureOptions = {}): Structure {\n const refined = options.wallDetail !== 'coarse'\n const built = options.construction ? { construction: options.construction, extras: options.extras ?? {} } : resolveConstruction(source)\n const construction = built.construction\n const extras = options.extras ?? built.extras ?? {}\n if (construction.system === 'canvas') return buildCanvasStructure(construction, extras)\n const tank = options.tank !== undefined ? options.tank : (source.waterTank ?? null)\n const context = createContext(source, construction, extras, tank, { porchRoofOnPostsOnly: options.porchRoofOnPostsOnly ?? refined, rafterRoof: options.rafterRoof ?? refined })\n addFoundation(context)\n buildFloors(context)\n addBalconies(context)\n addPorchRoofs(context)\n addExteriorSteps(context)\n addStairs(context)\n addRoof(context)\n if (refined) addDoorLintels(context)\n addWaterTank(context)\n addChimney(context)\n addWell(context)\n const levels = source.floors.map((_, floor) => context.level(floor))\n const framed = construction.system === 'masonry' && (context.isUnit || source.style === 'commercial' || context.floorCount >= 3)\n return { parts: context.builder.parts, supports: context.builder.supports, levels, elevation: context.elevation, roof: context.roof, construction, framed, openings: findOpenings(context) }\n}\n","export type ContentGroup = 'food' | 'water' | 'medicine' | 'tool' | 'cleaning' | 'improvised_weapon' | 'clothes' | 'document' | 'utensil' | 'trash'\n\nexport interface ContentEntry {\n itemId: string\n min: number\n max: number\n group: ContentGroup\n pickable: boolean\n weight: number\n}\n\nconst entry = (itemId: string, min: number, max: number, group: ContentGroup, pickable: boolean, weight: number): ContentEntry => ({ itemId, min, max, group, pickable, weight })\n\nconst FRIDGE = [\n entry('water_bottle', 1, 3, 'water', true, 3), entry('milk_carton', 1, 2, 'food', true, 2), entry('eggs', 1, 1, 'food', true, 2), entry('packed_meat', 1, 2, 'food', true, 1.5), entry('fruit', 1, 4, 'food', true, 2),\n entry('yogurt', 1, 3, 'food', true, 1), entry('soda', 1, 2, 'water', true, 1), entry('cheese', 1, 1, 'food', true, 1), entry('insulin', 1, 1, 'medicine', true, 0.4), entry('leftovers', 1, 2, 'food', true, 1),\n]\nconst BEDSIDE = [entry('medicine', 1, 2, 'medicine', true, 2), entry('book', 1, 2, 'document', true, 1.5), entry('charger', 1, 1, 'tool', true, 1), entry('flashlight', 1, 1, 'tool', true, 0.7), entry('glasses', 1, 1, 'tool', true, 0.7)]\nconst WARDROBE = [\n entry('shirt', 2, 6, 'clothes', true, 3), entry('trousers', 1, 4, 'clothes', true, 3), entry('coat', 1, 2, 'clothes', true, 1.5), entry('sneakers', 1, 2, 'clothes', true, 1.5),\n entry('shoes', 1, 2, 'clothes', true, 1), entry('blanket', 1, 2, 'clothes', true, 1.5), entry('backpack', 1, 1, 'tool', true, 0.8),\n]\nconst DRESSER = [entry('underwear', 2, 6, 'clothes', true, 3), entry('socks', 2, 6, 'clothes', true, 2), entry('t_shirt', 1, 4, 'clothes', true, 2), entry('documents', 1, 2, 'document', true, 1), entry('flashlight', 1, 1, 'tool', true, 0.7), entry('batteries', 1, 2, 'tool', true, 0.7)]\nconst FILING = [entry('documents', 1, 4, 'document', true, 3), entry('pen', 1, 3, 'tool', true, 1.5), entry('keys', 1, 2, 'tool', true, 1), entry('stapler', 1, 1, 'improvised_weapon', true, 0.5)]\nconst TRASH = [entry('full_trash_bag', 1, 1, 'trash', false, 2), entry('packaging', 1, 4, 'trash', true, 3), entry('empty_can', 1, 3, 'trash', true, 2), entry('crumpled_paper', 1, 3, 'trash', true, 1)]\n\n/** What each kind of container may hold, by category (or by type when a type differs from its category). */\nexport const CONTENT_TABLES: Record<string, ContentEntry[]> = {\n fridge: FRIDGE,\n display_fridge: [entry('soda', 2, 6, 'water', true, 3), entry('water_bottle', 2, 6, 'water', true, 3), entry('yogurt', 2, 5, 'food', true, 2)],\n freezer: [entry('frozen_meat', 2, 5, 'food', true, 3), entry('ice_cream', 1, 2, 'food', true, 1)],\n kitchen_cabinet: [\n entry('pot', 1, 2, 'tool', true, 1.5), entry('kitchen_knife', 1, 2, 'improvised_weapon', true, 1.5), entry('dish_soap', 1, 2, 'cleaning', true, 2), entry('sponge', 1, 2, 'cleaning', true, 1), entry('rice', 1, 2, 'food', true, 1.5),\n entry('beans', 1, 2, 'food', true, 1.5), entry('pasta', 1, 2, 'food', true, 1), entry('cooking_oil', 1, 1, 'food', true, 1), entry('canned_tuna', 1, 3, 'food', true, 1.5), entry('disinfectant', 1, 1, 'cleaning', true, 1), entry('trash_bag', 1, 2, 'trash', true, 0.7),\n ],\n overhead_cabinet: [entry('plates', 4, 8, 'utensil', false, 3), entry('glasses', 3, 6, 'utensil', false, 3), entry('mug', 1, 3, 'utensil', true, 1.5), entry('coffee', 1, 2, 'food', true, 1.5), entry('canned_corn', 1, 3, 'food', true, 1.5), entry('spices', 1, 3, 'food', true, 1)],\n washbasin: [\n entry('painkiller', 1, 2, 'medicine', true, 2), entry('bandages', 1, 2, 'medicine', true, 2), entry('soap', 1, 3, 'cleaning', true, 2), entry('toilet_paper', 1, 4, 'cleaning', true, 2), entry('shampoo', 1, 2, 'cleaning', true, 1),\n entry('toothbrush', 1, 2, 'cleaning', true, 1), entry('scissors', 1, 1, 'improvised_weapon', true, 0.5), entry('rubbing_alcohol', 1, 1, 'medicine', true, 1),\n ],\n wardrobe: WARDROBE,\n wardrobe_large: WARDROBE,\n dresser: DRESSER,\n console_table: DRESSER,\n nightstand: BEDSIDE,\n filing_cabinet: FILING,\n pantry: [\n entry('rice', 2, 4, 'food', true, 2), entry('beans', 2, 4, 'food', true, 2), entry('canned_tuna', 2, 5, 'food', true, 2), entry('water_jug', 1, 2, 'water', true, 2), entry('flour', 1, 2, 'food', true, 1),\n entry('sugar', 1, 2, 'food', true, 1), entry('cooking_oil', 1, 2, 'food', true, 1), entry('biscuits', 1, 4, 'food', true, 1.5),\n ],\n tv_unit: [entry('remote_control', 1, 1, 'tool', true, 2), entry('dvds', 1, 4, 'document', true, 1), entry('cables', 1, 3, 'tool', true, 1.5), entry('batteries', 1, 2, 'tool', true, 1)],\n laundry_cabinet: [entry('washing_powder', 1, 2, 'cleaning', true, 3), entry('bleach', 1, 2, 'cleaning', true, 2), entry('disinfectant', 1, 2, 'cleaning', true, 2), entry('bucket', 1, 1, 'tool', true, 1), entry('broom', 1, 1, 'improvised_weapon', true, 1), entry('rubber_gloves', 1, 2, 'cleaning', true, 1)],\n laundry_shelf: [entry('washing_powder', 1, 1, 'cleaning', true, 2), entry('softener', 1, 2, 'cleaning', true, 2), entry('clothespins', 1, 1, 'tool', true, 1)],\n workbench: [entry('hammer', 1, 1, 'improvised_weapon', true, 2), entry('screwdriver', 1, 2, 'tool', true, 2), entry('pliers', 1, 1, 'tool', true, 1.5), entry('insulating_tape', 1, 2, 'tool', true, 1), entry('screws', 1, 2, 'tool', true, 1)],\n tool_shelf: [entry('hammer', 1, 1, 'improvised_weapon', true, 1.5), entry('hand_saw', 1, 1, 'improvised_weapon', true, 1), entry('paint_can', 1, 3, 'trash', true, 1.5), entry('rope', 1, 1, 'tool', true, 1), entry('nails', 1, 2, 'tool', true, 1.5)],\n mailbox: [entry('letter', 1, 4, 'document', true, 3), entry('bill', 1, 2, 'document', true, 2), entry('flyer', 1, 4, 'trash', true, 2)],\n trash_bin: TRASH,\n outdoor_bin: TRASH,\n china_cabinet: [entry('china_plates', 3, 6, 'utensil', false, 3), entry('wine_glasses', 2, 5, 'utensil', false, 2)],\n}\n\n/** Groups of things somebody who locked themselves in would have stocked up. */\nexport const SUPPLY_GROUPS: readonly ContentGroup[] = ['food', 'water', 'medicine', 'tool']\n","import type { FindStack } from '@adatechnology/game-floorplan'\n\nimport { CONTENT_TABLES, SUPPLY_GROUPS } from './content-tables'\nimport type { ContentEntry } from './content-tables'\nimport type { Rng } from './shared'\n\nexport interface ContentStack extends FindStack {\n group: string\n pickable: boolean\n}\n\nexport interface ContentQuery {\n /** Category or type of the container (`fridge`, `kitchen_cabinet`, `overhead_cabinet`...). */\n container: string\n state: string\n rng: Rng\n /** Footprint of the container in m2. */\n footprint: number\n}\n\n/** How a state changes what a container holds: how many kinds, how likely each is, how many of each, and what is left over. */\nexport interface ContentStateRule {\n kinds(base: number, available: number, rng: Rng): number\n weight(entry: ContentEntry): number\n extraQuantity(entry: ContentEntry): number\n leftovers?(found: ContentStack[], container: string, rng: Rng): void\n}\n\nconst FRIDGES = ['fridge', 'display_fridge', 'freezer']\nconst isSupply = (entry: ContentEntry): boolean => SUPPLY_GROUPS.includes(entry.group)\n\n/** The normal world is the base; `fortified` and `abandoned` are the genre's rules, kept here until the item catalogue and the genre pack own them. */\nexport const CONTENT_STATES: Record<string, ContentStateRule> = {\n normal: { kinds: (base) => base, weight: (entry) => entry.weight, extraQuantity: () => 0 },\n fortified: { kinds: (base, available) => Math.min(available, base + 2), weight: (entry) => (isSupply(entry) ? entry.weight * 2.5 : entry.weight), extraQuantity: (entry) => (isSupply(entry) ? 1 : 0) },\n abandoned: {\n kinds: (_base, _available, rng) => (rng() < 0.4 ? 0 : 1),\n weight: (entry) => entry.weight,\n extraQuantity: () => 0,\n leftovers(found, container, rng) {\n if (found.length === 0 && rng() < 0.5) found.push({ itemId: 'scraps_and_papers', count: 1, pickable: false, group: 'trash' })\n if (FRIDGES.includes(container)) found.push({ itemId: 'spoiled_food', count: 1, pickable: false, group: 'trash' })\n },\n },\n}\n\nexport function registerContentState(state: string, rule: ContentStateRule): void {\n CONTENT_STATES[state] = rule\n}\n\n/** Weighted draw without replacement. */\nfunction weightedOrder<T extends { weight: number }>(candidates: T[], rng: Rng): T[] {\n const pool = candidates.slice()\n const out: T[] = []\n while (pool.length) {\n let x = rng() * pool.reduce((sum, c) => sum + c.weight, 0)\n let i = 0\n for (; i < pool.length - 1; i++) {\n x -= pool[i]!.weight\n if (x < 0) break\n }\n out.push(pool.splice(i, 1)[0]!)\n }\n return out\n}\n\n/** What a container holds in a state: a few kinds of thing from the table of its category, more of the useful ones when fortified, almost nothing when abandoned. */\nexport function contentOf(query: ContentQuery): ContentStack[] {\n const pool = CONTENT_TABLES[query.container]\n if (!pool) return []\n const rule = CONTENT_STATES[query.state] ?? CONTENT_STATES.normal!\n const { rng } = query\n const base = Math.max(2, Math.min(5, Math.round(1.5 + query.footprint * 3 + rng() * 1.5)))\n const kinds = rule.kinds(base, pool.length, rng)\n const found: ContentStack[] = []\n for (const candidate of weightedOrder(pool.map((entry) => ({ entry, weight: rule.weight(entry) })), rng).slice(0, kinds)) {\n const { entry } = candidate\n const count = entry.min + Math.floor(rng() * (entry.max - entry.min + 1)) + rule.extraQuantity(entry)\n found.push({ itemId: entry.itemId, count, pickable: entry.pickable, group: entry.group })\n }\n rule.leftovers?.(found, query.container, rng)\n return found\n}\n\nexport const hasContent = (container: string): boolean => container in CONTENT_TABLES\n\n","import type { Rect } from '../types'\n\n/** Loosely typed plan data: the engine's own plan and its items (`result.items`), which the utilities read and some of them annotate. */\nexport type Json = any\nexport type Rng = () => number\n\nexport const HALF_WALL = 0.075\nexport const round2 = (value: number): number => Math.round(value * 100) / 100\nexport const clamp = (value: number, low: number, high: number): number => Math.max(low, Math.min(high, value))\n\nexport const overlaps = (a: Rect, b: Rect, epsilon = 1e-6): boolean => a[0] < b[2] - epsilon && a[2] > b[0] + epsilon && a[1] < b[3] - epsilon && a[3] > b[1] + epsilon\n\nexport const inner = (rect: Rect): Rect => [rect[0] + HALF_WALL, rect[1] + HALF_WALL, rect[2] - HALF_WALL, rect[3] - HALF_WALL]\n\n/** A solid item: not a rug, not resting on something, and not decoration unless it stands on the floor. */\nexport const isSolid = (item: Json): boolean => !item.flat && !item.on && (!item.decor || item.mount === 'floor')\n\nexport const distanceToRect = (u: number, v: number, rect: Rect): number => Math.hypot(Math.max(rect[0] - u, 0, u - rect[2]), Math.max(rect[1] - v, 0, v - rect[3]))\n\n/** Room types without sockets, switches or circuits. */\nexport const NO_SOCKET_ROOMS: readonly string[] = ['void', 'elevator', 'stairs', 'balcony', 'terrace', 'porch', 'tent']\n\n/** Unit vector pointing out of the house from a wall (`sides[0]` or `sides[1]` is `outside`). */\nexport const outwardOf = (wall: Json): [number, number] => {\n const sign = wall.sides[0] === 'outside' ? -1 : 1\n return wall.axis === 'u' ? [0, sign] : [sign, 0]\n}\n\nexport const sideNameOf = (vector: [number, number]): string => (Math.abs(vector[0]) > Math.abs(vector[1]) ? (vector[0] > 0 ? 'right' : 'left') : vector[1] > 0 ? 'back' : 'front')\n\nexport const alongRange = (wall: Json): [number, number] => (wall.axis === 'u' ? [Math.min(wall.u0, wall.u1), Math.max(wall.u0, wall.u1)] : [Math.min(wall.v0, wall.v1), Math.max(wall.v0, wall.v1)])\n\n/** Exterior ground-floor wall at least 1 m long, the front one first when there is one (a gas meter and an inverter go on them). */\nexport function groundExteriorWalls(plan: Json): Json[] {\n return plan.walls.filter((wall: Json) => wall.exterior && wall.floor === 0 && wall.type === 'wall' && Math.hypot(wall.u1 - wall.u0, wall.v1 - wall.v0) >= 1.0)\n}\n","import type { Json } from './shared'\nimport { HALF_WALL, isSolid, round2 } from './shared'\n\nexport interface WallPoint {\n u: number\n v: number\n /** Position along the wall. */\n c: number\n axis: 'u' | 'v'\n pos: number\n side: number\n nu: number\n nv: number\n a0: number\n a1: number\n exterior: boolean\n windows: Json[]\n /** A solid item within 12 cm of the point reaches higher than `height`. */\n blocked(height: number): boolean\n}\n\nconst STEP = 0.05\nconst SURFACE_OFFSET = 0.012\n\n/** Points on the inner face of the walls of a room, away from corners (`margin`), where sockets, switches and a panel may go. */\nexport function wallPointsOf(plan: Json, room: Json, items: Json[], margin = 0.3): WallPoint[] {\n const points: WallPoint[] = []\n const windows = plan.windows.filter((w: Json) => w.floor === room.floor)\n const solids = items.filter((m) => m.floor === room.floor && !m.outdoor && m.room === room.id && isSolid(m))\n for (const wall of plan.walls) {\n if (wall.floor !== room.floor || wall.type !== 'wall' || !wall.sides.includes(room.id)) continue\n const side = wall.sides[1] === room.id ? 1 : -1\n const a0 = wall.axis === 'u' ? Math.min(wall.u0, wall.u1) : Math.min(wall.v0, wall.v1)\n const a1 = wall.axis === 'u' ? Math.max(wall.u0, wall.u1) : Math.max(wall.v0, wall.v1)\n const pos = wall.axis === 'u' ? wall.v0 : wall.u0\n const nearby = windows.filter((w: Json) => w.axis === wall.axis && Math.abs(w.pos - pos) < 1e-3 && w.at + w.width / 2 > a0 && w.at - w.width / 2 < a1)\n for (let c = a0 + margin; c <= a1 - margin + 1e-9; c += STEP) {\n const u = wall.axis === 'u' ? c : pos + side * (HALF_WALL + SURFACE_OFFSET)\n const v = wall.axis === 'u' ? pos + side * (HALF_WALL + SURFACE_OFFSET) : c\n points.push({\n u: round2(u), v: round2(v), c: round2(c), axis: wall.axis, pos, side, nu: wall.axis === 'u' ? 0 : side, nv: wall.axis === 'u' ? side : 0, a0, a1, exterior: wall.exterior, windows: nearby,\n blocked: (height) => solids.some((m) => m.aabb && Math.hypot(Math.max(m.aabb[0] - u, 0, u - m.aabb[2]), Math.max(m.aabb[1] - v, 0, v - m.aabb[3])) < 0.12 && (m.y || 0) + m.h > height),\n })\n }\n }\n return points\n}\n\nexport const hasWindowAt = (point: WallPoint, y: number, clearance = 0.2): boolean =>\n point.windows.some((w) => y + 0.1 > w.y0 - 0.05 && y - 0.1 < w.y1 + 0.05 && Math.abs(point.c - w.at) < w.width / 2 + clearance)\n\nexport const atDoor = (plan: Json, room: Json, point: WallPoint, clearance: number): boolean =>\n plan.doors.some((d: Json) => d.floor === room.floor && d.axis === point.axis && Math.abs(d.pos - point.pos) < 1e-3 && Math.abs(d.at - point.c) < d.width / 2 + clearance)\n","import type { Layout } from './electrical'\nimport { keyOf } from './electrical'\nimport type { Json } from './shared'\nimport { distanceToRect } from './shared'\nimport { atDoor, hasWindowAt } from './wall-points'\nimport type { WallPoint } from './wall-points'\n\n/** Categories that need a socket of their own. */\nconst APPLIANCES = ['fridge', 'display_fridge', 'freezer', 'tv', 'appliance', 'washing_machine', 'air_conditioner', 'cash_register', 'table_light']\nconst COUNTERS = ['kitchen_cabinet', 'workbench', 'checkout_counter']\nconst LAMPS = ['table_light', 'lamp']\n\nconst needsSocket = (item: Json): boolean => APPLIANCES.includes(item.category) || item.category === 'shower'\n\ninterface Pick {\n point: WallPoint\n y: number\n score: number\n}\n\n/** Sockets: one for each appliance (the shower heater too), then enough for the size of each room, two at counter height in a kitchen with a counter. */\nexport function addOutlets(layout: Layout): void {\n const { plan, items, rooms, electrical, pointsOf } = layout\n let counter = 0\n const outletsOf = (room: Json): Json[] => electrical.outlets.filter((t) => t.room === room.id && t.floor === room.floor)\n const newOutlet = (room: Json, point: WallPoint, y: number): Json => {\n const outlet = { id: `outlet${++counter}`, room: room.id, floor: room.floor, u: point.u, v: point.v, y, c: point.c, axis: point.axis, pos: point.pos, frontU: point.nu, frontV: point.nv, type: '2P+T', voltage: 127 }\n electrical.outlets.push(outlet)\n return outlet\n }\n const counters = items.filter((m) => COUNTERS.includes(m.category) && !m.outdoor)\n const heightFor = (room: Json, point: WallPoint): number =>\n room.type === 'kitchen' && counters.some((m) => m.floor === room.floor && m.room === room.id && distanceToRect(point.u, point.v, m.aabb) < 0.45) ? 1.1 : 0.3\n const valid = (room: Json, point: WallPoint, y: number): boolean =>\n !hasWindowAt(point, y, 0.25) && !atDoor(plan, room, point, 0.45) && !outletsOf(room).some((t) => Math.hypot(t.u - point.u, t.v - point.v) < 0.5 && t.y === y)\n const pick = (room: Json, score: (point: WallPoint) => number, fixedY: number | null, ignoreBlocked?: boolean): Pick | null => {\n let best: Pick | null = null\n for (const point of pointsOf.get(keyOf(room)) ?? []) {\n const y = fixedY ?? heightFor(room, point)\n if (!valid(room, point, y)) continue\n const total = score(point) + (point.blocked(y) && !ignoreBlocked ? 5 : 0)\n if (!best || total < best.score) best = { point, y, score: total }\n }\n return best\n }\n const roomOf = (item: Json): Json | undefined => rooms.find((x) => x.id === item.room && x.floor === item.floor)\n const appliances = items.filter((m) => !m.outdoor && needsSocket(m) && rooms.some((c) => c.id === m.room && c.floor === m.floor) && m.category !== 'table_light')\n for (const item of appliances) connectAppliance(item)\n function connectAppliance(item: Json): void {\n const room = roomOf(item)!\n const target = item.aabb\n const nearest = outletsOf(room).map((t) => ({ t, d: distanceToRect(t.u, t.v, target) })).filter((o) => o.d <= 1.2 && o.t.y <= 1.1).sort((a, b) => a.d - b.d)[0]\n const isShower = item.category === 'shower'\n let outlet: Json | null = nearest && !isShower ? nearest.t : null\n if (!outlet) {\n const height = isShower ? 1.1 : item.y > 0.7 ? 1.1 : null\n const best = pick(room, (p) => { const d = distanceToRect(p.u, p.v, target); return isShower && d < 0.6 ? 50 + d : d }, height)\n let chosen = best\n if (!isShower && (!best || distanceToRect(best.point.u, best.point.v, target) > 1.4)) {\n const behind = pick(room, (p) => distanceToRect(p.u, p.v, target), item.y > 0.7 ? 1.1 : null, true)\n if (behind && (!best || distanceToRect(behind.point.u, behind.point.v, target) < distanceToRect(best.point.u, best.point.v, target))) chosen = behind\n }\n if (chosen) outlet = newOutlet(room, chosen.point, chosen.y)\n }\n if (!outlet) return\n item.outlet = outlet.id\n if (isShower) item.showerHeater = { electric: true, powerW: 5500, outlet: outlet.id }\n }\n for (const room of rooms) {\n const area = room.parts.reduce((sum: number, q: number[]) => sum + (q[2]! - q[0]!) * (q[3]! - q[1]!), 0)\n const wanted = Math.max(room.type === 'kitchen' ? 3 : 2, Math.min(6, Math.round(area / 7)))\n const farthest = (existing: Json[]) => (p: WallPoint) => -Math.min(9, ...existing.map((t) => Math.hypot(t.u - p.u, t.v - p.v)))\n for (let guard = 0; outletsOf(room).length < wanted && guard < 12; guard++) {\n const best = pick(room, farthest(outletsOf(room)), null)\n if (!best) break\n newOutlet(room, best.point, best.y)\n }\n if (room.type !== 'kitchen' || !counters.some((m) => m.room === room.id)) continue\n for (let guard = 0; outletsOf(room).filter((t) => t.y === 1.1).length < 2 && guard < 4; guard++) {\n const existing = outletsOf(room)\n const best = pick(room, (p) => (heightFor(room, p) === 1.1 ? 0 : 20) - Math.min(9, ...existing.map((t) => Math.hypot(t.u - p.u, t.v - p.v))), 1.1)\n if (!best) break\n newOutlet(room, best.point, 1.1)\n }\n }\n for (const item of appliances) {\n if (item.category === 'shower' || !item.outlet) continue\n const room = roomOf(item)!\n const current = outletsOf(room).find((t) => t.id === item.outlet)\n if (!current || distanceToRect(current.u, current.v, item.aabb) <= 1.2) continue\n const other = outletsOf(room).filter((t) => t.y <= 1.1).map((t) => ({ t, d: distanceToRect(t.u, t.v, item.aabb) })).sort((a, b) => a.d - b.d)[0]\n if (other && other.d < distanceToRect(current.u, current.v, item.aabb) && other.d <= 1.2) item.outlet = other.t.id\n }\n for (const item of items.filter((m) => LAMPS.includes(m.category) && !m.outdoor)) {\n const room = roomOf(item)\n if (!room) continue\n const nearest = outletsOf(room).map((t) => ({ t, d: distanceToRect(t.u, t.v, item.aabb) })).sort((a, b) => a.d - b.d)[0]\n if (nearest) item.outlet = nearest.t.id\n }\n}\n\n","import type { Layout } from './electrical'\nimport { heightOf, keyOf } from './electrical'\nimport type { Json } from './shared'\nimport { clamp, round2 } from './shared'\nimport { atDoor, hasWindowAt } from './wall-points'\n\nconst METER_SIZE = { w: 0.35, d: 0.2, h: 0.5 }\n\nexport const mainDoorOf = (plan: Json): Json | undefined => plan.doors.find((p: Json) => p.floor === 0 && p.exterior && p.side === 'front') || plan.doors.find((p: Json) => p.floor === 0 && p.exterior)\n\n/** Pole, drop, meter and descent: the meter on the gate pillar (or the facade without a gate); an apartment or shop has it on the facade. */\nexport function placeEntrance(layout: Layout): void {\n const { plan, electrical } = layout\n const gate = plan.gates.find((g: Json) => g.type === 'pedestrian')\n const door = mainDoorOf(plan)\n const lot = plan.lot\n if (lot && plan.style !== 'commercial') {\n const rect = lot.rect\n const poleU = clamp(gate ? gate.u + 3 : plan.w / 2, rect[0] + 0.5, rect[2] - 0.5)\n const poleV = rect[1] - 0.6\n let meter: Json\n if (gate) {\n const direction = gate.u - gate.width / 2 - 0.4 >= rect[0] + 0.3 ? -1 : 1\n meter = { place: 'gate_pillar', u: round2(gate.u + direction * (gate.width / 2 + 0.25)), v: round2(gate.v), y: 1.4, side: 'front', ...METER_SIZE }\n } else meter = { place: 'facade', u: round2(door ? door.at + 1.2 : plan.w / 2), v: -0.1, y: 1.4, side: 'front', ...METER_SIZE }\n meter.id = 'meter'\n electrical.serviceEntrance = { pole: { u: round2(poleU), v: round2(poleV), h: 7.5 }, drop: [[round2(poleU), round2(poleV), 6.5], [meter.u, meter.v, 2.6]], meter, descent: [[meter.u, meter.v, 2.6], [meter.u, meter.v, 1.65]], internalRun: null }\n } else if (lot === null || plan.style === 'commercial') {\n const front = door ? { u: round2(door.at + 1.0), v: -0.1 } : { u: round2(plan.w / 2), v: -0.1 }\n electrical.serviceEntrance = {\n pole: { u: round2(front.u + 2), v: -3, h: 7.5 }, drop: [[round2(front.u + 2), -3, 6.5], [front.u, front.v, 3.2]],\n meter: { id: 'meter', place: 'facade', u: front.u, v: front.v, y: 1.4, side: 'front', ...METER_SIZE }, descent: [[front.u, front.v, 3.2], [front.u, front.v, 1.65]], internalRun: null,\n }\n }\n}\n\n/** The distribution panel in the room of the main door, on the wall nearest the meter, clear of doors and windows and of tall furniture. */\nexport function placePanel(layout: Layout): void {\n const { plan, rooms, electrical, pointsOf } = layout\n const door = mainDoorOf(plan)\n const room = (door && rooms.find((c) => c.id === door.a && c.floor === 0)) || rooms.find((c) => c.floor === 0) || rooms[0]\n if (!room) return\n const meter = electrical.serviceEntrance?.meter\n const targetU = meter ? meter.u : plan.w / 2\n const targetV = meter ? Math.max(0, meter.v) : 0\n let best: { point: Json; score: number } | null = null\n for (const point of pointsOf.get(keyOf(room)) ?? []) {\n if (point.blocked(1.5) || hasWindowAt(point, 1.5, 0.3) || atDoor(plan, room, point, 0.8)) continue\n const score = Math.hypot(point.u - targetU, point.v - targetV) + (point.exterior ? 0 : 3)\n if (!best || score < best.score) best = { point, score }\n }\n if (!best) best = { point: (pointsOf.get(keyOf(room)) ?? [])[0] as Json, score: 0 }\n if (best.point) {\n const p = best.point\n electrical.panel = { id: 'panel', room: room.id, floor: room.floor, u: p.u, v: p.v, y: 1.5, c: p.c, axis: p.axis, pos: p.pos, frontU: p.nu, frontV: p.nv, w: 0.3, h: 0.4, breakers: 0 }\n }\n if (electrical.serviceEntrance && electrical.panel) {\n const entrance = electrical.serviceEntrance\n entrance.internalRun = [[entrance.meter.u, entrance.meter.v, 0.1], [electrical.panel.u, electrical.panel.v, heightOf(plan, electrical.panel.floor, electrical.panel.y)]]\n }\n}\n","import type { Layout } from './electrical'\nimport { heightOf, keyOf } from './electrical'\nimport { mainDoorOf } from './electrical-entrance'\nimport type { Json } from './shared'\nimport { round2 } from './shared'\nimport { atDoor, hasWindowAt, wallPointsOf } from './wall-points'\n\nconst LAMP_CATEGORIES = ['ceiling_light', 'lamp', 'table_light']\n\nconst lampsOf = (layout: Layout): Json[] => layout.items.filter((m) => !m.outdoor && LAMP_CATEGORIES.includes(m.category))\n\n/** A switch by the latch of the main door of each room that has a lamp (and of the room of the front door, for the outside lamp), at 1.10 m. */\nexport function addSwitches(layout: Layout): void {\n const { plan, items, rooms, electrical, pointsOf } = layout\n const lamps = lampsOf(layout)\n const door = mainDoorOf(plan)\n let counter = 0\n const positionFor = (room: Json): { point: Json; door: Json; latch: boolean } | null => {\n const doors = plan.doors\n .filter((p: Json) => p.floor === room.floor && (p.a === room.id || p.b === room.id))\n .sort((a: Json, b: Json) => (a.opensTo === room.id ? 0 : 1) - (b.opensTo === room.id ? 0 : 1) || (a.width < b.width ? 1 : -1))\n const points = wallPointsOf(plan, room, items, 0.12)\n for (const tolerance of [0.16, 0.3]) {\n for (const d of doors) {\n for (const direction of [1, -1]) {\n const target = d.at + direction * (d.width / 2 + 0.18)\n const point = points.filter((q) => q.axis === d.axis && Math.abs(q.pos - d.pos) < 1e-3 && !hasWindowAt(q, 1.1, 0.2)).sort((a, b) => Math.abs(a.c - target) - Math.abs(b.c - target))[0]\n if (point && Math.abs(point.c - target) <= tolerance && !atDoor(plan, room, point, 0.0) && Math.abs(point.c - d.at) >= d.width / 2 + 0.12) return { point, door: d, latch: direction === 1 }\n }\n }\n }\n return null\n }\n for (const room of rooms.concat(plan.rooms.filter((x: Json) => ['stairs'].includes(x.type)))) {\n const roomLamps = lamps.filter((m) => m.room === room.id && m.floor === room.floor)\n const extra = door && door.a === room.id && room.floor === 0 && plan.lot ? [`outdoor_${door.id}`] : []\n if (!roomLamps.length && !extra.length) continue\n if (!pointsOf.get(keyOf(room))) pointsOf.set(keyOf(room), wallPointsOf(plan, room, items))\n const found = positionFor(room)\n if (!found) continue\n const p = found.point\n electrical.switches.push({ id: `switch${++counter}`, room: room.id, floor: room.floor, u: p.u, v: p.v, y: 1.1, c: p.c, axis: p.axis, pos: p.pos, frontU: p.nu, frontV: p.nv, door: found.door.id, latchSide: found.latch, controls: roomLamps.map((m) => m.id).concat(extra) })\n }\n if (door && plan.lot) {\n const id = `outdoor_${door.id}`\n electrical.outdoorLamps.push({ id, u: round2(door.at + door.width / 2 + 0.32), v: round2(door.pos), y: 2.15, door: door.id, switch: electrical.switches.find((s) => s.controls.includes(id))?.id ?? null })\n }\n}\n\n/** One circuit per room with sockets or switches, and the conduits: from the panel up to the ceiling, along it to the room and down to each point. */\nexport function addConduits(layout: Layout): void {\n const { plan, rooms, electrical } = layout\n const panel = electrical.panel\n const lamps = lampsOf(layout)\n for (const room of rooms) {\n const outlets = electrical.outlets.filter((t) => t.room === room.id && t.floor === room.floor)\n const switches = electrical.switches.filter((i) => i.room === room.id && i.floor === room.floor)\n const roomLamps = lamps.filter((m) => m.room === room.id && m.floor === room.floor)\n if (!outlets.length && !switches.length) continue\n const ceiling = (room.ceiling || plan.floors[room.floor].ceiling) - 0.12\n const part = room.parts[0]\n const centreU = round2((part[0] + part[2]) / 2)\n const centreV = round2((part[1] + part[3]) / 2)\n const circuit = { id: `circuit_${room.id}_${room.floor}`, room: room.id, floor: room.floor, outlets: outlets.map((t) => t.id), switches: switches.map((i) => i.id), lamps: roomLamps.map((m) => m.id), exposed: electrical.exposed, gauge_mm2: outlets.length > 3 ? 2.5 : 1.5 }\n electrical.circuits.push(circuit)\n const base = heightOf(plan, room.floor, 0)\n const riser = panel ? [[panel.u, panel.v, heightOf(plan, panel.floor, panel.y)], [panel.u, panel.v, heightOf(plan, panel.floor, 0) + ceiling]] : []\n if (panel) electrical.conduits.push({ id: `conduit_${circuit.id}`, circuit: circuit.id, from: 'panel', to: room.id, exposed: electrical.exposed, diameter: 0.025, points: riser.concat([[centreU, centreV, base + ceiling]]) })\n for (const point of outlets.concat(switches)) {\n electrical.conduits.push({ id: `conduit_${point.id}`, circuit: circuit.id, from: circuit.id, to: point.id, exposed: electrical.exposed, diameter: 0.02, points: [[centreU, centreV, base + ceiling], [point.u, point.v, base + ceiling], [point.u, point.v, base + point.y]] })\n }\n }\n if (panel) panel.breakers = electrical.circuits.length + 1\n}\n","import type { Json, Rng } from './shared'\nimport { NO_SOCKET_ROOMS } from './shared'\nimport { addOutlets } from './electrical-outlets'\nimport { addConduits, addSwitches } from './electrical-circuits'\nimport { placeEntrance, placePanel } from './electrical-entrance'\nimport { wallPointsOf } from './wall-points'\nimport type { WallPoint } from './wall-points'\n\nexport type EnergyMode = 'grid' | 'tap' | 'offgrid'\n\n/** What a template says about its energy (a shack taps the grid without a meter, a cabin may run off-grid on solar). */\nexport interface EnergyConfig {\n mode: EnergyMode\n solar?: boolean\n}\n\nexport interface Electrical {\n mode: EnergyMode\n serviceEntrance: Json | null\n panel: Json | null\n outlets: Json[]\n switches: Json[]\n circuits: Json[]\n conduits: Json[]\n exposed: boolean\n outdoorLamps: Json[]\n source?: 'solar' | 'lamp'\n}\n\nexport interface ElectricalContext {\n plan: Json\n items: Json[]\n rng: Rng\n energy?: EnergyConfig\n}\n\n/** Shared state of the steps that lay the installation out. */\nexport interface Layout {\n plan: Json\n items: Json[]\n rooms: Json[]\n electrical: Electrical\n pointsOf: Map<string, WallPoint[]>\n}\n\nexport const keyOf = (room: Json): string => `${room.id}@${room.floor}`\n\nconst absolute = (plan: Json, floor: number, y: number): number => (plan.floors[floor] ? plan.floors[floor].y0 : 0) + y\nexport const heightOf = absolute\n\n/**\n * The electrical installation: sockets for the appliances and by room size, the service entrance (pole, drop, meter, descent; a tap without meter for a shack),\n * the panel near the entrance, switches by the door latch, circuits and conduits. Items that plug in are annotated (`outlet`, `showerHeater`).\n */\nexport function planElectrical(context: ElectricalContext): Electrical {\n const { plan, items, rng, energy } = context\n const mode: EnergyMode = energy?.mode ?? 'grid'\n const electrical: Electrical = { mode, serviceEntrance: null, panel: null, outlets: [], switches: [], circuits: [], conduits: [], exposed: false, outdoorLamps: [] }\n electrical.exposed = plan.style === 'budget' ? rng() < 0.65 : plan.style === 'mid' ? rng() < 0.12 : false\n if (mode !== 'grid') electrical.exposed = true\n if (mode === 'offgrid') {\n electrical.source = energy?.solar ? 'solar' : 'lamp'\n return electrical\n }\n const rooms = plan.rooms.filter((room: Json) => !NO_SOCKET_ROOMS.includes(room.type) && !room.outdoor)\n const pointsOf = new Map<string, WallPoint[]>()\n for (const room of rooms) pointsOf.set(keyOf(room), wallPointsOf(plan, room, items))\n const layout: Layout = { plan, items, rooms, electrical, pointsOf }\n addOutlets(layout)\n placeEntrance(layout)\n placePanel(layout)\n addSwitches(layout)\n addConduits(layout)\n if (mode === 'tap' && electrical.serviceEntrance?.meter) {\n const entrance = electrical.serviceEntrance\n const meter = entrance.meter\n entrance.tap = true\n entrance.connection = { u: meter.u, v: meter.v, y: 2.6 }\n entrance.meter = null\n }\n return electrical\n}\n","import type { Rect } from '../types'\nimport type { Json, Rng } from './shared'\nimport { HALF_WALL, clamp, groundExteriorWalls, inner, isSolid, outwardOf, overlaps, round2, sideNameOf } from './shared'\n\nexport const CYLINDER_TYPE = 'cooking_gas_cylinder'\nconst CYLINDER = { w: 0.36, d: 0.36, h: 0.48 }\nconst CYLINDER_KG = 13\n\nexport interface GasMeter {\n id: 'gas.meter'\n u: number\n v: number\n y: number\n side: string\n w: number\n d: number\n h: number\n}\n\nexport interface Gas {\n type: 'piped' | 'cylinder'\n meter: GasMeter | null\n}\n\ninterface Spot {\n mode: 'beside' | 'niche' | 'under'\n x: number\n z: number\n rect: Rect\n outdoor?: boolean\n cabinet?: string\n}\n\n/** Gas meter on the front wall of the ground floor, 1.2 m up. */\nfunction placeMeter(plan: Json): GasMeter | null {\n const segments = groundExteriorWalls(plan).sort((a, b) => (b.sides.includes('outside') ? 1 : 0) - (a.sides.includes('outside') ? 1 : 0) || (a.axis === 'u' && a.v0 === 0 ? -1 : 1))\n const wall = segments.find((w) => w.axis === 'u' && w.v0 === 0) || segments[0]\n if (!wall) return null\n const centre = wall.axis === 'u' ? (wall.u0 + wall.u1) / 2 : (wall.v0 + wall.v1) / 2\n const vector = outwardOf(wall)\n const offset = HALF_WALL + 0.1\n return {\n id: 'gas.meter', u: round2(wall.axis === 'u' ? centre : wall.u0 + vector[0] * offset), v: round2(wall.axis === 'u' ? wall.v0 + vector[1] * offset : centre), y: 1.2, side: sideNameOf(vector), w: 0.3, d: 0.15, h: 0.4,\n }\n}\n\ninterface Context {\n plan: Json\n items: Json[]\n stateItems: Json[]\n rng: Rng\n}\n\nfunction besideStove(context: Context, stove: Json, room: Json, solids: Rect[], doorZones: Rect[]): Spot | undefined {\n const t: [number, number] = [-stove.frontV, stove.frontU]\n const parts = room.parts.map(inner)\n for (const s of context.rng() < 0.5 ? [1, -1] : [-1, 1]) {\n const cx = stove.x + t[0] * s * (stove.w / 2 + CYLINDER.w / 2 + 0.03) - (stove.frontU * (stove.d - CYLINDER.d)) / 2\n const cz = stove.z + t[1] * s * (stove.w / 2 + CYLINDER.w / 2 + 0.03) - (stove.frontV * (stove.d - CYLINDER.d)) / 2\n const rect = [cx - CYLINDER.w / 2, cz - CYLINDER.d / 2, cx + CYLINDER.w / 2, cz + CYLINDER.d / 2].map(round2) as Rect\n const inside = parts.some((q: Rect) => rect[0] >= q[0] - 0.011 && rect[2] <= q[2] + 0.011 && rect[1] >= q[1] - 0.011 && rect[3] <= q[3] + 0.011)\n if (inside && !solids.some((o) => overlaps(rect, o, 0.011)) && !doorZones.some((z) => overlaps(rect, z, 0.011))) return { mode: 'beside', x: cx, z: cz, rect }\n }\n return undefined\n}\n\nfunction inNiche(context: Context, stove: Json, room: Json, doorZones: Rect[]): Spot | undefined {\n const { plan, items, stateItems } = context\n const wall = plan.walls.find(\n (p: Json) =>\n p.exterior && p.floor === stove.floor && p.type === 'wall' && p.sides.includes(room.id) &&\n (p.axis === 'u'\n ? Math.abs(stove.x - clamp(stove.x, p.u0, p.u1)) < 1.6 && Math.abs(stove.z - p.v0) < 1.6\n : Math.abs(stove.z - clamp(stove.z, p.v0, p.v1)) < 1.6 && Math.abs(stove.x - p.u0) < 1.6),\n )\n if (!wall || stove.floor !== 0) return undefined\n const vector = outwardOf(wall)\n const cx = wall.axis === 'u' ? clamp(stove.x, wall.u0 + 0.4, wall.u1 - 0.4) : wall.u0 + vector[0] * (HALF_WALL + CYLINDER.w / 2 + 0.05)\n const cz = wall.axis === 'u' ? wall.v0 + vector[1] * (HALF_WALL + CYLINDER.d / 2 + 0.05) : clamp(stove.z, wall.v0 + 0.4, wall.v1 - 0.4)\n const rect = [cx - CYLINDER.w / 2, cz - CYLINDER.d / 2, cx + CYLINDER.w / 2, cz + CYLINDER.d / 2].map(round2) as Rect\n const blockedByItem = items.some((o) => o.outdoor && isSolid(o) && overlaps(rect, o.aabb, 0.011))\n const blockedByState = stateItems.some((o) => o.outdoor && o.aabb && !o.flat && o.mount !== 'ground' && overlaps(rect, o.aabb, 0.011))\n const blockedByPath = plan.paths.some((c: Json) => c.rects.some((z: Rect) => overlaps(rect, z, 0.011)))\n const blockedByGate = plan.gates.some((g: Json) => g.zones.some((z: Rect) => overlaps(rect, z, 0.011)))\n const blockedByFence = !plan.lot || plan.lot.perimeter.some((q: Json) => overlaps(rect, [Math.min(q.u0, q.u1) - HALF_WALL, Math.min(q.v0, q.v1) - HALF_WALL, Math.max(q.u0, q.u1) + HALF_WALL, Math.max(q.v0, q.v1) + HALF_WALL], 0.011))\n if (blockedByItem || blockedByState || blockedByPath || doorZones.some((z) => overlaps(rect, z, 0.011)) || blockedByGate || blockedByFence) return undefined\n return { mode: 'niche', x: cx, z: cz, rect, outdoor: true }\n}\n\nfunction underCounter(context: Context, stove: Json): Spot | undefined {\n const distance = (m: Json): number => Math.hypot(m.x - stove.x, m.z - stove.z)\n const cabinets = context.items\n .filter(\n (m) => m.floor === stove.floor && m.room === stove.room && !m.outdoor && !m.on && !m.flat && ['kitchen_cabinet', 'workbench'].includes(m.category) && m.aabb && m.id !== stove.id &&\n Math.min(m.aabb[2] - m.aabb[0], m.aabb[3] - m.aabb[1]) >= CYLINDER.d - 0.011 && Math.max(m.aabb[2] - m.aabb[0], m.aabb[3] - m.aabb[1]) >= CYLINDER.w + 0.02,\n )\n .sort((a, b) => (a.category === 'kitchen_cabinet' ? 0 : 1) - (b.category === 'kitchen_cabinet' ? 0 : 1) || distance(a) - distance(b))\n for (const cabinet of cabinets) {\n if (distance(cabinet) > 3) continue\n const box = cabinet.aabb as Rect\n const hw = CYLINDER.w / 2\n const hd = CYLINDER.d / 2\n const cx = clamp(stove.x, box[0] + hw + 0.01, box[2] - hw - 0.01)\n const cz = clamp(stove.z, box[1] + hd + 0.01, box[3] - hd - 0.01)\n const rect = [cx - hw, cz - hd, cx + hw, cz + hd].map(round2) as Rect\n if (rect[0] < box[0] || rect[2] > box[2] || rect[1] < box[1] || rect[3] > box[3] || overlaps(rect, stove.aabb, 0.011)) continue\n return { mode: 'under', x: cx, z: cz, rect, cabinet: cabinet.id }\n }\n return undefined\n}\n\nconst PLACEMENT = { beside: 'beside', niche: 'external_niche', under: 'under_counter' } as const\n\nfunction cylinderItem(stove: Json, spot: Spot): Json {\n const item: Json = {\n id: `${stove.room}.${CYLINDER_TYPE}`, type: CYLINDER_TYPE, category: CYLINDER_TYPE, x: round2(spot.x), z: round2(spot.z), ry: 0, w: CYLINDER.w, d: CYLINDER.d, h: CYLINDER.h, y: 0,\n frontU: -stove.frontU, frontV: -stove.frontV, room: stove.room, floor: stove.floor, outdoor: !!spot.outdoor, slot: 'cylinder', on: null, mode: null, clearance: 0, flat: false, low: false,\n aabb: spot.rect, link: stove.id, placement: PLACEMENT[spot.mode], hose: [[round2(spot.x), round2(spot.z), 0.3], [stove.x, stove.z, 0.5]], capacityKg: CYLINDER_KG,\n }\n if (spot.cabinet) {\n item.on = spot.cabinet\n item.hidden = true\n }\n if (spot.outdoor) item.floor = -1\n item.color = stove.color\n return item\n}\n\n/**\n * Gas for the stoves of the house: a cylinder beside the stove, in an outside niche with a hose or under the counter, or (high-end houses, or when\n * nothing fits) piped gas with a meter on the facade. The cylinders are added to `items`; the stoves are annotated (`gas`, `cylinder`, `gasMeter`).\n */\nexport function planGas(context: Context): Gas | null {\n const { plan, items, stateItems, rng } = context\n const stoves = items.filter((m) => m.category === 'stove' && !m.outdoor)\n if (!stoves.length) return null\n const high = plan.style === 'high'\n const piped = plan.style !== 'commercial' && (high ? rng() < 0.8 : plan.style === 'mid' ? rng() < 0.1 : false)\n const out: Gas = { type: piped ? 'piped' : 'cylinder', meter: null }\n const ensureMeter = (): void => {\n if (!out.meter) out.meter = placeMeter(plan)\n }\n for (const stove of stoves) {\n const room = plan.rooms.find((c: Json) => c.id === stove.room && c.floor === stove.floor)\n if (!room) continue\n stove.gas = piped ? 'piped' : 'cylinder'\n if (piped) {\n ensureMeter()\n stove.gasMeter = 'gas.meter'\n continue\n }\n const solids = items.filter((m) => m.floor === stove.floor && m.room === stove.room && isSolid(m) && m.id !== stove.id).map((m) => m.aabb as Rect)\n .concat(stateItems.filter((m) => m.aabb && m.room === stove.room && m.floor === stove.floor && !m.flat && !m.on && m.mount !== 'window' && m.mount !== 'ground').map((m) => m.aabb as Rect))\n const doorZones = plan.doors.filter((p: Json) => p.floor === stove.floor).flatMap((p: Json) => p.zones as Rect[])\n const order: Spot['mode'][] = rng() < 0.7 ? ['beside', 'niche', 'under'] : ['niche', 'beside', 'under']\n let spot: Spot | undefined\n for (const mode of order) {\n if (spot) break\n spot = mode === 'beside' ? besideStove(context, stove, room, solids, doorZones) : mode === 'niche' ? inNiche(context, stove, room, doorZones) : underCounter(context, stove)\n }\n if (!spot) {\n stove.gas = 'piped'\n out.type = 'piped'\n ensureMeter()\n stove.gasMeter = 'gas.meter'\n continue\n }\n const cylinder = cylinderItem(stove, spot)\n items.push(cylinder)\n stove.cylinder = cylinder.id\n }\n return out\n}\n","import type { Json } from './shared'\nimport { round2 } from './shared'\nimport type { WaterTank } from '../types'\n\nconst FIXTURES: Record<string, string> = { kitchen_cabinet: 'tap', washbasin: 'tap', shower: 'shower', toilet: 'flush', laundry_tub: 'tub', washing_machine: 'machine' }\nconst FLOW_LPM: Record<string, number> = { tap: 6, shower: 9, flush: 6, tub: 8, machine: 12 }\nconst POINT_HEIGHT: Record<string, number> = { shower: 2.1, flush: 0.9, machine: 0.8 }\nconst DEFAULT_CAPACITY = { budget: 500, mid: 1000 }\n\nexport interface PlumbingContext {\n plan: Json\n items: Json[]\n tank: WaterTank | null\n}\n\nconst absolute = (plan: Json, floor: number, y: number): number => (plan.floors[floor] ? plan.floors[floor].y0 : 0) + y\n\n/**\n * Plumbing as logic: a point for every tap, shower, toilet, tub and machine, and the runs you can see: the outlet of the tank, under each sink and in the wall\n * from the tank to every wet room (hidden in the wall, it shows only where the wall breaks).\n */\nexport function planPlumbing(context: PlumbingContext): Json {\n const { plan, items, tank } = context\n const fixtures = items.filter((m) => FIXTURES[m.category] && !m.decor)\n const points: Json[] = []\n const runs: Json[] = []\n const capacity = tank?.capacity ?? (plan.style === 'budget' ? DEFAULT_CAPACITY.budget : plan.style === 'mid' ? DEFAULT_CAPACITY.mid : plan.tpl?.id === 'mansion' ? 3000 : 2000)\n const plumbing: Json = { tank: tank ? 'water_tank' : null, capacityL: tank || !plan.tpl.noWalls ? capacity : 0, points, visibleRuns: runs }\n const top = plan.floors.length - 1\n fixtures.forEach((item, index) => {\n const kind = FIXTURES[item.category]!\n points.push({ id: `pt${index + 1}`, kind, item: item.id, room: item.room, floor: item.outdoor ? -1 : item.floor, u: item.x, v: item.z, y: POINT_HEIGHT[kind] ?? 0.9, flowLpm: FLOW_LPM[kind], run: null })\n })\n if (!tank) return plumbing\n const slabY = absolute(plan, top, plan.floors[top].ceiling)\n const tankY = tank.place === 'raised_slab' ? tank.platform!.topY : tank.place === 'attic' ? slabY + 0.5 : tank.y\n runs.push({ id: 'run_outlet', from: 'water_tank', to: 'ceiling', points: [[tank.u, tank.v, round2(tankY + 0.15)], [tank.u, tank.v, round2(slabY - 0.15)]], diameter: 0.032, exposed: 'tank_outlet' })\n for (const point of points) {\n const item = fixtures.find((x) => x.id === point.item)!\n if (point.kind !== 'tap' || item.outdoor) continue\n const front = [item.frontU || 0, item.frontV || 1]\n const behind = [item.x - front[0]! * (item.d / 2 + 0.02), item.z - front[1]! * (item.d / 2 + 0.02)]\n runs.push({ id: `run_under_${point.id}`, from: 'valve', to: point.id, points: [[round2(behind[0]!), round2(behind[1]!), absolute(plan, item.floor, 0.5)], [item.x, item.z, absolute(plan, item.floor, 0.5)], [item.x, item.z, absolute(plan, item.floor, 0.75)]], diameter: 0.025, exposed: 'under_sink' })\n }\n const wet: { room: string; floor: number; points: Json[] }[] = []\n for (const point of points) {\n if (!wet.some((c) => c.room === point.room && c.floor === point.floor)) wet.push({ room: point.room, floor: point.floor, points: points.filter((q) => q.room === point.room && q.floor === point.floor) })\n }\n for (const room of wet) {\n const found = plan.rooms.find((c: Json) => c.id === room.room && c.floor === room.floor)\n const zone = plan.zones.find((z: Json) => z.id === room.room)\n const parts = (found || zone || { parts: [[tank.u, tank.v, tank.u, tank.v]] }).parts\n const centreU = (parts[0][0] + parts[0][2]) / 2\n const centreV = (parts[0][1] + parts[0][3]) / 2\n const ceiling = found ? found.ceiling || plan.floors[found.floor].ceiling : 2.8\n const y0 = found ? absolute(plan, found.floor, 0) : 0\n const id = `run_wall_${room.room}${room.floor === -1 ? '_outside' : `_${room.floor}`}`\n runs.push({ id, from: 'water_tank', to: room.room, points: [[tank.u, tank.v, round2(slabY - 0.15)], [round2(centreU), round2(centreV), round2(slabY - 0.15)], [round2(centreU), round2(centreV), round2(y0 + ceiling - 0.15)], [round2(centreU), round2(centreV), round2(y0 + 0.6)]], diameter: 0.025, exposed: 'wall' })\n for (const point of room.points) point.run = id\n }\n return plumbing\n}\n","import { outwardOf, groundExteriorWalls, HALF_WALL, round2, sideNameOf } from './shared'\nimport type { Json, Rng } from './shared'\nimport type { EnergyConfig } from './electrical'\n\nconst PANEL_WIDTH = 1.0\nconst PANEL_LENGTH = 1.65\nconst NO_PANELS_UNDER: readonly string[] = ['void', 'elevator', 'stairs', 'balcony', 'terrace', 'porch']\n\nexport interface SolarContext {\n plan: Json\n rng: Rng\n energy?: EnergyConfig\n}\n\n/** Inverter on a side wall of the ground floor, 1.5 m up. */\nfunction placeInverter(plan: Json): Json | null {\n const wall = groundExteriorWalls(plan).filter((q) => q.sides.includes('outside')).sort((a, b) => (a.axis === 'v' ? 0 : 1) - (b.axis === 'v' ? 0 : 1))[0]\n if (!wall) return null\n const vector = outwardOf(wall)\n const centre = wall.axis === 'u' ? (wall.u0 + wall.u1) / 2 : (wall.v0 + wall.v1) / 2\n const offset = HALF_WALL + 0.08\n return { id: 'inverter', u: round2(wall.axis === 'u' ? centre : wall.u0 + vector[0] * offset), v: round2(wall.axis === 'u' ? wall.v0 + vector[1] * offset : centre), y: 1.5, side: sideNameOf(vector), w: 0.4, d: 0.15, h: 0.5, outdoor: true, link: 'panel' }\n}\n\n/**\n * Solar panels: about 6% of budget houses, 25% of mid and 50% of the rest; on the roof slope that faces north or on tilted racks on a flat roof, with the\n * inverter on the wall. A template with its own energy decides (`energy.solar`).\n */\nexport function planSolar(context: SolarContext): Json | null {\n const { plan, rng, energy } = context\n if (!plan.lot || plan.style === 'commercial' || !plan.facade) return null\n const chance = plan.style === 'budget' ? 0.06 : plan.style === 'mid' ? 0.25 : 0.5\n const forced = energy ? (energy.solar ? 1 : 0) : null\n const draw = rng()\n if (forced !== null ? !forced : draw >= chance) return null\n const floor = plan.floors.length - 1\n const level = plan.floors[floor]\n const flat = plan.facade.roof === 'slab'\n const tops = plan.rooms.filter((c: Json) => c.floor === floor && !NO_PANELS_UNDER.includes(c.type))\n if (!tops.length) return null\n const parts: number[][] = tops.flatMap((c: Json) => c.parts)\n const box = [Math.min(...parts.map((q) => q[0]!)), Math.min(...parts.map((q) => q[1]!)), Math.max(...parts.map((q) => q[2]!)), Math.max(...parts.map((q) => q[3]!))] as [number, number, number, number]\n const north = rng() < 0.5 ? 'front' : 'back'\n const angle = flat ? 15 : 25\n const projection = round2(PANEL_LENGTH * Math.cos((angle * Math.PI) / 180))\n const margin = 0.6\n const uStart = box[0] + margin\n const uEnd = box[2] - margin\n const columns = Math.max(1, Math.floor((uEnd - uStart) / (PANEL_WIDTH + 0.05)))\n const vMiddle = (box[1] + box[3]) / 2\n const vArea = flat ? [box[1] + margin, box[3] - margin] : north === 'front' ? [box[1] + 0.4, vMiddle - 0.2] : [vMiddle + 0.2, box[3] - 0.4]\n const step = flat ? projection + 0.5 : projection + 0.05\n const rowsMax = Math.max(1, Math.floor((vArea[1]! - vArea[0]!) / step))\n const wanted = forced !== null ? 1 + Math.floor(rng() * 2) : 3 + Math.floor(rng() * (plan.style === 'high' ? 12 : 8))\n const rows = Math.max(1, Math.min(rowsMax, Math.ceil(wanted / columns)))\n const count = Math.min(wanted, rows * columns)\n const u0 = uStart + (uEnd - uStart - columns * (PANEL_WIDTH + 0.05)) / 2\n const vStart = north === 'front' ? vArea[0]! : vArea[1]! - rows * step\n const panels: Json[] = []\n for (let k = 0; k < count; k++) {\n const row = Math.floor(k / columns)\n const column = k % columns\n panels.push({ id: `pv${k + 1}`, u: round2(u0 + column * (PANEL_WIDTH + 0.05) + PANEL_WIDTH / 2), v: round2(vStart + row * step + (flat ? 0.25 : 0) + projection / 2), w: PANEL_WIDTH, d: projection, length: PANEL_LENGTH })\n }\n const area = [round2(u0), round2(vStart), round2(u0 + columns * (PANEL_WIDTH + 0.05)), round2(vStart + rows * step)]\n return { type: flat ? 'slab_rack' : 'roof', orientation: 'north', north, slopeSide: flat ? null : north, tilt: angle, area, areaM2: round2(count * PANEL_WIDTH * PANEL_LENGTH), count, floor, y: round2(level.y0 + level.ceiling), panels, inverter: placeInverter(plan) }\n}\n","import type { FindsQuery, FindStack } from '@adatechnology/game-floorplan'\n\nimport type { WaterTank } from '../types'\nimport { hasContent } from './content'\nimport type { EnergyConfig, Electrical } from './electrical'\nimport { planElectrical } from './electrical'\nimport { planGas } from './gas'\nimport type { Gas } from './gas'\nimport { planPlumbing } from './plumbing'\nimport type { Json, Rng } from './shared'\nimport { planSolar } from './solar'\n\nexport interface Utilities {\n gas: Gas | null\n electrical: Electrical\n solar: Json | null\n plumbing: Json\n}\n\nexport interface UtilitiesContext {\n plan: Json\n items: Json[]\n stateItems: Json[]\n tank: WaterTank | null\n energy?: EnergyConfig\n /** Seeded stream by name: `gas`, `electrical`, `solar`. */\n rngFor(key: string): Rng\n}\n\n/** Gas, electricity, solar panels and plumbing of a house, in the order that lets the later ones see the cylinders the first adds to `items`. */\nexport function planUtilities(context: UtilitiesContext): Utilities {\n const { plan, items, stateItems, tank, energy, rngFor } = context\n const gas = planGas({ plan, items, stateItems, rng: rngFor('gas') })\n const electrical = planElectrical({ plan, items, rng: rngFor('eletrica'), ...(energy ? { energy } : {}) })\n const solar = planSolar({ plan, rng: rngFor('solar'), ...(energy ? { energy } : {}) })\n const plumbing = planPlumbing({ plan, items, tank })\n return { gas, electrical, solar, plumbing }\n}\n\nconst OVERHEAD = 'overhead_cabinet'\nconst ALWAYS_HOLD: readonly string[] = ['trash_bin', 'outdoor_bin', 'mailbox']\n\nexport interface ContentsContext {\n items: Json[]\n state: string\n place: string\n /** Outbreak days and region of the world, passed to the finds provider. */\n day?: number\n region?: string\n rngFor(key: string): Rng\n findsFor(query: FindsQuery): readonly FindStack[]\n}\n\n/** What every container holds, asked of the registered finds provider: by item id, and `<id>#overhead` for the wall cabinet over a sink. */\nexport function planContents(context: ContentsContext): Record<string, readonly FindStack[]> {\n const out: Record<string, readonly FindStack[]> = {}\n const ask = (item: Json, container: string, key: string): readonly FindStack[] =>\n context.findsFor({ place: context.place, container, state: context.state, rng: context.rngFor(key), footprint: item.w * item.d, key: item.id, ...(context.day === undefined ? {} : { day: context.day }), ...(context.region === undefined ? {} : { region: context.region }) })\n for (const item of context.items) {\n if (item.decor && item.mount !== 'wall_top') continue\n const container = hasContent(item.type) ? item.type : item.category\n if (!hasContent(container)) continue\n if (!ALWAYS_HOLD.includes(container) && item.decor) continue\n out[item.id] = ask(item, container, `content:${item.id}`)\n if (container === 'kitchen_cabinet' && item.overhead !== false) out[`${item.id}#overhead`] = ask(item, OVERHEAD, `content:${item.id}:overhead`)\n }\n return out\n}\n","import type { Rect } from '../types'\nimport type { Json, Rng } from './shared'\nimport { isSolid, overlaps, round2 } from './shared'\n\nconst WALL = 0.15\nconst DOOR_WIDTH = 0.85\nconst DOOR_HEIGHT = 2.1\nconst USES: Record<string, string[]> = { guest_room: ['single_bed', 'nightstand'], office: ['desk', 'shelf_unit_small'], storage: ['tool_shelf', 'crate'], gourmet: ['dining_table_small', 'workbench'] }\nconst USE_WEIGHTS: Record<string, number> = { guest_room: 3, office: 2, storage: 2, gourmet: 2 }\nconst PATH_WIDTH = 1.0\n\nexport interface OutbuildingContext {\n plan: Json\n items: Json[]\n catalog: Record<string, Json>\n rngFor(key: string): Rng\n}\n\n/**\n * Name of the seeded stream of an outbuilding. It is the name the Visor de casas 3D gave it (`edif:<room>.<slot>` in Portuguese: `quintal.edicula`), kept verbatim so that an\n * old seed draws the same use and furniture; it never appears in the output.\n */\nconst LEGACY_ROOMS: Record<string, string> = { backyard: 'quintal' }\nconst LEGACY_SLOTS: Record<string, string> = { outbuilding: 'edicula' }\nexport const streamOf = (itemId: string): string => {\n const [room = '', ...slot] = itemId.split('.')\n return `edif:${LEGACY_ROOMS[room] ?? room}.${slot.map((part) => LEGACY_SLOTS[part] ?? part).join('.')}`\n}\n\nfunction pickWeighted(rng: Rng, weights: Record<string, number>): string {\n const keys = Object.keys(weights)\n let x = rng() * keys.reduce((sum, key) => sum + weights[key]!, 0)\n for (const key of keys) {\n x -= weights[key]!\n if (x < 0) return key\n }\n return keys[keys.length - 1]!\n}\n\nconst sideOf = (x: number, z: number): string => (Math.abs(x) > Math.abs(z) ? (x > 0 ? 'right' : 'left') : z > 0 ? 'back' : 'front')\n\ninterface Frame {\n n: [number, number]\n t: [number, number]\n cx: number\n cz: number\n depth: number\n width: number\n horizontal: boolean\n sideToMiddle: number\n}\n\nconst at = (frame: Frame, a: number, b: number): [number, number] => [frame.cx + frame.n[0] * a + frame.t[0] * b, frame.cz + frame.n[1] * a + frame.t[1] * b]\n\nfunction opening(frame: Frame, id: string, a: number, b: number, vector: [number, number], width: number, extra: Json): Json {\n const [u, v] = at(frame, a, b)\n const alongU = Math.abs(vector[0]) !== 1\n return { id, axis: alongU ? 'u' : 'v', pos: round2(alongU ? v : u), at: round2(alongU ? u : v), u: round2(u), v: round2(v), width: round2(width), side: sideOf(vector[0], vector[1]), ...extra }\n}\n\nfunction wallsOf(box: Rect, door: Json, height: number): Json[] {\n const walls: Json[] = []\n const sides = [\n { axis: 'u', pos: box[1], i0: box[0], i1: box[2], side: 'front' }, { axis: 'u', pos: box[3], i0: box[0], i1: box[2], side: 'back' },\n { axis: 'v', pos: box[0], i0: box[1], i1: box[3], side: 'left' }, { axis: 'v', pos: box[2], i0: box[1], i1: box[3], side: 'right' },\n ]\n for (const w of sides) {\n const cut = w.axis === door.axis && Math.abs(w.pos - door.pos) < 0.02 ? [door.at - door.width / 2, door.at + door.width / 2] : null\n const segments = cut ? [[w.i0, cut[0]!], [cut[1]!, w.i1]] : [[w.i0, w.i1]]\n for (const [x0, x1] of segments) {\n if (x1! - x0! <= 1e-3) continue\n walls.push(w.axis === 'u' ? { axis: 'u', u0: round2(x0!), v0: round2(w.pos), u1: round2(x1!), v1: round2(w.pos), thickness: WALL, h: height, side: w.side } : { axis: 'v', u0: round2(w.pos), v0: round2(x0!), u1: round2(w.pos), v1: round2(x1!), thickness: WALL, h: height, side: w.side })\n }\n }\n return walls\n}\n\nfunction furnish(context: OutbuildingContext, frame: Frame, use: string, interior: Rect, insideDoor: Rect): Json[] {\n const placed: Json[] = []\n USES[use]!.forEach((type, k) => {\n const def = context.catalog[type]!\n const facing: [number, number] = k === 0 ? frame.n : [frame.t[0] * frame.sideToMiddle, frame.t[1] * frame.sideToMiddle]\n const [a, b] = k === 0 ? [-frame.depth / 2 + WALL + def.d / 2, frame.sideToMiddle * -0.4] : [-0.1, -frame.sideToMiddle * (frame.width / 2 - WALL - def.d / 2)]\n const [u, v] = at(frame, a, b)\n const eu = Math.abs(facing[0]) === 1 ? def.d : def.w\n const ev = Math.abs(facing[0]) === 1 ? def.w : def.d\n const box = [u - eu / 2, v - ev / 2, u + eu / 2, v + ev / 2].map(round2) as Rect\n if (box[0] < interior[0] - 0.011 || box[2] > interior[2] + 0.011 || box[1] < interior[1] - 0.011 || box[3] > interior[3] + 0.011 || overlaps(box, insideDoor) || placed.some((o) => overlaps(box, o.aabb))) return\n placed.push({ type, category: def.category, u: round2(u), v: round2(v), w: def.w, d: def.d, h: def.h, ry: Math.atan2(facing[0], facing[1]), frontU: facing[0], frontV: facing[1], aabb: box })\n })\n return placed\n}\n\n/**\n * The outbuilding at the back of the yard is a small building of its own: walls with a gap for the door, a door of 0.85 m facing the yard, two windows and the\n * furniture of a drawn use (guest room, office, storage, gourmet space).\n */\nexport function planOutbuildings(context: OutbuildingContext): Json[] {\n const { plan, items } = context\n const lot = plan.lot\n if (!lot) return []\n const out: Json[] = []\n for (const item of items.filter((m) => m.category === 'outbuilding')) {\n const rng = context.rngFor(streamOf(item.id))\n const [a0, a1, a2, a3] = item.aabb as Rect\n const n: [number, number] = [item.frontU, item.frontV]\n const t: [number, number] = [-item.frontV, item.frontU]\n const horizontal = Math.abs(item.frontU) === 1\n const cx = (a0 + a2) / 2\n const cz = (a1 + a3) / 2\n const depth = horizontal ? a2 - a0 : a3 - a1\n const width = horizontal ? a3 - a1 : a2 - a0\n const sideToMiddle = ((lot.rect[0] + lot.rect[2]) / 2 - cx) * t[0] + ((lot.rect[1] + lot.rect[3]) / 2 - cz) * t[1] >= 0 ? 1 : -1\n const frame: Frame = { n, t, cx, cz, depth, width, horizontal, sideToMiddle }\n const doorOffset = sideToMiddle * (width / 2 - 0.95)\n const door = opening(frame, `${item.id}.d0`, depth / 2, doorOffset, n, DOOR_WIDTH, { height: DOOR_HEIGHT, exterior: true })\n const windowFront = opening(frame, `${item.id}.w0`, depth / 2, -sideToMiddle * (width / 2 - 0.9), n, Math.min(1.0, width / 2 - 0.6), { y0: 1.0, y1: 2.0 })\n const windowSide = opening(frame, `${item.id}.w1`, 0, (sideToMiddle * width) / 2, [t[0] * sideToMiddle, t[1] * sideToMiddle], Math.min(1.0, depth - 0.8), { y0: 1.0, y1: 2.0 })\n const [p, q] = [at(frame, depth / 2, doorOffset), at(frame, depth / 2 - 0.9, doorOffset)]\n door.zone = (horizontal ? [Math.min(p[0], q[0]), p[1] - door.width / 2, Math.max(p[0], q[0]), p[1] + door.width / 2] : [p[0] - door.width / 2, Math.min(p[1], q[1]), p[0] + door.width / 2, Math.max(p[1], q[1])]).map(round2)\n const interior: Rect = [a0 + WALL, a1 + WALL, a2 - WALL, a3 - WALL]\n const use = pickWeighted(rng, USE_WEIGHTS)\n out.push({ id: item.id, type: 'outbuilding', use, floor: 0, aabb: (item.aabb as Rect).slice(), interior: [interior.map(round2)], ceiling: item.h, thickness: WALL, front: n, walls: wallsOf(item.aabb, door, item.h), doors: [door], windows: [windowFront, windowSide], items: furnish(context, frame, use, interior, door.zone) })\n }\n return out\n}\n\n/** A pedestrian path from every door of an outbuilding: a 1 m stub out of the door and an L to the nearest existing path, away from furniture, the building and the fence. */\nexport function addOutbuildingPaths(lot: Json, outbuildings: Json[], items: Json[]): void {\n const half = PATH_WIDTH / 2\n const rect = lot.rect as Rect\n const solids = items.filter((m) => m.outdoor && m.aabb && isSolid(m)).map((m) => m.aabb as Rect)\n const fence = lot.perimeter.map((q: Json) => [Math.min(q.u0, q.u1) - 0.075, Math.min(q.v0, q.v1) - 0.075, Math.max(q.u0, q.u1) + 0.075, Math.max(q.v0, q.v1) + 0.075] as Rect)\n const strip = (p: number[], q: number[]): Rect => [Math.min(p[0]!, q[0]!) - half, Math.min(p[1]!, q[1]!) - half, Math.max(p[0]!, q[0]!) + half, Math.max(p[1]!, q[1]!) + half]\n for (const building of outbuildings) {\n for (const door of building.doors as Json[]) {\n if (lot.paths.some((c: Json) => c.to === door.id)) continue\n const z = door.zone as Rect\n const zc = door.axis === 'v' ? (z[0] + z[2]) / 2 : (z[1] + z[3]) / 2\n const outside = zc > door.pos ? -1 : 1\n const A = door.axis === 'v' ? [door.pos, door.at] : [door.at, door.pos]\n const S = door.axis === 'v' ? [door.pos + outside * PATH_WIDTH, door.at] : [door.at, door.pos + outside * PATH_WIDTH]\n const stub: Rect = door.axis === 'v' ? [Math.min(A[0]!, S[0]!), A[1]! - half, Math.max(A[0]!, S[0]!), A[1]! + half] : [A[0]! - half, Math.min(A[1]!, S[1]!), A[0]! + half, Math.max(A[1]!, S[1]!)]\n const cost = (rs: Rect[]): number => {\n let n = 0\n for (const r of rs) {\n const c: Rect = [r[0] + 0.02, r[1] + 0.02, r[2] - 0.02, r[3] - 0.02]\n for (const q of solids) if (overlaps(c, q, 0.011)) n += 2\n if (overlaps(c, building.aabb, 0.011)) n += 3\n for (const q of fence) if (overlaps(c, q, 0.011)) n += 3\n if (r[0] < rect[0] || r[1] < rect[1] || r[2] > rect[2] || r[3] > rect[3]) n += 3\n }\n return n\n }\n let best: { v: number; k: { rects: Rect[]; points: number[][] }; from: string | null } | null = null\n for (const c of lot.paths.filter((p: Json) => p.type === 'pedestrian' || p.id === 'cargo_path')) {\n for (const r of c.rects as Rect[]) {\n const T = [Math.min(Math.max(S[0]!, r[0] + half), r[2] - half), Math.min(Math.max(S[1]!, r[1] + half), r[3] - half)]\n const candidates: { rects: Rect[]; points: number[][] }[] = []\n if (Math.abs(T[0]! - S[0]!) < 1e-6 && Math.abs(T[1]! - S[1]!) < 1e-6) candidates.push({ rects: [stub], points: [A, S] })\n else for (const via of [[T[0]!, S[1]!], [S[0]!, T[1]!]]) candidates.push({ rects: [stub, strip(S, via), strip(via, T)].filter((q) => q[2] - q[0] > 1e-6), points: [A, S, via, T] })\n for (const k of candidates) {\n const distance = k.points.slice(1).reduce((sum, q, i) => sum + Math.abs(q[0]! - k.points[i]![0]!) + Math.abs(q[1]! - k.points[i]![1]!), 0)\n const value = cost(k.rects.slice(1)) * 100 + distance\n if (!best || value < best.v) best = { v: value, k, from: c.from }\n }\n }\n }\n const chosen = best ? best.k : { rects: [stub], points: [A, S] }\n lot.paths.push({ id: `path_${door.id}`, type: 'pedestrian', from: best ? best.from : null, to: door.id, width: PATH_WIDTH, rects: chosen.rects.map((q) => q.map(round2)), points: chosen.points.map((q) => q.map(round2)) })\n }\n }\n}\n","import { round2 } from './geometry'\nimport type { Rect, StructureSource, WaterTank } from './types'\n\ntype Rng = () => number\n\nconst TANK_SIDE = 1.1\nconst NOT_UNDER_TANK = ['void', 'elevator', 'stairs', 'balcony', 'porch']\nconst WET_ROOMS = ['bathroom', 'kitchen', 'laundry']\nconst ATTIC_CHANCE = 0.12\nconst clamp = (value: number, low: number, high: number): number => Math.max(low, Math.min(high, value))\n\nexport interface TankPlanOptions {\n /** Litres by template id or style id (default: budget 500, mid 1000, mansion 3000, any other 2000). */\n capacities?: Record<string, number>\n /** Where the tank goes; default: on the slab of a flat roof, else on a raised platform (the attic one time in eight). */\n location?: (source: StructureSource, rng: Rng) => WaterTank['place']\n /** A template with its own tank (a trestle for the rural water) answers here instead. */\n custom?: (source: StructureSource, rng: Rng) => WaterTank | null\n}\n\nconst DEFAULT_CAPACITIES: Record<string, number> = { budget: 500, mid: 1000, mansion: 3000 }\n\nfunction capacityOf(source: StructureSource, capacities: Record<string, number>): number {\n return capacities[source.style ?? ''] ?? capacities[source.template ?? ''] ?? 2000\n}\n\n/** Candidate spot: the room part with the least weight (wet rooms first, terraces last, near the reference point or the middle). */\nfunction bestSpot(source: StructureSource, floor: number, reference: { u: number; v: number } | undefined): { roomType: string; roomId: string; rect: Rect } | undefined {\n const centre: [number, number] = reference ? [reference.u, reference.v] : [source.w / 2, source.d / 2]\n let best: { roomType: string; roomId: string; rect: Rect; weight: number } | undefined\n for (const room of source.rooms.filter((r) => r.floor === floor && !NOT_UNDER_TANK.includes(r.type))) {\n for (const part of room.parts) {\n const rect: Rect = [part[0] + 0.4, part[1] + 0.4, part[2] - 0.4, part[3] - 0.4]\n if (rect[2] - rect[0] < TANK_SIDE || rect[3] - rect[1] < TANK_SIDE) continue\n const base = WET_ROOMS.includes(room.type) ? 0 : room.type === 'terrace' ? 500 : 100\n const weight = base + Math.hypot((rect[0] + rect[2]) / 2 - centre[0], (rect[1] + rect[3]) / 2 - centre[1])\n if (!best || weight < best.weight) best = { roomType: room.type, roomId: room.id, rect, weight }\n }\n }\n return best\n}\n\nfunction raisedPlatform(source: StructureSource, u: number, v: number, baseY: number): NonNullable<WaterTank['platform']> {\n const margin = 0.12\n const edge = Math.max(0, Math.min(u, source.w - u, v, source.d - v))\n const rise = round2(clamp(edge * 0.35 + 0.7, 1.1, 2.4))\n const thickness = 0.12\n const reach = TANK_SIDE / 2 + margin - 0.06\n const pillars = ([[-1, -1], [1, -1], [-1, 1], [1, 1]] as const).map(([a, b]) => ({ u: round2(u + a * reach), v: round2(v + b * reach), side: 0.12 }))\n const half = TANK_SIDE / 2 + margin\n return { aabb: [u - half, v - half, u + half, v + half].map(round2) as Rect, baseY, height: rise, thickness, topY: round2(baseY + rise + thickness), pillars, ladder: true }\n}\n\n/**\n * The water tank of a house: on the roof slab, in the attic, or on a platform that rises out of the roof, never in the yard. Null for a plan without\n * a lot (an apartment) or a commercial building, and when no room has space.\n */\nexport function planWaterTank(source: StructureSource, rng: Rng, options: TankPlanOptions = {}): WaterTank | null {\n if (!source.lot || source.style === 'commercial') return null\n if (options.custom) return options.custom(source, rng)\n const floor = source.floors.length - 1\n const level = source.floors[floor]!\n const capacity = capacityOf(source, { ...DEFAULT_CAPACITIES, ...options.capacities })\n const height = capacity >= 2000 ? 1.4 : capacity === 1000 ? 1.0 : 0.85\n const place = options.location ? options.location(source, rng) : source.facade.roof === 'slab' ? 'slab' : rng() < ATTIC_CHANCE ? 'attic' : 'raised_slab'\n const reference = (source.facade.slab as { waterTank?: { u: number; v: number } } | undefined)?.waterTank\n const spot = bestSpot(source, floor, reference)\n if (!spot) return null\n const target = reference ? [reference.u, reference.v] : [(spot.rect[0] + spot.rect[2]) / 2, (spot.rect[1] + spot.rect[3]) / 2]\n const u = clamp(target[0]!, spot.rect[0] + TANK_SIDE / 2, spot.rect[2] - TANK_SIDE / 2)\n const v = clamp(target[1]!, spot.rect[1] + TANK_SIDE / 2, spot.rect[3] - TANK_SIDE / 2)\n const where = spot.roomType === 'terrace' ? 'slab' : place\n const slabY = round2(spot.roomType === 'terrace' ? level.y0 : level.y0 + level.ceiling)\n const tank: WaterTank = {\n id: 'water_tank', kind: 'water_tank', itemType: 'water_tank', place: where, floor, room: spot.roomId, u: round2(u), v: round2(v), y: slabY, w: TANK_SIDE, d: TANK_SIDE, h: height,\n capacity, aabb: [u - TANK_SIDE / 2, v - TANK_SIDE / 2, u + TANK_SIDE / 2, v + TANK_SIDE / 2].map(round2) as Rect,\n }\n if (where === 'raised_slab') {\n tank.platform = raisedPlatform(source, u, v, slabY)\n tank.y = tank.platform.topY\n }\n return tank\n}\n","import type { ViewerLayer, ViewerLayerContext, ViewerLayerLegendEntry } from '@adatechnology/game-floorplan'\n\nimport type { StructurePart } from './types'\n\ntype MaterialGroup = 'concrete' | 'steel' | 'masonry' | 'wood'\n\nconst COLORS: Record<MaterialGroup, string> = { concrete: '#7d8590', steel: '#3d6fb0', masonry: '#b5654b', wood: '#a0693a' }\nconst BEAM_IDS = ['plate_', 'porch_beam', 'base_beam', 'trestle_beam']\n\nexport const LAYER_ID = 'structure'\n\nexport function groupOf(material: string): MaterialGroup {\n if (material === 'concrete') return 'concrete'\n if (material === 'steel' || material === 'aluminium' || material === 'cast_iron') return 'steel'\n if (material === 'brick' || material === 'stone' || material === 'ceramic') return 'masonry'\n return 'wood'\n}\n\nconst isRoofFrame = (part: StructurePart): boolean => ['truss', 'rafter', 'ridge'].some((prefix) => part.id.startsWith(prefix))\nconst isDrawnBeam = (part: StructurePart): boolean => part.role === 'beam' && BEAM_IDS.some((prefix) => part.id.startsWith(prefix))\n\nfunction drawColumns(context: ViewerLayerContext, parts: readonly StructurePart[]): void {\n for (const part of parts.filter((p) => p.role === 'column')) {\n const color = COLORS[groupOf(part.material)]\n if (groupOf(part.material) === 'wood') context.rect(part.aabb, null, color, 2)\n else context.rect(part.aabb, color, null)\n context.hit(part.aabb, `${part.id} · column · ${part.material} · ${part.mass} kg`)\n }\n}\n\nfunction drawBeams(context: ViewerLayerContext, parts: readonly StructurePart[]): void {\n context.g.save()\n context.g.setLineDash([6, 4])\n for (const part of parts.filter(isDrawnBeam)) {\n context.rect(part.aabb, null, COLORS[groupOf(part.material)], 1.5)\n context.hit(part.aabb, `${part.id} · beam · ${part.material} · ${part.mass} kg`)\n }\n context.g.restore()\n}\n\nfunction drawRoofFrames(context: ViewerLayerContext, parts: readonly StructurePart[]): void {\n context.g.save()\n context.g.strokeStyle = COLORS.wood\n context.g.lineWidth = 1\n for (const part of parts.filter(isRoofFrame)) {\n const [u0, v0, u1, v1] = part.aabb\n const alongV = v1 - v0 > u1 - u0\n context.g.beginPath()\n if (alongV) { context.g.moveTo(context.X((u0 + u1) / 2), context.Z(v0)); context.g.lineTo(context.X((u0 + u1) / 2), context.Z(v1)) }\n else { context.g.moveTo(context.X(u0), context.Z((v0 + v1) / 2)); context.g.lineTo(context.X(u1), context.Z((v0 + v1) / 2)) }\n context.g.stroke()\n }\n context.g.restore()\n}\n\nfunction drawPorchRoofs(context: ViewerLayerContext, parts: readonly StructurePart[]): void {\n context.g.save()\n context.g.setLineDash([2, 4])\n for (const part of parts.filter((p) => p.id.startsWith('porch_roof'))) context.rect(part.aabb, null, COLORS.wood, 1)\n context.g.restore()\n}\n\n/** What the viewer draws at one storey: pillars (filled for concrete, steel and masonry, hollow for wood), dashed beams, trusses on the top storey, the porch roof outline. */\nexport function drawStructure(context: ViewerLayerContext): void {\n const structure = context.plan.structure\n if (!structure) return\n const floor = context.all ? 0 : context.floor\n const here = (structure.parts as StructurePart[]).filter((part) => part.floor === floor)\n drawPorchRoofs(context, here)\n if (floor === (context.plan.roof?.bearingFloor ?? 0)) drawRoofFrames(context, structure.parts)\n drawBeams(context, here)\n drawColumns(context, here)\n}\n\nexport function structureLegend(plan: { structure?: { parts: StructurePart[] } }): ViewerLayerLegendEntry[] {\n const parts = plan.structure?.parts ?? []\n const entries: ViewerLayerLegendEntry[] = []\n for (const group of ['concrete', 'steel', 'masonry', 'wood'] as const) {\n const columns = parts.some((p) => p.role === 'column' && groupOf(p.material) === group)\n if (columns) entries.push({ label: `structure_column_${group}`, color: COLORS[group], shape: group === 'wood' ? 'hollow' : 'filled' })\n }\n for (const group of ['concrete', 'wood'] as const) {\n if (parts.some((p) => isDrawnBeam(p) && groupOf(p.material) === group)) entries.push({ label: `structure_beam_${group}`, color: COLORS[group], shape: 'dashed' })\n }\n if (parts.some(isRoofFrame)) entries.push({ label: 'structure_roof_frame', color: COLORS.wood, shape: 'line' })\n return entries\n}\n\nexport const structureLayer: ViewerLayer = {\n id: LAYER_ID,\n label: 'structure_layer',\n defaultOn: false,\n draw: drawStructure,\n legend: structureLegend,\n}\n","import type { FloorplanEngine, ResultExtensionContext } from '@adatechnology/game-floorplan'\n\nimport { constructionFor } from './construction'\nimport enLocale from './locales/en.json'\nimport ptBrLocale from './locales/pt-BR.json'\nimport type { ConstructionBuild } from './registry'\nimport { buildStructure } from './structure'\nimport { contentOf } from './utilities/content'\nimport { planContents, planUtilities } from './utilities'\nimport { addOutbuildingPaths, planOutbuildings } from './utilities/outbuildings'\nimport type { EnergyConfig } from './utilities/electrical'\nimport type { TankPlanOptions } from './water-tank'\nimport { planWaterTank } from './water-tank'\nimport { structureLayer } from './viewer-layer'\nimport type { Roof, StructureOptions, WallDetail } from './types'\n\nexport interface StructurePackOptions {\n /** Litres of the tank by template id or style id. */\n tankCapacities?: Record<string, number>\n}\n\ntype Cache = { build: ConstructionBuild; roof?: Roof }\nconst CACHE = new WeakMap<object, Cache>()\n\nconst cacheOf = (result: object): Cache => {\n const cache = CACHE.get(result)\n if (!cache) throw new Error('The construction extension did not run for this plan')\n return cache\n}\n\nfunction constructionExtension(context: ResultExtensionContext): unknown {\n const build = constructionFor({ result: context.result as never, seed: context.seed, template: context.plan.tpl as never, options: context.options })\n CACHE.set(context.result, { build })\n return build.construction\n}\n\nfunction structureExtension(context: ResultExtensionContext): unknown {\n const cache = cacheOf(context.result)\n const options: StructureOptions = { construction: cache.build.construction, extras: cache.build.extras ?? {}, tank: context.result.waterTank ?? null, wallDetail: (context.options.wallDetail ?? 'panels') as WallDetail }\n const { roof, ...structure } = buildStructure(context.result, options)\n cache.roof = roof\n for (const part of structure.parts) {\n if (part.door === undefined || part.steps === undefined) continue\n const door = context.result.doors.find((d: { id: string }) => d.id === part.door)\n if (door) door.steps = part.steps\n }\n return structure\n}\n\nconst COOKING_CYLINDER = { type: 'cooking_gas_cylinder', category: 'cooking_gas_cylinder', w: 0.36, d: 0.36, h: 0.48 }\n\nfunction energyOf(context: ResultExtensionContext): EnergyConfig | undefined {\n const energy = context.plan.tpl.energy\n return typeof energy === 'function' ? energy(context.options, context.plan.w, context.plan.d) : undefined\n}\n\n/**\n * Registers the structure into the engine: `result.construction`, `result.structureExtras`, `result.waterTank`, `result.structure` and `result.roof` of every plan,\n * and the structure layer of the 2D viewer. Register the content packs first.\n */\nexport function register(engine: FloorplanEngine, options: StructurePackOptions = {}): void {\n engine.registerLocale('en', enLocale)\n engine.registerLocale('pt-BR', ptBrLocale)\n engine.registerResultExtension('construction', constructionExtension)\n engine.registerResultExtension('structureExtras', (context) => cacheOf(context.result).build.extras ?? {}, { after: ['construction'] })\n engine.registerResultExtension(\n 'waterTank',\n (context) => {\n const tank: TankPlanOptions = { capacities: options.tankCapacities, custom: context.plan.tpl.tank, location: context.plan.tpl.tankLocation }\n return planWaterTank(context.result as never, context.rng, tank)\n },\n { after: ['construction'], seedKey: 'caixa' },\n )\n engine.registerResultExtension('structure', structureExtension, { after: ['construction', 'structureExtras', 'waterTank'] })\n engine.registerResultExtension('roof', (context) => cacheOf(context.result).roof ?? null, { after: ['structure'] })\n engine.registerViewerLayer(structureLayer)\n engine.registerItem(COOKING_CYLINDER)\n engine.registerResultExtension('contents', (context) => planContents({ items: context.result.items, state: context.result.state, place: context.plan.tpl.place ?? 'house', ...(typeof context.options.day === 'number' ? { day: context.options.day } : {}), ...(typeof context.options.region === 'string' ? { region: context.options.region } : {}), rngFor: (key) => engine.createRng(context.seed, key), findsFor: (query) => { const answered = engine.findsAnswer(query); return answered ?? contentOf({ container: query.container, state: query.state, rng: query.rng, footprint: query.footprint ?? 0.5 }) } }))\n engine.registerResultExtension('outbuildings', (context) => {\n const outbuildings = planOutbuildings({ plan: context.plan, items: context.result.items, catalog: engine.catalog, rngFor: (key) => engine.createRng(context.seed, key) })\n if (context.result.lot) addOutbuildingPaths(context.result.lot, outbuildings, context.result.items)\n return outbuildings\n }, { after: ['contents'] })\n engine.registerResultExtension('utilities', (context) => planUtilities({ plan: context.plan, items: context.result.items, stateItems: context.result.stateItems, tank: context.result.waterTank ?? null, ...(energyOf(context) ? { energy: energyOf(context) } : {}), rngFor: (key) => engine.createRng(context.seed, key) }), { after: ['outbuildings', 'waterTank'] })\n}\n","import type { ChainDelay, ExplosionChain, PartSpec } from './types'\n\n/** What can set an explosive part off from outside, in the order a hit can carry it. */\nexport type ChainTrigger = 'shot' | 'fire' | 'explosion'\n\n/** Temperature in °C that primes a part with `chain.fire` when its `explodes.atC` is not set. */\nexport const FIRE_PRIME_C = 300\n\n/** Seconds from a trigger to the blast: a number is fixed, `[min, max]` is drawn from the world seed (one draw). */\nexport const drawChainDelay = (delay: ChainDelay, random: () => number): number => {\n if (typeof delay === 'number') return delay\n const [min, max] = delay\n return min + random() * (max - min)\n}\n\n/** The delay `spec` gives for `trigger`, or undefined when the part does not answer to it. */\nexport const chainDelayOf = (spec: PartSpec, trigger: ChainTrigger): ChainDelay | undefined => spec.explodes?.chain?.[trigger]\n\n/** Fraction of the hit points a shot must have taken off before it primes the part. */\nexport const shotDamageFractionOf = (spec: PartSpec): number => spec.explodes?.chain?.shotDamageFraction ?? 0\n\n/** The numbers of an explosive that sits in the world, as `game-weapons` gives them (`ExplosiveDef` fits). */\nexport interface WorldExplosive {\n readonly energy: number\n /** Metres within which the blast reaches other parts (and primes theirs). */\n readonly injuryRadius: number\n readonly chain?: ExplosionChain\n}\n\nexport interface ExplosivePartOptions {\n /** Temperature in °C at which fire primes (or sets off) the part; default `FIRE_PRIME_C` when the explosive answers to fire. */\n readonly atC?: number\n}\n\n/**\n * A part that explodes with the energy and reach of `explosive` and answers to what `explosive.chain` says: a bullet, fire or a blast\n * nearby primes it and it goes off after the delay. `part` is everything else about the part (shape, material, position, fluid inside).\n */\nexport const explosivePart = (explosive: WorldExplosive, part: Omit<PartSpec, 'explodes'>, options: ExplosivePartOptions = {}): PartSpec => ({\n ...part,\n explodes: {\n energy: explosive.energy,\n radius: explosive.injuryRadius,\n ...(options.atC !== undefined ? { atC: options.atC } : {}),\n ...(explosive.chain ? { chain: { ...explosive.chain } } : {}),\n },\n})\n","import type { PartShape, Quat, Vec3 } from './types'\n\nconst EPS = 1e-9\n\n/** Small vector helpers (arrays of three numbers). Pure functions; they allocate a new array. */\nexport const vec = {\n add: (a: Vec3, b: Vec3): Vec3 => [a[0] + b[0], a[1] + b[1], a[2] + b[2]],\n sub: (a: Vec3, b: Vec3): Vec3 => [a[0] - b[0], a[1] - b[1], a[2] - b[2]],\n scale: (a: Vec3, s: number): Vec3 => [a[0] * s, a[1] * s, a[2] * s],\n dot: (a: Vec3, b: Vec3): number => a[0] * b[0] + a[1] * b[1] + a[2] * b[2],\n cross: (a: Vec3, b: Vec3): Vec3 => [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]],\n length: (a: Vec3): number => Math.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]),\n distance: (a: Vec3, b: Vec3): number => Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]),\n normalize: (a: Vec3, fallback: Vec3 = [0, 1, 0]): Vec3 => {\n const l = Math.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2])\n return l < EPS ? [fallback[0], fallback[1], fallback[2]] : [a[0] / l, a[1] / l, a[2] / l]\n },\n lerp: (a: Vec3, b: Vec3, t: number): Vec3 => [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t, a[2] + (b[2] - a[2]) * t],\n /** `a + b * s` */\n madd: (a: Vec3, b: Vec3, s: number): Vec3 => [a[0] + b[0] * s, a[1] + b[1] * s, a[2] + b[2] * s],\n}\n\nconst IDENTITY: Quat = [0, 0, 0, 1]\n\n/** Quaternion helpers (`[x, y, z, w]`). */\nexport const quat = {\n identity: (): Quat => [IDENTITY[0], IDENTITY[1], IDENTITY[2], IDENTITY[3]],\n /** Hamilton product `a * b` (apply `b` first, then `a`). */\n mul: (a: Quat, b: Quat): Quat => [\n a[3] * b[0] + a[0] * b[3] + a[1] * b[2] - a[2] * b[1],\n a[3] * b[1] - a[0] * b[2] + a[1] * b[3] + a[2] * b[0],\n a[3] * b[2] + a[0] * b[1] - a[1] * b[0] + a[2] * b[3],\n a[3] * b[3] - a[0] * b[0] - a[1] * b[1] - a[2] * b[2],\n ],\n conjugate: (q: Quat): Quat => [-q[0], -q[1], -q[2], q[3]],\n normalize: (q: Quat): Quat => {\n const l = Math.hypot(q[0], q[1], q[2], q[3])\n return l < EPS ? [0, 0, 0, 1] : [q[0] / l, q[1] / l, q[2] / l, q[3] / l]\n },\n /** Rotation of `angle` radians around a unit `axis`. */\n fromAxisAngle: (axis: Vec3, angle: number): Quat => {\n const s = Math.sin(angle / 2)\n return [axis[0] * s, axis[1] * s, axis[2] * s, Math.cos(angle / 2)]\n },\n /** Rotation matrix, row-major 3x3. */\n toMatrix: (q: Quat): number[] => {\n const [x, y, z, w] = q\n const xx = x * x, yy = y * y, zz = z * z, xy = x * y, xz = x * z, yz = y * z, wx = w * x, wy = w * y, wz = w * z\n return [1 - 2 * (yy + zz), 2 * (xy - wz), 2 * (xz + wy), 2 * (xy + wz), 1 - 2 * (xx + zz), 2 * (yz - wx), 2 * (xz - wy), 2 * (yz + wx), 1 - 2 * (xx + yy)]\n },\n /** Quaternion from three orthonormal columns (the images of the x, y and z axes). */\n fromColumns: (cx: Vec3, cy: Vec3, cz: Vec3): Quat => {\n const m00 = cx[0], m10 = cx[1], m20 = cx[2]\n const m01 = cy[0], m11 = cy[1], m21 = cy[2]\n const m02 = cz[0], m12 = cz[1], m22 = cz[2]\n const tr = m00 + m11 + m22\n let q: Quat\n if (tr > 0) {\n const s = Math.sqrt(tr + 1) * 2\n q = [(m21 - m12) / s, (m02 - m20) / s, (m10 - m01) / s, 0.25 * s]\n } else if (m00 > m11 && m00 > m22) {\n const s = Math.sqrt(1 + m00 - m11 - m22) * 2\n q = [0.25 * s, (m01 + m10) / s, (m02 + m20) / s, (m21 - m12) / s]\n } else if (m11 > m22) {\n const s = Math.sqrt(1 + m11 - m00 - m22) * 2\n q = [(m01 + m10) / s, 0.25 * s, (m12 + m21) / s, (m02 - m20) / s]\n } else {\n const s = Math.sqrt(1 + m22 - m00 - m11) * 2\n q = [(m02 + m20) / s, (m12 + m21) / s, 0.25 * s, (m10 - m01) / s]\n }\n return quat.normalize(q)\n },\n}\n\n/** Quaternion from Euler angles in radians, order XYZ (the three.js default). */\nexport const quatFromEuler = (x: number, y: number, z: number): Quat => {\n const c1 = Math.cos(x / 2), c2 = Math.cos(y / 2), c3 = Math.cos(z / 2)\n const s1 = Math.sin(x / 2), s2 = Math.sin(y / 2), s3 = Math.sin(z / 2)\n return [s1 * c2 * c3 + c1 * s2 * s3, c1 * s2 * c3 - s1 * c2 * s3, c1 * c2 * s3 + s1 * s2 * c3, c1 * c2 * c3 - s1 * s2 * s3]\n}\n\n/** Rotate a vector by a quaternion. */\nexport const rotateVec = (q: Quat, v: Vec3): Vec3 => {\n const qx = q[0], qy = q[1], qz = q[2], qw = q[3]\n const tx = 2 * (qy * v[2] - qz * v[1])\n const ty = 2 * (qz * v[0] - qx * v[2])\n const tz = 2 * (qx * v[1] - qy * v[0])\n return [v[0] + qw * tx + (qy * tz - qz * ty), v[1] + qw * ty + (qz * tx - qx * tz), v[2] + qw * tz + (qx * ty - qy * tx)]\n}\n\n/** World point to the local space of a transform (`position`, `rotation`). */\nexport const toLocal = (position: Vec3, rotation: Quat, p: Vec3): Vec3 =>\n rotateVec([-rotation[0], -rotation[1], -rotation[2], rotation[3]], [p[0] - position[0], p[1] - position[1], p[2] - position[2]])\n\n/** Local point of a transform (`position`, `rotation`) to world space. */\nexport const toWorld = (position: Vec3, rotation: Quat, p: Vec3): Vec3 => {\n const r = rotateVec(rotation, p)\n return [r[0] + position[0], r[1] + position[1], r[2] + position[2]]\n}\n\n// ---------------------------------------------------------------------------------------------------------------------------------------------\n// Shapes (part space: centred on the origin, cylinders along +Y)\n// ---------------------------------------------------------------------------------------------------------------------------------------------\n\n/** Dimensions of the bounding box of a shape, in the shape's own axes. */\nexport const shapeDims = (s: PartShape): Vec3 => {\n if (s.kind === 'box') return [s.size[0], s.size[1], s.size[2]]\n if (s.kind === 'cylinder') return [s.radius * 2, s.height, s.radius * 2]\n return [s.radius * 2, s.radius * 2, s.radius * 2]\n}\n\n/** Radius of the sphere that encloses the shape. */\nexport const shapeBound = (s: PartShape): number => {\n if (s.kind === 'box') return 0.5 * Math.hypot(s.size[0], s.size[1], s.size[2])\n if (s.kind === 'cylinder') return Math.hypot(s.radius, s.height / 2)\n return s.radius\n}\n\nexport const shapeArea = (s: PartShape): number => {\n if (s.kind === 'box') return 2 * (s.size[0] * s.size[1] + s.size[1] * s.size[2] + s.size[0] * s.size[2])\n if (s.kind === 'cylinder') return 2 * Math.PI * s.radius * s.height + 2 * Math.PI * s.radius * s.radius\n return 4 * Math.PI * s.radius * s.radius\n}\n\nexport interface ShapeRay {\n /** Entry distance along the ray (negative when the origin is inside). */\n t0: number\n /** Normal at the entry, outward. */\n n0: Vec3\n /** Exit distance. */\n t1: number\n /** Normal at the exit, outward. */\n n1: Vec3\n}\n\n/** Exact ray intersection with a shape in part space. `d` need not be normalised but must be non-zero. */\nexport const rayShape = (s: PartShape, o: Vec3, d: Vec3): ShapeRay | null => {\n if (s.kind === 'box') {\n let tmin = -Infinity, tmax = Infinity\n let a0 = 0, a1 = 0, s0 = 1, s1 = 1\n for (let i = 0; i < 3; i++) {\n const h = s.size[i] / 2\n if (Math.abs(d[i]) < EPS) {\n if (Math.abs(o[i]) > h) return null\n continue\n }\n let ta = (-h - o[i]) / d[i]\n let tb = (h - o[i]) / d[i]\n let sa = -1, sb = 1\n if (ta > tb) {\n const t = ta\n ta = tb\n tb = t\n sa = 1\n sb = -1\n }\n if (ta > tmin) {\n tmin = ta\n a0 = i\n s0 = sa\n }\n if (tb < tmax) {\n tmax = tb\n a1 = i\n s1 = sb\n }\n if (tmin > tmax) return null\n }\n if (tmax < 0 || !Number.isFinite(tmin) || !Number.isFinite(tmax)) return null\n const n0: Vec3 = [0, 0, 0]\n const n1: Vec3 = [0, 0, 0]\n n0[a0] = s0\n n1[a1] = s1\n return { t0: tmin, n0, t1: tmax, n1 }\n }\n if (s.kind === 'sphere') {\n const b = vec.dot(o, d)\n const a = vec.dot(d, d)\n const c = vec.dot(o, o) - s.radius * s.radius\n const disc = b * b - a * c\n if (disc < 0) return null\n const sq = Math.sqrt(disc)\n const t0 = (-b - sq) / a\n const t1 = (-b + sq) / a\n if (t1 < 0) return null\n const p0 = vec.madd(o, d, t0)\n const p1 = vec.madd(o, d, t1)\n return { t0, n0: vec.normalize(p0), t1, n1: vec.normalize(p1) }\n }\n // cylinder along Y: intersection of the infinite cylinder interval and the y slab\n const r = s.radius\n const hh = s.height / 2\n const a = d[0] * d[0] + d[2] * d[2]\n const c = o[0] * o[0] + o[2] * o[2] - r * r\n let tA = -Infinity, tB = Infinity\n if (a > EPS) {\n const b = o[0] * d[0] + o[2] * d[2]\n const disc = b * b - a * c\n if (disc < 0) return null\n const sq = Math.sqrt(disc)\n tA = (-b - sq) / a\n tB = (-b + sq) / a\n } else if (c > 0) return null\n let yA = -Infinity, yB = Infinity\n if (Math.abs(d[1]) > EPS) {\n yA = (-hh - o[1]) / d[1]\n yB = (hh - o[1]) / d[1]\n if (yA > yB) {\n const t = yA\n yA = yB\n yB = t\n }\n } else if (Math.abs(o[1]) > hh) return null\n const t0 = Math.max(tA, yA)\n const t1 = Math.min(tB, yB)\n if (t0 > t1 || t1 < 0 || !Number.isFinite(t0) || !Number.isFinite(t1)) return null\n const normalAt = (t: number, fromSide: boolean, sign: number): Vec3 => {\n if (fromSide) {\n const p = vec.madd(o, d, t)\n return vec.normalize([p[0], 0, p[2]], [1, 0, 0])\n }\n return [0, sign, 0]\n }\n const n0 = normalAt(t0, tA >= yA, d[1] > 0 ? -1 : 1)\n const n1 = normalAt(t1, tB <= yB, d[1] > 0 ? 1 : -1)\n return { t0, n0, t1, n1 }\n}\n\n/** Distance from a part-space point to the shape (0 inside). */\nexport const distanceToShape = (s: PartShape, p: Vec3): number => {\n if (s.kind === 'box') {\n const dx = Math.max(Math.abs(p[0]) - s.size[0] / 2, 0)\n const dy = Math.max(Math.abs(p[1]) - s.size[1] / 2, 0)\n const dz = Math.max(Math.abs(p[2]) - s.size[2] / 2, 0)\n return Math.hypot(dx, dy, dz)\n }\n if (s.kind === 'sphere') return Math.max(0, vec.length(p) - s.radius)\n const dr = Math.max(0, Math.hypot(p[0], p[2]) - s.radius)\n const dy = Math.max(0, Math.abs(p[1]) - s.height / 2)\n return Math.hypot(dr, dy)\n}\n\n/** Nearest point on the surface of a shape to a part-space point, with the outward normal. */\nexport const surfacePoint = (s: PartShape, p: Vec3): { point: Vec3; normal: Vec3 } => {\n if (s.kind === 'box') {\n const h: Vec3 = [s.size[0] / 2, s.size[1] / 2, s.size[2] / 2]\n const inside = Math.abs(p[0]) <= h[0] && Math.abs(p[1]) <= h[1] && Math.abs(p[2]) <= h[2]\n if (!inside) {\n const c: Vec3 = [Math.max(-h[0], Math.min(h[0], p[0])), Math.max(-h[1], Math.min(h[1], p[1])), Math.max(-h[2], Math.min(h[2], p[2]))]\n return { point: c, normal: vec.normalize(vec.sub(p, c)) }\n }\n let axis = 0\n let best = Infinity\n for (let i = 0; i < 3; i++) {\n const g = h[i] - Math.abs(p[i])\n if (g < best) {\n best = g\n axis = i\n }\n }\n const sign = p[axis] >= 0 ? 1 : -1\n const point: Vec3 = [p[0], p[1], p[2]]\n point[axis] = sign * h[axis]\n const normal: Vec3 = [0, 0, 0]\n normal[axis] = sign\n return { point, normal }\n }\n if (s.kind === 'sphere') {\n const n = vec.normalize(p)\n return { point: vec.scale(n, s.radius), normal: n }\n }\n const rho = Math.hypot(p[0], p[2])\n const hh = s.height / 2\n const inside = rho <= s.radius && Math.abs(p[1]) <= hh\n if (!inside) {\n const k = rho > s.radius ? s.radius / rho : 1\n const c: Vec3 = [p[0] * k, Math.max(-hh, Math.min(hh, p[1])), p[2] * k]\n return { point: c, normal: vec.normalize(vec.sub(p, c)) }\n }\n if (s.radius - rho < hh - Math.abs(p[1])) {\n const k = rho < EPS ? 0 : s.radius / rho\n const point: Vec3 = rho < EPS ? [s.radius, p[1], 0] : [p[0] * k, p[1], p[2] * k]\n return { point, normal: vec.normalize([point[0], 0, point[2]], [1, 0, 0]) }\n }\n const sign = p[1] >= 0 ? 1 : -1\n return { point: [p[0], sign * hh, p[2]], normal: [0, sign, 0] }\n}\n\n/** Axis-aligned bounds of a shape with a given centre and orientation. */\nexport const aabbOf = (s: PartShape, center: Vec3, q: Quat): { min: Vec3; max: Vec3 } => {\n let hx: number, hy: number, hz: number\n if (s.kind === 'sphere') {\n hx = hy = hz = s.radius\n } else {\n const m = quat.toMatrix(q)\n if (s.kind === 'box') {\n const a = s.size[0] / 2, b = s.size[1] / 2, c = s.size[2] / 2\n hx = Math.abs(m[0]) * a + Math.abs(m[1]) * b + Math.abs(m[2]) * c\n hy = Math.abs(m[3]) * a + Math.abs(m[4]) * b + Math.abs(m[5]) * c\n hz = Math.abs(m[6]) * a + Math.abs(m[7]) * b + Math.abs(m[8]) * c\n } else {\n const ax = [m[1], m[4], m[7]]\n const hh = s.height / 2\n const e = (i: number) => s.radius * Math.sqrt(Math.max(0, 1 - ax[i] * ax[i])) + hh * Math.abs(ax[i])\n hx = e(0)\n hy = e(1)\n hz = e(2)\n }\n }\n return { min: [center[0] - hx, center[1] - hy, center[2] - hz], max: [center[0] + hx, center[1] + hy, center[2] + hz] }\n}\n\n/** Seeded generator (mulberry32). The state is a single int32, so it round-trips through JSON. */\nexport interface Rng {\n next(): number\n state(): number\n set(state: number): void\n}\n\nexport const createRng = (seed: number): Rng => {\n let s = seed | 0\n return {\n next() {\n s = (s + 0x6d2b79f5) | 0\n let t = Math.imul(s ^ (s >>> 15), 1 | s)\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n },\n state: () => s,\n set(v) {\n s = v | 0\n },\n }\n}\n","import { quat } from './math'\nimport type { Fragment, FractureStyle, Quat, Vec3 } from './types'\n\n/** A fragment in the part's local space (centre, size in the fragment's own axes, orientation relative to the part). */\nexport interface PlannedFragment {\n center: Vec3\n size: Vec3\n q: Quat\n shape: Fragment['shape']\n /** Share of the part's mass (unnormalised). */\n weight: number\n}\n\nexport interface PlanInput {\n style: FractureStyle\n /** Bounding box dimensions in part axes. */\n dims: Vec3\n thickness: number\n /** Index 0..2 of the grain axis, if any. */\n grain?: number\n /** Impact point in part space. */\n hit: Vec3\n fragmentSize: [number, number]\n maxFragments: number\n rnd: () => number\n}\n\ninterface Box {\n c: Vec3\n s: Vec3\n}\n\n/** Split a box into `count` pieces by cutting the largest piece along its longest allowed axis. */\nconst bsp = (root: Box, count: number, axes: number[], rnd: () => number): Box[] => {\n const pieces: Box[] = [root]\n const vol = (b: Box) => axes.reduce((v, a) => v * b.s[a], 1)\n while (pieces.length < count) {\n let bi = 0\n for (let i = 1; i < pieces.length; i++) if (vol(pieces[i]) > vol(pieces[bi])) bi = i\n const b = pieces[bi]\n let ax = axes[0]\n for (const a of axes) if (b.s[a] > b.s[ax]) ax = a\n if (b.s[ax] < 1e-4) break\n const r = 0.3 + 0.4 * rnd()\n const l1 = b.s[ax] * r\n const l2 = b.s[ax] - l1\n const c1: Vec3 = [b.c[0], b.c[1], b.c[2]]\n const c2: Vec3 = [b.c[0], b.c[1], b.c[2]]\n c1[ax] = b.c[ax] - b.s[ax] / 2 + l1 / 2\n c2[ax] = b.c[ax] + b.s[ax] / 2 - l2 / 2\n const s1: Vec3 = [b.s[0], b.s[1], b.s[2]]\n const s2: Vec3 = [b.s[0], b.s[1], b.s[2]]\n s1[ax] = l1\n s2[ax] = l2\n pieces[bi] = { c: c1, s: s1 }\n pieces.push({ c: c2, s: s2 })\n }\n return pieces\n}\n\nconst parity = (p: [number, number, number]): number => {\n let inv = 0\n for (let i = 0; i < 3; i++) for (let j = i + 1; j < 3; j++) if (p[i] > p[j]) inv++\n return inv % 2 === 0 ? 1 : -1\n}\n\n/** Orientation whose x, y, z axes are the part axes `ax`, `ay`, `az`, then rotated by `angle` around its own z. */\nconst frame = (ax: number, ay: number, az: number, angle = 0): Quat => {\n const e = (i: number): Vec3 => [i === 0 ? 1 : 0, i === 1 ? 1 : 0, i === 2 ? 1 : 0]\n const z = e(az)\n const sg = parity([ax, ay, az])\n const q = quat.fromColumns(e(ax), e(ay), [z[0] * sg, z[1] * sg, z[2] * sg])\n return angle === 0 ? q : quat.mul(q, quat.fromAxisAngle([0, 0, 1], angle))\n}\n\nconst clamp = (v: number, a: number, b: number) => Math.max(a, Math.min(b, v))\n\n/** Deterministic fragment layout for a failed part, in part space. */\nexport const planFragments = (inp: PlanInput): PlannedFragment[] => {\n const { style, dims, rnd, maxFragments } = inp\n const [fmin, fmax] = inp.fragmentSize\n const mean = (fmin + fmax) / 2\n const root: Box = { c: [0, 0, 0], s: [dims[0], dims[1], dims[2]] }\n const idq = quat.identity()\n const out: PlannedFragment[] = []\n const sorted = [0, 1, 2].sort((a, b) => dims[a] - dims[b])\n const t = sorted[0]\n const [u, v] = [sorted[1], sorted[2]].sort((a, b) => a - b)\n\n if (style === 'snap') {\n const n = Math.min(maxFragments, 2 + Math.floor(rnd() * 3))\n for (const b of bsp(root, n, [0, 1, 2], rnd)) out.push({ center: b.c, size: b.s, q: idq, shape: 'slab', weight: b.s[0] * b.s[1] * b.s[2] })\n return out\n }\n if (style === 'crumble' || style === 'none') {\n const n = clamp(Math.ceil((dims[0] * dims[1] * dims[2]) / (mean * mean * mean)), 4, maxFragments)\n for (const b of bsp(root, n, [0, 1, 2], rnd)) out.push({ center: b.c, size: b.s, q: idq, shape: 'chunk', weight: b.s[0] * b.s[1] * b.s[2] })\n return out\n }\n if (style === 'splinter') {\n const g = inp.grain ?? [0, 1, 2].sort((a, b) => dims[b] - dims[a])[0]\n const [a, b] = [0, 1, 2].filter((i) => i !== g)\n const w = Math.max(fmin * 1.5, 0.01)\n const c = clamp(Math.round((dims[a] * dims[b]) / (w * w)), 3, Math.max(3, Math.floor(maxFragments / 2)))\n const maxLen = fmax * 4\n const cells = bsp(root, c, [a, b], rnd)\n const pieces: Box[] = []\n for (const cell of cells) {\n let list = [cell]\n const extra = rnd() < 0.4 ? 1 : 0\n const k = Math.max(1, Math.ceil(dims[g] / maxLen)) + extra\n list = bsp(cell, k, [g], rnd)\n for (const p of list) pieces.push(p)\n }\n for (const p of pieces.slice(0, maxFragments)) {\n out.push({ center: p.c, size: [p.s[g], p.s[a], p.s[b]], q: frame(g, a, b), shape: 'splinter', weight: p.s[0] * p.s[1] * p.s[2] })\n }\n return out\n }\n if (style === 'tear') {\n const n = clamp(Math.round((dims[u] * dims[v]) / (mean * mean)), 3, maxFragments)\n const th = Math.min(inp.thickness, dims[t])\n for (const b of bsp(root, n, [u, v], rnd)) {\n out.push({ center: [b.c[0], b.c[1], b.c[2]], size: [b.s[u], b.s[v], th], q: frame(u, v, t), shape: 'scrap', weight: b.s[u] * b.s[v] })\n }\n return out\n }\n // shatter: thin shards radiating from the impact\n const th = Math.min(inp.thickness, dims[t])\n const Hu = dims[u] / 2, Hv = dims[v] / 2\n const hu = clamp(inp.hit[u], -Hu * 0.95, Hu * 0.95)\n const hv = clamp(inp.hit[v], -Hv * 0.95, Hv * 0.95)\n const R = Math.max(Math.hypot(Hu + Math.abs(hu), Hv + Math.abs(hv)), 0.02)\n const n = clamp(Math.round((dims[u] * dims[v]) / (mean * mean)), 6, maxFragments)\n const sectors = clamp(Math.round(Math.sqrt(n * 1.6)), 5, 10)\n const rings = Math.max(1, Math.ceil(n / sectors))\n const radii: number[] = []\n for (let k = 0; k <= rings; k++) radii.push(R * Math.pow(k / rings, 1.3))\n const cap = fmax * 1.5\n for (let j = 0; j < sectors && out.length < maxFragments; j++) {\n const theta = (j + (rnd() - 0.5) * 0.4) * ((Math.PI * 2) / sectors)\n for (let k = 0; k < rings && out.length < maxFragments; k++) {\n const rm = (radii[k] + radii[k + 1]) / 2\n const cu = hu + rm * Math.cos(theta)\n const cv = hv + rm * Math.sin(theta)\n if (Math.abs(cu) > Hu + 0.01 || Math.abs(cv) > Hv + 0.01) continue\n const radial = clamp(radii[k + 1] - radii[k], 0.01, cap)\n const tang = clamp(radii[k + 1] * ((Math.PI * 2) / sectors) * 0.9, 0.01, cap)\n const c: Vec3 = [0, 0, 0]\n c[u] = clamp(cu, -Hu * 0.98, Hu * 0.98)\n c[v] = clamp(cv, -Hv * 0.98, Hv * 0.98)\n c[t] = 0\n out.push({ center: c, size: [radial, tang, th], q: frame(u, v, t, theta), shape: 'shard', weight: radial * tang })\n }\n }\n if (out.length === 0) out.push({ center: [0, 0, 0], size: [dims[u], dims[v], th], q: frame(u, v, t), shape: 'shard', weight: 1 })\n return out\n}\n","import { quat, rotateVec } from './math'\nimport type { FragmentMark, PartUnits, Quat, Vec3 } from './types'\n\n/** One masonry unit (or panel) cut out of a wall, in the part's own axes. */\nexport interface UnitCell {\n center: Vec3\n size: Vec3\n}\n\n/** The two axes a wall spreads along: height is local y unless the part is thin along y (a slab), then x and z. */\nexport const planeAxes = (thin: number): [number, number] => (thin === 1 ? [0, 2] : [thin === 0 ? 2 : 0, 1])\n\n/**\n * Every unit of the wall laid in `bond`: rows along the plane's second axis, running bond shifts odd rows by half a unit, edge units are cut to\n * the wall. More than `cap` units are merged into bigger ones (the same bond) so a whole wall stays a drawable number of fragments.\n */\nexport const unitGrid = (dims: Vec3, thin: number, units: Pick<PartUnits, 'size' | 'bond'>, cap: number): UnitCell[] => {\n const [u, v] = planeAxes(thin)\n let unitU = Math.min(units.size[0], dims[u]), unitV = Math.min(units.size[1], dims[v])\n const rowsFor = (h: number): number => Math.ceil(dims[v] / h - 1e-9)\n const colsFor = (w: number): number => Math.ceil(dims[u] / w - 1e-9) + (units.bond === 'running' ? 1 : 0)\n const merge = Math.ceil(Math.sqrt((rowsFor(unitV) * colsFor(unitU)) / cap))\n if (merge > 1) {\n unitU = Math.min(unitU * merge, dims[u])\n unitV = Math.min(unitV * merge, dims[v])\n }\n const cells: UnitCell[] = []\n for (let row = 0; row < rowsFor(unitV); row++) {\n const v0 = -dims[v] / 2 + row * unitV, v1 = Math.min(v0 + unitV, dims[v] / 2)\n const shift = units.bond === 'running' && row % 2 === 1 ? unitU / 2 : 0\n for (let col = 0; col < colsFor(unitU); col++) {\n const u0 = Math.max(-dims[u] / 2 + col * unitU - shift, -dims[u] / 2), u1 = Math.min(-dims[u] / 2 + (col + 1) * unitU - shift, dims[u] / 2)\n if (u1 - u0 < 0.01) continue\n const center: Vec3 = [0, 0, 0], size: Vec3 = [0, 0, 0]\n center[u] = (u0 + u1) / 2\n center[v] = (v0 + v1) / 2\n size[u] = u1 - u0\n size[v] = v1 - v0\n size[thin] = dims[thin]\n cells.push({ center, size })\n }\n }\n return cells\n}\n\nconst planeDistance = (cell: UnitCell, thin: number, point: Vec3): number => {\n const [u, v] = planeAxes(thin)\n const du = cell.center[u] - point[u], dv = cell.center[v] - point[v]\n return Math.sqrt(du * du + dv * dv)\n}\n\n/** Units whose centre is within `radius` of `point` (part-local) in the wall plane; at least the nearest one. */\nexport const cellsWithin = (cells: readonly UnitCell[], thin: number, point: Vec3, radius: number): UnitCell[] => {\n const inside = cells.filter((c) => planeDistance(c, thin, point) <= radius)\n if (inside.length > 0 || cells.length === 0) return inside\n return [cells.reduce((best, c) => (planeDistance(c, thin, point) < planeDistance(best, thin, point) ? c : best))]\n}\n\nexport const cellsOutside = (cells: readonly UnitCell[], thin: number, point: Vec3, radius: number): UnitCell[] => cells.filter((c) => planeDistance(c, thin, point) > radius)\n\n/** A hole in the part's own axes. */\nexport interface LocalHole {\n point: Vec3\n normal: Vec3\n diameter: number\n}\n\nexport const MAX_MARKS_PER_FRAGMENT = 12\n\n/** The holes that fall inside a fragment box (`rotation` is the fragment's orientation in the part), in the fragment's own axes. */\nexport const marksInBox = (center: Vec3, size: Vec3, rotation: Quat | undefined, holes: readonly LocalHole[]): FragmentMark[] => {\n const inverse = rotation ? quat.conjugate(rotation) : undefined\n const marks: FragmentMark[] = []\n for (const hole of holes) {\n const offset: Vec3 = [hole.point[0] - center[0], hole.point[1] - center[1], hole.point[2] - center[2]]\n const point = inverse ? rotateVec(inverse, offset) : offset\n const inside = point.every((value, k) => Math.abs(value) <= size[k]! / 2 + hole.diameter / 2)\n if (!inside) continue\n marks.push({ point, normal: inverse ? rotateVec(inverse, hole.normal) : hole.normal, diameter: hole.diameter })\n if (marks.length >= MAX_MARKS_PER_FRAGMENT) break\n }\n return marks\n}\n","import type { MaterialDef, SurfaceLayer, Vec3 } from './types'\n\n/** A surface layer with its material resolved; `energy` is what a bullet spends crossing one face's worth of it, in joules. */\nexport interface LayerRT {\n index: number\n def: SurfaceLayer\n mat: MaterialDef\n energy: number\n}\n\n/** `[layer, face (+1 or -1), x, y, z, radius]`: a patch of a layer that came off, in object-local space. Saved with the part. */\nexport type Spall = readonly [number, number, number, number, number, number]\n\nexport const MAX_SPALLS = 64\n\n/** Index of the smallest dimension (the first one on a tie): the axis a wall is thin along. */\nexport const thinAxisOf = (dims: Vec3): number => (dims[0] <= dims[1] && dims[0] <= dims[2] ? 0 : dims[1] <= dims[2] ? 1 : 2)\n\nexport const resolveLayer = (def: SurfaceLayer, index: number, mat: MaterialDef): LayerRT => ({ index, def, mat, energy: mat.penetration * def.thickness * 1000 })\n\nconst onFace = (layer: LayerRT, face: number): boolean => layer.def.faces === 'both' || layer.def.faces === (face > 0 ? '+' : '-')\n\nconst isSpalled = (spalls: readonly Spall[] | undefined, layer: number, face: number, point: Vec3): boolean => {\n for (const s of spalls ?? []) {\n if (s[0] !== layer || s[1] !== face) continue\n const dx = s[2] - point[0], dy = s[3] - point[1], dz = s[4] - point[2]\n if (dx * dx + dy * dy + dz * dz <= s[5] * s[5]) return true\n }\n return false\n}\n\n/** The outermost layer still on `face` at `point` (layers are listed outermost first). */\nexport const outerLayer = (layers: readonly LayerRT[], spalls: readonly Spall[] | undefined, face: number, point: Vec3): LayerRT | undefined =>\n layers.find((l) => onFace(l, face) && !isSpalled(spalls, l.index, face, point))\n\n/** Joules a bullet spends crossing every layer still on `face` at `point`. */\nexport const layersEnergy = (layers: readonly LayerRT[], spalls: readonly Spall[] | undefined, face: number, point: Vec3): number => {\n let sum = 0\n for (const l of layers) if (onFace(l, face) && !isSpalled(spalls, l.index, face, point)) sum += l.energy\n return sum\n}\n\n/** Metres of layer a ray crosses on one face (full thickness, before obliquity). */\nexport const layersThickness = (layers: readonly LayerRT[], face: number): number => {\n let sum = 0\n for (const l of layers) if (onFace(l, face)) sum += l.def.thickness\n return sum\n}\n","import type { Vec3 } from './types'\n\n/** A bar as two end points. */\nexport type Bar = [Vec3, Vec3]\n\nconst COVER = 0.03\nconst MAX_BARS_PER_DIRECTION = 24\nconst MAX_MEMBER_BARS_PER_SIDE = 6\nconst STEEL_DENSITY = 7850\n\n/** Positions centred on 0 with exact `spacing`, as many as fit inside `length - 2 * cover` (at least two, at most `cap`). */\nconst spread = (length: number, cover: number, spacing: number, cap: number): number[] => {\n const room = Math.max(0, length - 2 * cover)\n const count = Math.min(cap, Math.max(2, Math.floor(room / spacing) + 1))\n const step = count > 1 && room / (count - 1) < spacing ? room / (count - 1) : spacing\n return Array.from({ length: count }, (_, i) => (i - (count - 1) / 2) * step)\n}\n\nconst bar = (axis: number, along: number, fixed: Array<[number, number]>): Bar => {\n const a: Vec3 = [0, 0, 0], b: Vec3 = [0, 0, 0]\n for (const [index, value] of fixed) {\n a[index] = value\n b[index] = value\n }\n a[axis] = -along\n b[axis] = along\n return [a, b]\n}\n\n/** Long members (columns, beams): two smaller dimensions close to each other and a much longer third one. */\nconst isMember = (dims: Vec3): boolean => {\n const [a = 0, b = 0, c = 0] = [...dims].sort((x, y) => x - y)\n return b / a < 3 && c / b >= 3\n}\n\n/**\n * Rebar of a box in the part's own axes. Plates (walls, slabs) get a grid along each of the two large axes at mid thickness; long members get\n * bars along their length at the perimeter of the section. `thin` is the axis the part is thinnest along.\n */\nexport const rebarBars = (dims: Vec3, thin: number, spacing: number): Bar[] => {\n const out: Bar[] = []\n if (isMember(dims)) {\n const long = dims.indexOf(Math.max(...dims))\n const [u = 0, v = 0] = [0, 1, 2].filter((i) => i !== long)\n const us = spread(dims[u], COVER, spacing, MAX_MEMBER_BARS_PER_SIDE)\n const vs = spread(dims[v], COVER, spacing, MAX_MEMBER_BARS_PER_SIDE)\n us.forEach((x, i) => vs.forEach((y, j) => {\n if (i === 0 || j === 0 || i === us.length - 1 || j === vs.length - 1) out.push(bar(long, dims[long] / 2 - 0.02, [[u, x], [v, y]]))\n }))\n return out\n }\n const [u = 0, v = 0] = [0, 1, 2].filter((i) => i !== thin)\n for (const y of spread(dims[v], COVER, spacing, MAX_BARS_PER_DIRECTION)) out.push(bar(u, dims[u] / 2 - 0.02, [[v, y], [thin, 0]]))\n for (const x of spread(dims[u], COVER, spacing, MAX_BARS_PER_DIRECTION)) out.push(bar(v, dims[v] / 2 - 0.02, [[u, x], [thin, 0]]))\n return out\n}\n\n/** The part of each bar that lies within `radius` of `center` in the plane of axes `u` and `v` (bars that miss the disc are dropped). */\nexport const clipBarsToDisc = (bars: readonly Bar[], u: number, v: number, center: [number, number], radius: number): Bar[] => {\n const out: Bar[] = []\n for (const [a, b] of bars) {\n const axis = a[u] !== b[u] ? u : v\n const other = axis === u ? v : u\n const off = a[other] - center[other === u ? 0 : 1]\n if (Math.abs(off) >= radius) continue\n const half = Math.sqrt(radius * radius - off * off)\n const mid = center[axis === u ? 0 : 1]\n const lo = Math.max(Math.min(a[axis], b[axis]), mid - half), hi = Math.min(Math.max(a[axis], b[axis]), mid + half)\n if (hi - lo < 1e-6) continue\n const p: Vec3 = [a[0], a[1], a[2]], q: Vec3 = [b[0], b[1], b[2]]\n p[axis] = lo\n q[axis] = hi\n out.push([p, q])\n }\n return out\n}\n\n/** Steel mass in kg of bars of `diameter` metres. */\nexport const rebarMass = (bars: readonly Bar[], diameter: number, density = STEEL_DENSITY): number => {\n let length = 0\n for (const [a, b] of bars) length += Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]) + Math.abs(a[2] - b[2])\n return Math.PI * (diameter / 2) * (diameter / 2) * length * density\n}\n","[\n {\n \"id\": \"steel\",\n \"density\": 7850,\n \"hpPerKg\": 400,\n \"penetration\": 110,\n \"ductility\": 0.9,\n \"fracture\": \"none\",\n \"damageScale\": {\n \"slash\": 0.1,\n \"blunt\": 0.8\n },\n \"hitDebris\": \"sparks\",\n \"breakDebris\": \"sparks\",\n \"ricochetDeg\": 20,\n \"thermal\": {\n \"meltC\": 1450,\n \"meltRate\": 0.05,\n \"conductivity\": 0.5,\n \"heatCapacity\": 3\n },\n \"visual\": {\n \"glows\": true\n },\n \"tags\": [\n \"metal\",\n \"conductive\"\n ],\n \"compressive\": 2000000\n },\n {\n \"id\": \"cast_iron\",\n \"density\": 7200,\n \"hpPerKg\": 150,\n \"penetration\": 160,\n \"ductility\": 0.2,\n \"fracture\": \"snap\",\n \"fragmentSize\": [\n 0.08,\n 0.3\n ],\n \"damageScale\": {\n \"slash\": 0.1,\n \"blunt\": 1.2\n },\n \"hitDebris\": \"sparks\",\n \"breakDebris\": \"chips\",\n \"ricochetDeg\": 15,\n \"thermal\": {\n \"meltC\": 1200,\n \"meltRate\": 0.05,\n \"conductivity\": 0.45,\n \"heatCapacity\": 3\n },\n \"visual\": {\n \"glows\": true\n },\n \"tags\": [\n \"metal\",\n \"conductive\"\n ],\n \"compressive\": 1500000\n },\n {\n \"id\": \"aluminium\",\n \"density\": 2700,\n \"hpPerKg\": 250,\n \"penetration\": 60,\n \"ductility\": 0.85,\n \"fracture\": \"none\",\n \"damageScale\": {\n \"slash\": 0.2\n },\n \"hitDebris\": \"sparks\",\n \"breakDebris\": \"sparks\",\n \"ricochetDeg\": 15,\n \"thermal\": {\n \"meltC\": 660,\n \"meltRate\": 0.06,\n \"conductivity\": 0.8,\n \"heatCapacity\": 1.5\n },\n \"visual\": {\n \"glows\": true\n },\n \"tags\": [\n \"metal\",\n \"conductive\"\n ],\n \"compressive\": 800000\n },\n {\n \"id\": \"copper\",\n \"density\": 8960,\n \"hpPerKg\": 300,\n \"penetration\": 70,\n \"ductility\": 0.95,\n \"fracture\": \"none\",\n \"damageScale\": {\n \"slash\": 0.2\n },\n \"hitDebris\": \"sparks\",\n \"breakDebris\": \"sparks\",\n \"ricochetDeg\": 15,\n \"thermal\": {\n \"meltC\": 1085,\n \"meltRate\": 0.05,\n \"conductivity\": 1,\n \"heatCapacity\": 2.5\n },\n \"visual\": {\n \"glows\": true\n },\n \"tags\": [\n \"metal\",\n \"conductive\"\n ],\n \"compressive\": 1000000\n },\n {\n \"id\": \"wood_soft\",\n \"density\": 500,\n \"hpPerKg\": 90,\n \"penetration\": 9,\n \"ductility\": 0.35,\n \"fracture\": \"splinter\",\n \"fragmentSize\": [\n 0.03,\n 0.15\n ],\n \"damageScale\": {\n \"blunt\": 1.2,\n \"slash\": 1.5\n },\n \"hitDebris\": \"splinters\",\n \"breakDebris\": \"splinters\",\n \"thermal\": {\n \"ignitionC\": 300,\n \"flameC\": 800,\n \"fuelFraction\": 0.9,\n \"burnRate\": 0.012,\n \"conductivity\": 0.05,\n \"heatCapacity\": 1.2,\n \"smoke\": \"grey\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"wood\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 100000\n },\n {\n \"id\": \"wood_hard\",\n \"density\": 750,\n \"hpPerKg\": 140,\n \"penetration\": 14,\n \"ductility\": 0.3,\n \"fracture\": \"splinter\",\n \"fragmentSize\": [\n 0.03,\n 0.2\n ],\n \"damageScale\": {\n \"slash\": 1.2\n },\n \"hitDebris\": \"splinters\",\n \"breakDebris\": \"splinters\",\n \"thermal\": {\n \"ignitionC\": 330,\n \"flameC\": 800,\n \"fuelFraction\": 0.9,\n \"burnRate\": 0.01,\n \"conductivity\": 0.06,\n \"heatCapacity\": 1.4,\n \"smoke\": \"grey\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"wood\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 150000\n },\n {\n \"id\": \"plywood\",\n \"density\": 600,\n \"hpPerKg\": 70,\n \"penetration\": 7,\n \"ductility\": 0.3,\n \"fracture\": \"snap\",\n \"fragmentSize\": [\n 0.1,\n 0.4\n ],\n \"damageScale\": {\n \"slash\": 1.3\n },\n \"hitDebris\": \"splinters\",\n \"breakDebris\": \"splinters\",\n \"thermal\": {\n \"ignitionC\": 300,\n \"flameC\": 800,\n \"fuelFraction\": 0.85,\n \"burnRate\": 0.013,\n \"conductivity\": 0.05,\n \"heatCapacity\": 1.2,\n \"smoke\": \"grey\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"wood\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 60000\n },\n {\n \"id\": \"mdf\",\n \"density\": 750,\n \"hpPerKg\": 45,\n \"penetration\": 6,\n \"ductility\": 0.15,\n \"fracture\": \"snap\",\n \"fragmentSize\": [\n 0.08,\n 0.35\n ],\n \"hitDebris\": \"chips\",\n \"breakDebris\": \"dust\",\n \"thermal\": {\n \"ignitionC\": 290,\n \"flameC\": 750,\n \"fuelFraction\": 0.85,\n \"burnRate\": 0.014,\n \"conductivity\": 0.05,\n \"heatCapacity\": 1.2,\n \"smoke\": \"grey\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"wood\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 30000\n },\n {\n \"id\": \"glass\",\n \"density\": 2500,\n \"hpPerKg\": 12,\n \"penetration\": 6,\n \"ductility\": 0.02,\n \"fracture\": \"shatter\",\n \"fragmentSize\": [\n 0.05,\n 0.25\n ],\n \"damageScale\": {\n \"blunt\": 1.5,\n \"shelter\": 3\n },\n \"hitDebris\": \"shards\",\n \"breakDebris\": \"shards\",\n \"ricochetDeg\": 8,\n \"thermal\": {\n \"meltC\": 1400,\n \"meltRate\": 0.03,\n \"conductivity\": 0.1,\n \"heatCapacity\": 1.5,\n \"thermalShockC\": 150\n },\n \"visual\": {\n \"glows\": true,\n \"transparent\": true\n },\n \"tags\": [\n \"glass\",\n \"brittle\"\n ],\n \"compressive\": 100000\n },\n {\n \"id\": \"tempered_glass\",\n \"density\": 2500,\n \"hpPerKg\": 30,\n \"penetration\": 9,\n \"ductility\": 0.02,\n \"fracture\": \"crumble\",\n \"fragmentSize\": [\n 0.006,\n 0.02\n ],\n \"hitDebris\": \"shards\",\n \"breakDebris\": \"shards\",\n \"ricochetDeg\": 8,\n \"thermal\": {\n \"meltC\": 1400,\n \"meltRate\": 0.03,\n \"conductivity\": 0.1,\n \"heatCapacity\": 1.5,\n \"thermalShockC\": 250\n },\n \"visual\": {\n \"glows\": true,\n \"transparent\": true\n },\n \"tags\": [\n \"glass\",\n \"brittle\"\n ],\n \"compressive\": 200000,\n \"damageScale\": {\n \"shelter\": 3\n }\n },\n {\n \"id\": \"ceramic\",\n \"density\": 2400,\n \"hpPerKg\": 25,\n \"penetration\": 12,\n \"ductility\": 0.02,\n \"fracture\": \"shatter\",\n \"fragmentSize\": [\n 0.03,\n 0.12\n ],\n \"damageScale\": {\n \"blunt\": 1.3\n },\n \"hitDebris\": \"chips\",\n \"breakDebris\": \"shards\",\n \"thermal\": {\n \"conductivity\": 0.1,\n \"heatCapacity\": 1.5,\n \"thermalShockC\": 200\n },\n \"tags\": [\n \"ceramic\",\n \"brittle\"\n ],\n \"compressive\": 150000\n },\n {\n \"id\": \"concrete\",\n \"density\": 2300,\n \"hpPerKg\": 14,\n \"penetration\": 18,\n \"ductility\": 0.03,\n \"fracture\": \"crumble\",\n \"fragmentSize\": [\n 0.05,\n 0.25\n ],\n \"damageScale\": {\n \"explosive\": 1.2\n },\n \"hitDebris\": \"chips\",\n \"breakDebris\": \"dust\",\n \"thermal\": {\n \"conductivity\": 0.15,\n \"heatCapacity\": 2.5\n },\n \"tags\": [\n \"masonry\",\n \"brittle\"\n ],\n \"compressive\": 444000\n },\n {\n \"id\": \"brick\",\n \"density\": 1900,\n \"hpPerKg\": 12,\n \"penetration\": 14,\n \"ductility\": 0.05,\n \"fracture\": \"crumble\",\n \"fragmentSize\": [\n 0.04,\n 0.12\n ],\n \"hitDebris\": \"chips\",\n \"breakDebris\": \"dust\",\n \"thermal\": {\n \"conductivity\": 0.15,\n \"heatCapacity\": 2.5\n },\n \"tags\": [\n \"masonry\",\n \"brittle\"\n ],\n \"compressive\": 40000\n },\n {\n \"id\": \"plaster\",\n \"density\": 850,\n \"hpPerKg\": 18,\n \"penetration\": 3,\n \"ductility\": 0.05,\n \"fracture\": \"crumble\",\n \"fragmentSize\": [\n 0.05,\n 0.3\n ],\n \"hitDebris\": \"dust\",\n \"breakDebris\": \"dust\",\n \"thermal\": {\n \"conductivity\": 0.1,\n \"heatCapacity\": 1.5\n },\n \"tags\": [\n \"masonry\",\n \"brittle\"\n ],\n \"compressive\": 8000\n },\n {\n \"id\": \"stone\",\n \"density\": 2700,\n \"hpPerKg\": 25,\n \"penetration\": 25,\n \"ductility\": 0.03,\n \"fracture\": \"crumble\",\n \"fragmentSize\": [\n 0.06,\n 0.3\n ],\n \"hitDebris\": \"chips\",\n \"breakDebris\": \"dust\",\n \"thermal\": {\n \"conductivity\": 0.2,\n \"heatCapacity\": 2.5\n },\n \"tags\": [\n \"masonry\",\n \"brittle\"\n ],\n \"compressive\": 300000\n },\n {\n \"id\": \"plastic\",\n \"density\": 1100,\n \"hpPerKg\": 60,\n \"penetration\": 8,\n \"ductility\": 0.5,\n \"fracture\": \"snap\",\n \"fragmentSize\": [\n 0.05,\n 0.3\n ],\n \"hitDebris\": \"chips\",\n \"breakDebris\": \"chips\",\n \"thermal\": {\n \"ignitionC\": 400,\n \"flameC\": 700,\n \"fuelFraction\": 0.8,\n \"burnRate\": 0.02,\n \"meltC\": 200,\n \"meltRate\": 0.06,\n \"conductivity\": 0.05,\n \"heatCapacity\": 1,\n \"smoke\": \"black\"\n },\n \"visual\": {\n \"charColor\": 855309\n },\n \"tags\": [\n \"plastic\",\n \"flammable\"\n ],\n \"compressive\": 40000\n },\n {\n \"id\": \"rubber\",\n \"density\": 1100,\n \"hpPerKg\": 80,\n \"penetration\": 12,\n \"ductility\": 0.9,\n \"fracture\": \"tear\",\n \"fragmentSize\": [\n 0.05,\n 0.2\n ],\n \"hitDebris\": \"chips\",\n \"breakDebris\": \"fibers\",\n \"thermal\": {\n \"ignitionC\": 350,\n \"flameC\": 750,\n \"fuelFraction\": 0.6,\n \"burnRate\": 0.015,\n \"conductivity\": 0.05,\n \"heatCapacity\": 1.2,\n \"smoke\": \"black\"\n },\n \"visual\": {\n \"charColor\": 855309\n },\n \"tags\": [\n \"rubber\",\n \"flammable\"\n ],\n \"compressive\": 20000\n },\n {\n \"id\": \"fabric\",\n \"density\": 400,\n \"hpPerKg\": 20,\n \"penetration\": 0.8,\n \"ductility\": 0.8,\n \"fracture\": \"tear\",\n \"fragmentSize\": [\n 0.05,\n 0.25\n ],\n \"damageScale\": {\n \"slash\": 4,\n \"ballistic\": 0.5\n },\n \"hitDebris\": \"fibers\",\n \"breakDebris\": \"fibers\",\n \"thermal\": {\n \"ignitionC\": 230,\n \"flameC\": 600,\n \"fuelFraction\": 1,\n \"burnRate\": 0.05,\n \"conductivity\": 0.03,\n \"heatCapacity\": 0.6,\n \"smoke\": \"grey\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"fabric\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 500\n },\n {\n \"id\": \"foam\",\n \"density\": 30,\n \"hpPerKg\": 15,\n \"penetration\": 0.5,\n \"ductility\": 0.7,\n \"fracture\": \"tear\",\n \"fragmentSize\": [\n 0.03,\n 0.15\n ],\n \"damageScale\": {\n \"slash\": 2,\n \"ballistic\": 0.4\n },\n \"hitDebris\": \"fibers\",\n \"breakDebris\": \"fibers\",\n \"thermal\": {\n \"ignitionC\": 250,\n \"flameC\": 900,\n \"fuelFraction\": 0.95,\n \"burnRate\": 0.09,\n \"conductivity\": 0.02,\n \"heatCapacity\": 0.5,\n \"smoke\": \"black\"\n },\n \"visual\": {\n \"charColor\": 855309\n },\n \"tags\": [\n \"fabric\",\n \"flammable\"\n ],\n \"compressive\": 100\n },\n {\n \"id\": \"leather\",\n \"density\": 900,\n \"hpPerKg\": 50,\n \"penetration\": 4,\n \"ductility\": 0.8,\n \"fracture\": \"tear\",\n \"fragmentSize\": [\n 0.05,\n 0.25\n ],\n \"damageScale\": {\n \"slash\": 2\n },\n \"hitDebris\": \"fibers\",\n \"breakDebris\": \"fibers\",\n \"thermal\": {\n \"ignitionC\": 320,\n \"flameC\": 650,\n \"fuelFraction\": 0.7,\n \"burnRate\": 0.01,\n \"conductivity\": 0.05,\n \"heatCapacity\": 1,\n \"smoke\": \"grey\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"fabric\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 2000\n },\n {\n \"id\": \"paper\",\n \"density\": 700,\n \"hpPerKg\": 8,\n \"penetration\": 0.3,\n \"ductility\": 0.5,\n \"fracture\": \"tear\",\n \"fragmentSize\": [\n 0.03,\n 0.15\n ],\n \"damageScale\": {\n \"slash\": 3\n },\n \"hitDebris\": \"fibers\",\n \"breakDebris\": \"fibers\",\n \"thermal\": {\n \"ignitionC\": 230,\n \"flameC\": 600,\n \"fuelFraction\": 1,\n \"burnRate\": 0.06,\n \"conductivity\": 0.03,\n \"heatCapacity\": 0.5,\n \"smoke\": \"grey\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"fabric\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 500\n },\n {\n \"id\": \"foliage\",\n \"density\": 150,\n \"hpPerKg\": 20,\n \"penetration\": 0.5,\n \"ductility\": 0.6,\n \"fracture\": \"tear\",\n \"fragmentSize\": [\n 0.03,\n 0.1\n ],\n \"damageScale\": {\n \"slash\": 4\n },\n \"hitDebris\": \"leaves\",\n \"breakDebris\": \"leaves\",\n \"thermal\": {\n \"ignitionC\": 300,\n \"flameC\": 700,\n \"fuelFraction\": 0.8,\n \"burnRate\": 0.08,\n \"conductivity\": 0.03,\n \"heatCapacity\": 0.8,\n \"smoke\": \"white\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"plant\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 500\n },\n {\n \"id\": \"green_wood\",\n \"density\": 650,\n \"hpPerKg\": 5,\n \"penetration\": 10,\n \"ductility\": 0.5,\n \"fracture\": \"splinter\",\n \"fragmentSize\": [\n 0.03,\n 0.2\n ],\n \"damageScale\": {\n \"slash\": 1.3,\n \"ballistic\": 0.1\n },\n \"hitDebris\": \"splinters\",\n \"breakDebris\": \"leaves\",\n \"thermal\": {\n \"ignitionC\": 400,\n \"flameC\": 700,\n \"fuelFraction\": 0.8,\n \"burnRate\": 0.006,\n \"conductivity\": 0.06,\n \"heatCapacity\": 2,\n \"smoke\": \"white\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"plant\",\n \"wood\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 60000\n },\n {\n \"id\": \"cactus\",\n \"density\": 900,\n \"hpPerKg\": 30,\n \"penetration\": 2,\n \"ductility\": 0.6,\n \"fracture\": \"tear\",\n \"fragmentSize\": [\n 0.04,\n 0.15\n ],\n \"damageScale\": {\n \"slash\": 3\n },\n \"hitDebris\": \"fibers\",\n \"breakDebris\": \"fibers\",\n \"thermal\": {\n \"ignitionC\": 450,\n \"flameC\": 650,\n \"fuelFraction\": 0.3,\n \"burnRate\": 0.01,\n \"conductivity\": 0.05,\n \"heatCapacity\": 3,\n \"smoke\": \"white\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"plant\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 5000\n },\n {\n \"id\": \"flesh_fruit\",\n \"density\": 950,\n \"hpPerKg\": 15,\n \"penetration\": 1.5,\n \"ductility\": 0.7,\n \"fracture\": \"tear\",\n \"fragmentSize\": [\n 0.02,\n 0.08\n ],\n \"damageScale\": {\n \"slash\": 2\n },\n \"hitDebris\": \"drips\",\n \"breakDebris\": \"drips\",\n \"thermal\": {\n \"conductivity\": 0.05,\n \"heatCapacity\": 3\n },\n \"tags\": [\n \"plant\",\n \"organic\"\n ],\n \"compressive\": 1000\n },\n {\n \"id\": \"wax\",\n \"density\": 900,\n \"hpPerKg\": 30,\n \"penetration\": 3,\n \"ductility\": 0.5,\n \"fracture\": \"snap\",\n \"fragmentSize\": [\n 0.05,\n 0.2\n ],\n \"hitDebris\": \"chips\",\n \"breakDebris\": \"chips\",\n \"thermal\": {\n \"ignitionC\": 230,\n \"flameC\": 700,\n \"fuelFraction\": 0.9,\n \"burnRate\": 0.02,\n \"meltC\": 60,\n \"meltRate\": 0.2,\n \"conductivity\": 0.05,\n \"heatCapacity\": 0.8,\n \"smoke\": \"grey\"\n },\n \"tags\": [\n \"wax\",\n \"flammable\"\n ],\n \"compressive\": 5000\n },\n {\n \"id\": \"soil\",\n \"density\": 1300,\n \"hpPerKg\": 3,\n \"penetration\": 5,\n \"ductility\": 0.3,\n \"fracture\": \"crumble\",\n \"fragmentSize\": [\n 0.03,\n 0.12\n ],\n \"hitDebris\": \"dust\",\n \"breakDebris\": \"dust\",\n \"thermal\": {\n \"conductivity\": 0.1,\n \"heatCapacity\": 2.5\n },\n \"tags\": [\n \"soil\",\n \"masonry\"\n ],\n \"compressive\": 20000\n }\n]\n","{\n \"cast iron\": \"cast_iron\",\n \"cast_iron\": \"cast_iron\",\n \"castiron\": \"cast_iron\",\n \"metal\": \"steel\",\n \"steel\": \"steel\",\n \"iron\": \"steel\",\n \"chrome\": \"steel\",\n \"alumin\": \"aluminium\",\n \"alu_\": \"aluminium\",\n \"alu-\": \"aluminium\",\n \"alu \": \"aluminium\",\n \"copper\": \"copper\",\n \"brass\": \"copper\",\n \"bronze\": \"copper\",\n \"wood\": \"wood_soft\",\n \"timber\": \"wood_soft\",\n \"plank\": \"wood_soft\",\n \"lumber\": \"wood_soft\",\n \"pine\": \"wood_soft\",\n \"hardwood\": \"wood_hard\",\n \"oak\": \"wood_hard\",\n \"plywood\": \"plywood\",\n \"mdf\": \"mdf\",\n \"chipboard\": \"mdf\",\n \"glass\": \"glass\",\n \"window\": \"glass\",\n \"mirror\": \"glass\",\n \"tempered\": \"tempered_glass\",\n \"windshield\": \"tempered_glass\",\n \"fabric\": \"fabric\",\n \"cloth\": \"fabric\",\n \"cushion\": \"fabric\",\n \"sofa\": \"fabric\",\n \"curtain\": \"fabric\",\n \"carpet\": \"fabric\",\n \"textile\": \"fabric\",\n \"canvas\": \"fabric\",\n \"foam\": \"foam\",\n \"sponge\": \"foam\",\n \"mattress\": \"foam\",\n \"leather\": \"leather\",\n \"paper\": \"paper\",\n \"cardboard\": \"paper\",\n \"leaf\": \"foliage\",\n \"leaves\": \"foliage\",\n \"foliage\": \"foliage\",\n \"bush\": \"foliage\",\n \"grass\": \"foliage\",\n \"trunk\": \"green_wood\",\n \"branch\": \"green_wood\",\n \"twig\": \"green_wood\",\n \"cactus\": \"cactus\",\n \"fruit\": \"flesh_fruit\",\n \"apple\": \"flesh_fruit\",\n \"melon\": \"flesh_fruit\",\n \"wax\": \"wax\",\n \"candle\": \"wax\",\n \"concrete\": \"concrete\",\n \"cement\": \"concrete\",\n \"brick\": \"brick\",\n \"tile\": \"ceramic\",\n \"ceramic\": \"ceramic\",\n \"porcelain\": \"ceramic\",\n \"stone\": \"stone\",\n \"rock\": \"stone\",\n \"marble\": \"stone\",\n \"plaster\": \"plaster\",\n \"drywall\": \"plaster\",\n \"gypsum\": \"plaster\",\n \"plastic\": \"plastic\",\n \"pvc\": \"plastic\",\n \"acrylic\": \"plastic\",\n \"rubber\": \"rubber\",\n \"tire\": \"rubber\",\n \"tyre\": \"rubber\",\n \"soil\": \"soil\",\n \"dirt\": \"soil\",\n \"potting\": \"soil\",\n \"mud\": \"soil\"\n}","import materialsJson from './data/materials.json'\nimport hintsJson from './data/material-hints.json'\nimport { aabbOf, quatFromEuler, shapeDims } from './math'\nimport type { JointKind, JointSpec, MaterialDef, MaterialId, PartShape, PartSpec, ToolKind } from './types'\n\n/** Built-in materials (data in `src/data/materials.json`). Override or extend with the `materials` option of `createDestruction`. */\nexport const MATERIALS: MaterialDef[] = materialsJson as unknown as MaterialDef[]\n\n/** Default joint strength (joint hit points), tools that undo it and seconds of tool work. */\nexport const JOINT_DEFAULTS: Record<JointKind, { strength: number; tools: ToolKind[]; seconds: number }> = {\n screw: { strength: 80, tools: ['screwdriver'], seconds: 2.5 },\n bolt: { strength: 200, tools: ['wrench'], seconds: 4 },\n nail: { strength: 60, tools: ['pry_bar', 'hammer'], seconds: 2 },\n weld: { strength: 600, tools: ['cutting_torch', 'saw'], seconds: 8 },\n glue: { strength: 50, tools: ['pry_bar', 'knife'], seconds: 3 },\n hinge: { strength: 120, tools: ['screwdriver'], seconds: 3 },\n clip: { strength: 20, tools: ['hand'], seconds: 0.6 },\n tie: { strength: 15, tools: ['knife', 'hand'], seconds: 1 },\n mortar: { strength: 400, tools: ['hammer'], seconds: 6 },\n fused: { strength: 1000, tools: [], seconds: 0 },\n stem: { strength: 40, tools: ['knife', 'saw', 'hand'], seconds: 1.5 },\n rebar: { strength: 1500, tools: ['cutting_torch', 'saw'], seconds: 20 },\n resting: { strength: 30, tools: ['hand'], seconds: 1 },\n}\n\nconst has = (m: MaterialDef, tag: string) => !!m.tags && m.tags.includes(tag)\n\n/**\n * The joint kind that fits two materials: glass is glued (clipped to plastic), soft things are tied, plants share a stem, masonry gets mortar,\n * metal is welded, wood is screwed, plastic clips. `inferJoints` refines weld to bolt for thick metal and screw to nail for thin wood.\n */\nexport const JOINT_BY_MATERIALS = (a: MaterialDef, b: MaterialDef): JointKind => {\n const any = (tag: string) => has(a, tag) || has(b, tag)\n const both = (tag: string) => has(a, tag) && has(b, tag)\n if (any('glass')) return any('plastic') ? 'clip' : 'glue'\n if (any('fabric')) return 'tie'\n if (both('plant')) return 'stem'\n if (any('plant')) return 'tie'\n if (both('masonry')) return 'mortar'\n if (any('masonry') && any('metal')) return 'bolt'\n if (both('metal')) return 'weld'\n if (any('plastic')) return 'clip'\n if (any('rubber') || any('wax')) return 'glue'\n return 'screw'\n}\n\nconst MATERIAL_MAP: ReadonlyMap<MaterialId, MaterialDef> = new Map(MATERIALS.map((m) => [m.id, m]))\n\nconst HINTS = Object.entries(hintsJson as Record<string, string>).sort((x, y) => y[0].length - x[0].length)\n\n/** Guess a material id from a mesh or node name (case-insensitive substring; the longest keyword wins). */\nexport const guessMaterial = (name: string): MaterialId | undefined => {\n const n = name.toLowerCase()\n for (const [key, id] of HINTS) if (n.includes(key)) return id\n return undefined\n}\n\n/** Volume of a shape in m³. */\nexport const partVolume = (shape: PartShape): number => {\n if (shape.kind === 'box') return shape.size[0] * shape.size[1] * shape.size[2]\n if (shape.kind === 'cylinder') return Math.PI * shape.radius * shape.radius * shape.height\n return (4 / 3) * Math.PI * shape.radius ** 3\n}\n\n/** Mass of a part in kg: its `mass`, or density × volume × fill. */\nexport const partMass = (part: PartSpec, material: MaterialDef): number => part.mass ?? material.density * partVolume(part.shape) * (part.fill ?? 1)\n\n/** Wall thickness of a part in metres (see `PartSpec.thickness`). */\nexport const partThickness = (part: PartSpec): number => {\n const dims = shapeDims(part.shape)\n const min = Math.min(dims[0], dims[1], dims[2])\n return Math.max(1e-4, Math.min(part.thickness ?? min * (part.fill ?? 1), min))\n}\n\n/**\n * Joints for touching parts. Two parts touch when their axis-aligned bounds (after rotation), grown by `tolerance` metres, overlap. The kind comes\n * from `JOINT_BY_MATERIALS`; thick metal pairs (smallest dimension of both >= 2 cm) get a `bolt` instead of a `weld`, and thin wood pairs (either\n * under 2 cm) a `nail` instead of a `screw`.\n */\nexport const inferJoints = (parts: PartSpec[], tolerance = 0.01, materials: ReadonlyMap<string, MaterialDef> = MATERIAL_MAP): JointSpec[] => {\n const boxes = parts.map((p) => aabbOf(p.shape, p.position, quatFromEuler(...(p.rotation ?? [0, 0, 0]))))\n const out: JointSpec[] = []\n for (let i = 0; i < parts.length; i++) {\n for (let j = i + 1; j < parts.length; j++) {\n const a = boxes[i], b = boxes[j]\n let touch = true\n for (let k = 0; k < 3 && touch; k++) if (a.min[k] - tolerance > b.max[k] || b.min[k] - tolerance > a.max[k]) touch = false\n if (!touch) continue\n const ma = materials.get(parts[i].material)\n const mb = materials.get(parts[j].material)\n let kind: JointKind = ma && mb ? JOINT_BY_MATERIALS(ma, mb) : 'screw'\n const thin = Math.min(partThickness(parts[i]), partThickness(parts[j]))\n if (kind === 'weld' && thin >= 0.02) kind = 'bolt'\n if (kind === 'screw' && ma && mb && has(ma, 'wood') && has(mb, 'wood') && thin < 0.02) kind = 'nail'\n out.push({ id: `${parts[i].id}~${parts[j].id}`, a: parts[i].id, b: parts[j].id, kind })\n }\n }\n return out\n}\n\n/**\n * Load in kg a structural part carries before it fails: `structure.capacity`, else `material.compressive` (default 20 000 kg/m²) times the\n * section. The section is the product of the two smallest dimensions (thickness times longest dimension for slabs; thickness times horizontal length for walls); foundations get x10.\n */\nexport const partCapacity = (part: PartSpec, material: MaterialDef): number => {\n if (part.structure?.capacity !== undefined) return part.structure.capacity\n const d = shapeDims(part.shape).sort((a, b) => a - b)\n const role = part.structure?.role\n const sh = shapeDims(part.shape)\n const section = role === 'wall' || role === 'partition' ? Math.min(sh[0], sh[2]) * Math.max(sh[0], sh[2]) : role === 'slab' ? d[0] * d[2] : d[0] * d[1]\n return Math.max(1, section * (material.compressive ?? 20000) * (role === 'foundation' ? 10 : 1))\n}\n\n\n/**\n * Multiplier of blunt damage on brittle parts (ductility < 0.3): up to x4.7 for fully brittle materials (glass, ceramic, stone), times a thinness\n * term that follows bending stress (1 / thickness squared, x1 at 2 cm or more, at most x25). A 3 mm glass bottle breaks from a 1.5 m drop; a\n * concrete block (thick) is only ever x4.4.\n */\nexport const fragility = (ductility: number, thickness: number): number => {\n if (ductility >= 0.3) return 1\n return (1 + (4 * (0.3 - ductility)) / 0.3) * Math.min(25, Math.max(1, (0.02 / Math.max(thickness, 1e-4)) ** 2))\n}\n","import { chainDelayOf, drawChainDelay, FIRE_PRIME_C, shotDamageFractionOf } from './chain'\nimport type { ChainTrigger } from './chain'\nimport { planFragments } from './fracture'\nimport type { PlannedFragment } from './fracture'\nimport { cellsOutside, cellsWithin, marksInBox, planeAxes, unitGrid } from './breach'\nimport type { LocalHole, UnitCell } from './breach'\nimport { layersEnergy, layersThickness, MAX_SPALLS, outerLayer, resolveLayer, thinAxisOf } from './layers'\nimport type { LayerRT } from './layers'\nimport { clipBarsToDisc, rebarBars, rebarMass } from './rebar'\nimport { JOINT_DEFAULTS, inferJoints, MATERIALS, partCapacity, partMass, partThickness, partVolume, fragility } from './materials'\nimport { aabbOf, createRng, distanceToShape, quat, quatFromEuler, rayShape, rotateVec, shapeArea, shapeBound, shapeDims, surfacePoint, toLocal, toWorld, vec } from './math'\nimport type { DestructibleImpl } from './contracts'\nimport type {\n AddOptions, Crack, DamageType, DebrisKind, DestructibleSpec, Dent, DestructionEvent, DestructionEventType, DestructionOptions, DestructionSnapshot,\n DamageStage, DestructionWorld, Fragment, Hit, HitResult, Hole, JointSpec, JointState, MaterialDef, MaterialId, ObjectRuntime, ObjectState, PartRuntime, PartSpec,\n PartState, Quat, RayHit, ToolKind, Vec3,\n BlastOptions, BlastReport, ConfinementOptions, FragmentHitOptions, ShelterOptions,\n} from './types'\n\n/** Hit points removed per joule (before the material's `damageScale`). */\nconst DMG_PER_J = 0.02\n/** Fraction of a blast's energy that reaches a part at distance 0. */\nconst BLAST_COUPLING = 0.1\n/**\n * Blast options (all off until asked for). Shelter: a part the line from the blast to the target crosses lets through `exp(-r / k)`, `r` being the\n * hit points of the slab it crosses per square metre (`hpPerKg * density * path * damageScale.shelter`). Fragment hits: up to 24 fragments, half their\n * kinetic energy lands as a blunt hit, thrown at most 6 m (and `speed * 0.4 s`) within 10 degrees of their aim. Confinement: 26 rays reaching\n * `1.5 * radius`, multiplier `1 + 1.5 * closedShare^2 * clamp(radius / meanDistance, 0, 2)` up to 3.\n */\nexport const SHELTER_DEFAULTS: Required<ShelterOptions> = { k: 2800, brokenTransmission: 0.5, minPath: 0.005 }\nexport const FRAGMENT_HIT_DEFAULTS: Required<FragmentHitOptions> = { max: 24, energyFactor: 0.5, hitType: 'blunt', range: 6, flightTime: 0.4, spread: 10, aim: 40 }\nexport const CONFINEMENT_DEFAULTS: Required<ConfinementOptions> = { rays: 26, reach: 1.5, gain: 1.5, power: 2, max: 3 }\nconst FLAMMABLE_FLUIDS = ['gas', 'fuel']\n/** Staged parts: default breach radius (m), blast multiplier on the breach area, area a part must lose to open (m²), and the share of capacity the bare cage keeps. */\nconst BREACH_RADIUS = 0.55\nconst BREACH_BLAST_FACTOR = 6\nconst BREACH_AREA = 0.25\n/** Metres of reach per cube root of kilojoule for a blast to open a breach. */\nconst BREACH_BLAST_REACH = Infinity\nconst RESIDUAL_CAPACITY = 0.15\n/** Unit-sized fragments of a whole wall: at most this many times `maxFragments`. A breach picks its units from a grid of up to `BREACH_GRID_CAP`. */\nconst UNIT_FRAGMENT_FACTOR = 4\nconst BREACH_GRID_CAP = 4096\n\n/** A cut only goes through a slice of the part, so a part longer than `CUT_SLICE` costs no more to cut than a 1 m piece of the same section. */\nconst CUT_SLICE = 1\nconst cutFactorOf = (shape: PartSpec['shape']): number => clamp(Math.max(...shapeDims(shape)) / CUT_SLICE, 1, 50)\n\ninterface PartRT {\n spec: PartSpec\n mat: MaterialDef\n st: PartState\n q: Quat\n /** Current object-local position (the spec's, unless moved by `setPartPose`). */\n pos: Vec3\n mass0: number\n fuel0: number\n area: number\n thickness: number\n /** Slash damage multiplier: longest dimension / 1 m (1..50). */\n cutFactor: number\n dims: Vec3\n bound: number\n rt: PartRuntime\n /** Structural role other than `none`. */\n structural: boolean\n anchored: boolean\n cap: number\n /** The part has layers, units, reinforcement or a breach: it goes through damage stages. */\n staged: boolean\n /** Axis the part is thinnest along (the wall's depth). */\n thin: number\n layers: LayerRT[]\n}\n\ninterface JointRT {\n spec: Required<JointSpec>\n st: JointState\n ia: number\n ib: number\n bears: boolean | 'a_on_b' | 'b_on_a'\n /** Object-local position. */\n pos: Vec3\n step: number\n}\n\ninterface ObjRT {\n id: string\n spec: DestructibleSpec\n st: ObjectState\n parts: PartRT[]\n byId: Map<string, PartRT>\n idx: Map<string, number>\n joints: JointRT[]\n jointMap: Map<string, JointRT>\n byPart: Map<string, JointRT[]>\n /** Local bounding sphere. */\n bc: Vec3\n br: number\n active: boolean\n tmp: number[]\n hasStructure: boolean\n dirty: boolean\n maxStress: number\n collapsed: Set<string>\n /** Structural parts with no support path to an anchored part (they fall). */\n unsup: boolean[]\n anyAnchor: boolean\n /** Creation order of the object in this world: breaks ties between parts that go off at the same time. */\n order: number\n}\n\ninterface Carry {\n parts: Map<string, { st: PartState; rt: PartRuntime }>\n joints: Map<string, { st: JointState; step: number }>\n collapsed?: string[]\n}\n\ninterface Loc {\n p: PartRT\n point: Vec3\n normal: Vec3\n dir: Vec3\n pathLen: number\n}\n\ninterface ImplRT {\n impl: DestructibleImpl\n position: Vec3\n rotation: Quat\n /** Part pose overrides set by `setPartPose` (object-local). */\n poses: Map<string, { pos: Vec3; q: Quat }>\n}\n\ninterface Blast {\n point: Vec3\n energy: number\n radius: number\n source?: string\n}\n\nconst clamp = (v: number, a: number, b: number) => Math.max(a, Math.min(b, v))\n/** Share of its capacity a structural part still has: a bare rebar cage keeps the reinforcement's residual, a breached part loses what left it. */\nconst capacityScale = (p: PartRT): number => {\n if (p.st.stripped) return p.spec.reinforcement?.residualCapacity ?? RESIDUAL_CAPACITY\n return p.rt.removed ? Math.max(0.05, 1 - p.rt.removed / p.mass0) : 1\n}\nconst isLost = (p: PartRT) => p.st.status === 'broken' || p.st.status === 'melted' || p.st.status === 'ashes'\nconst clone = <T>(v: T): T => structuredClone(v)\n/**\n * Fraction of a structural part's hit points lost per second while its stress is above 1. A floor of 0.12 makes even a barely overloaded part\n * give way in about 8 s (a rate proportional to the excess alone never finishes: stress 1.02 would take two minutes), then it grows with the\n * excess and tops out at 0.6: stress 1.1 fails in ~4.5 s, 1.5 in ~1.9 s and anything above 1.7 in ~1.7 s. Deterministic: depends only on stress.\n */\nconst overloadRate = (stress: number) => Math.min(0.6, 0.12 + 0.8 * (stress - 1))\nconst updateBound = (o: ObjRT) => {\n if (!o.parts.length) return\n const c: Vec3 = [0, 0, 0]\n for (const p of o.parts) for (let k = 0; k < 3; k++) c[k] += p.pos[k] / o.parts.length\n let r = 0\n for (const p of o.parts) r = Math.max(r, vec.distance(c, p.pos) + p.bound)\n o.bc = c\n o.br = r\n}\nconst AXIS = { x: 0, y: 1, z: 2 } as const\n\nexport const createDestruction = (options: DestructionOptions = {}): DestructionWorld => {\n const materials = new Map<MaterialId, MaterialDef>()\n for (const m of MATERIALS) materials.set(m.id, m)\n for (const m of options.materials ?? []) materials.set(m.id, m)\n const ambient = options.ambientC ?? 20\n const maxFragments = options.maxFragments ?? 24\n const maxDents = options.maxDents ?? 24\n const maxHoles = options.maxHoles ?? 32\n const fireSpread = options.fireSpread ?? 0.6\n const breachRadius = options.breach?.radius ?? BREACH_RADIUS\n const breachBlastFactor = options.breach?.blastFactor ?? BREACH_BLAST_FACTOR\n const breachBlastReach = options.breach?.blastReach ?? BREACH_BLAST_REACH\n const rng = createRng(options.seed ?? 1)\n const rnd = () => rng.next()\n\n let time = 0\n let counter = 0\n const objects = new Map<string, ObjRT>()\n const listeners = new Map<string, Set<(e: DestructionEvent) => void>>()\n let cur: DestructionEvent[] = []\n const blasts: Blast[] = []\n /** Glass the blast front has not reached yet: the damage lands when it does (`blastFrontSpeed`). */\n const frontQueue: Array<{ o: ObjRT; p: PartRT; due: number; amount: number; fragEnergy: number; point: Vec3; src?: string }> = []\n const blastFrontSpeed = options.blastFrontSpeed ?? 0\n /** Explosive parts that were primed and wait for their delay. */\n const primed = new Map<PartRT, ObjRT>()\n let orderCounter = 0\n const impls = new Map<string, ImplRT>()\n const taken = (id: string) => objects.has(id) || impls.has(id)\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Events\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n const emit = (e: DestructionEvent) => {\n cur.push(e)\n options.onEvent?.(e)\n const all = listeners.get('*')\n if (all) for (const fn of [...all]) fn(e)\n const typed = listeners.get(e.type)\n if (typed) for (const fn of [...typed]) fn(e)\n }\n const base = (o: ObjRT, source?: string): { object: string; time: number; source?: string } =>\n source === undefined ? { object: o.id, time } : { object: o.id, time, source }\n\n const pendingCollapse = new Map<ObjRT, string | undefined>()\n let runDepth = 0\n\n /** Blasts queued by parts that exploded; each can prime or set off more parts. It ends: a part goes off once and is primed once, so the queue only grows by parts not yet lost. */\n const drainBlasts = () => {\n for (let blast = blasts.shift(); blast; blast = blasts.shift()) blastWorld(blast.point, blast.energy, blast.radius, blast.source)\n }\n\n const run = <T>(fn: () => T): { value: T; events: DestructionEvent[] } => {\n const prev = cur\n const mine: DestructionEvent[] = []\n cur = mine\n runDepth++\n try {\n const value = fn()\n drainBlasts()\n if (runDepth === 1) flushCollapse()\n return { value, events: mine }\n } finally {\n runDepth--\n cur = prev\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Building objects\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n const nextId = () => {\n let id: string\n do id = `obj_${++counter}`\n while (taken(id))\n return id\n }\n\n const freshRuntime = (): PartRuntime => ({ meltEmitted: 0, dripT: 0, prevTemp: ambient, shockT: 0, jet: false })\n\n const resolveSpec = (spec: DestructibleSpec): DestructibleSpec => {\n const out = clone(spec)\n const joints = out.joints ?? inferJoints(out.parts, 0.01, materials)\n const structural = (id: string) => {\n const role = out.parts.find((p) => p.id === id)?.structure?.role\n return role !== undefined && role !== 'none'\n }\n out.joints = joints.map((j) => {\n const def = JOINT_DEFAULTS[j.kind]\n return {\n id: j.id ?? `${j.a}~${j.b}`, a: j.a, b: j.b, kind: j.kind, strength: j.strength ?? def.strength, tools: j.tools ?? [...def.tools], seconds: j.seconds ?? def.seconds,\n bears: j.bears ?? (structural(j.a) && structural(j.b)),\n }\n })\n return out\n }\n\n const build = (spec: DestructibleSpec, id: string, pos: Vec3, rot: Quat, carry?: Carry): ObjRT => {\n const st: ObjectState = { id, position: [pos[0], pos[1], pos[2]], rotation: [rot[0], rot[1], rot[2], rot[3]], parts: [], joints: [], groups: [], destroyed: false }\n if (spec.name !== undefined) st.name = spec.name\n const o: ObjRT = {\n id, spec, st, parts: [], byId: new Map(), idx: new Map(), joints: [], jointMap: new Map(), byPart: new Map(), bc: [0, 0, 0], br: 0, active: false, tmp: [], hasStructure: false, dirty: false, maxStress: 0, collapsed: new Set(carry?.collapsed ?? []), unsup: [], anyAnchor: false, order: ++orderCounter,\n }\n for (const ps of spec.parts) {\n if (o.byId.has(ps.id)) throw new Error(`duplicate part id \"${ps.id}\"`)\n const mat = materials.get(ps.material)\n if (!mat) throw new Error(`unknown material \"${ps.material}\" on part \"${ps.id}\"`)\n const mass0 = partMass(ps, mat)\n const maxHp = Math.max(1, ps.hp ?? mass0 * mat.hpPerKg)\n const fuel0 = mat.thermal.ignitionC !== undefined ? mass0 * (mat.thermal.fuelFraction ?? 0) : 0\n const c = carry?.parts.get(ps.id)\n const staged = !!(ps.layers?.length || ps.reinforcement || ps.units || ps.breach)\n const layers = (ps.layers ?? []).map((l, i) => {\n const lm = materials.get(l.material)\n if (!lm) throw new Error(`unknown material \"${l.material}\" on layer ${i} of part \"${ps.id}\"`)\n return resolveLayer(l, i, lm)\n })\n if (ps.reinforcement && !materials.has(ps.reinforcement.material)) throw new Error(`unknown material \"${ps.reinforcement.material}\" on the reinforcement of part \"${ps.id}\"`)\n const pst: PartState = c?.st ?? {\n id: ps.id, material: ps.material, status: 'intact', hp: maxHp, maxHp, mass: mass0, temperature: ambient, burning: false, fuel: fuel0, char: 0, melt: 0,\n dents: [], holes: [], cracks: [], group: 0, ...(staged ? { stage: 0 as DamageStage } : {}),\n }\n if (!c && ps.contains) pst.liters = ps.contains.liters\n const p: PartRT = {\n spec: ps, mat, st: pst, q: quatFromEuler(...(ps.rotation ?? [0, 0, 0])), pos: [ps.position[0], ps.position[1], ps.position[2]], mass0, fuel0, area: shapeArea(ps.shape), thickness: partThickness(ps), cutFactor: cutFactorOf(ps.shape),\n dims: shapeDims(ps.shape), bound: shapeBound(ps.shape), rt: c?.rt ?? { ...freshRuntime(), prevTemp: pst.temperature },\n structural: !!ps.structure && ps.structure.role !== 'none', anchored: !!ps.anchored || ps.structure?.role === 'foundation', cap: ps.structure ? partCapacity(ps, mat) : 0,\n staged, thin: thinAxisOf(shapeDims(ps.shape)), layers,\n }\n if (p.structural) o.hasStructure = true\n if (p.rt.chainDue !== undefined && !isLost(p)) primed.set(p, o)\n o.idx.set(ps.id, o.parts.length)\n o.parts.push(p)\n o.byId.set(ps.id, p)\n o.st.parts.push(pst)\n o.byPart.set(ps.id, [])\n }\n for (const js of spec.joints ?? []) {\n const r = js as Required<JointSpec>\n const ia = o.idx.get(r.a), ib = o.idx.get(r.b)\n if (ia === undefined || ib === undefined) throw new Error(`joint \"${r.id}\" references an unknown part`)\n if (o.jointMap.has(r.id)) throw new Error(`duplicate joint id \"${r.id}\"`)\n const pa = o.parts[ia], pb = o.parts[ib]\n const A = aabbOf(pa.spec.shape, pa.spec.position, pa.q)\n const B = aabbOf(pb.spec.shape, pb.spec.position, pb.q)\n const pos: Vec3 = [0, 0, 0]\n for (let k = 0; k < 3; k++) pos[k] = (Math.max(A.min[k], B.min[k]) + Math.min(A.max[k], B.max[k])) / 2\n const bears: JointRT['bears'] = r.bears ?? (pa.structural && pb.structural)\n const c = carry?.joints.get(r.id)\n const jst: JointState = c?.st ?? { id: r.id, a: r.a, b: r.b, kind: r.kind, hp: r.strength, maxHp: r.strength, progress: 0, open: false }\n const j: JointRT = { spec: r, st: jst, ia, ib, bears, pos, step: c?.step ?? 0 }\n o.joints.push(j)\n o.jointMap.set(r.id, j)\n o.byPart.get(r.a)!.push(j)\n o.byPart.get(r.b)!.push(j)\n o.st.joints.push(jst)\n }\n // open joints whose parts are no longer both here (left behind by `splitGroup`) stay listed, inert, so callers still see them open\n for (const [jid, c] of carry?.joints ?? []) if (c.st.open && !o.jointMap.has(jid)) o.st.joints.push(c.st)\n updateBound(o)\n o.anyAnchor = o.parts.some((p) => p.anchored)\n o.unsup = o.parts.map(() => false)\n solveStructure(o)\n recomputeGroups(o)\n o.st.destroyed = o.parts.length > 0 && o.parts.every(isLost)\n o.active = o.maxStress > 0.8 || o.parts.some((p) => p.st.burning || p.st.temperature > ambient + 0.5 || (p.st.liters ?? 0) > 0)\n return o\n }\n\n const recomputeGroups = (o: ObjRT) => {\n const n = o.parts.length\n const parent = Array.from({ length: n }, (_, i) => i)\n const find = (i: number): number => {\n while (parent[i] !== i) {\n parent[i] = parent[parent[i]]\n i = parent[i]\n }\n return i\n }\n const union = (a: number, b: number) => {\n parent[find(a)] = find(b)\n }\n const live = (j: JointRT) => !j.st.open && !isLost(o.parts[j.ia]) && !isLost(o.parts[j.ib])\n if (o.unsup.some(Boolean)) {\n // parts that lost every support fall: cut them from the supported pieces; loose non-structural parts follow the part they hang on\n for (const j of o.joints) if (live(j) && !o.unsup[j.ia] && !o.unsup[j.ib]) union(j.ia, j.ib)\n const supported = new Set<number>()\n for (let i = 0; i < n; i++) if (!isLost(o.parts[i]) && !o.unsup[i] && (o.parts[i].structural || o.parts[i].anchored)) supported.add(find(i))\n for (const j of o.joints) {\n if (!live(j) || !(o.unsup[j.ia] || o.unsup[j.ib])) continue\n if (o.unsup[j.ia] && o.unsup[j.ib]) union(j.ia, j.ib)\n else {\n const u = o.unsup[j.ia] ? j.ia : j.ib\n const other = u === j.ia ? j.ib : j.ia\n if (!o.parts[other].structural && !supported.has(find(other))) union(u, other)\n }\n }\n } else for (const j of o.joints) if (live(j)) union(j.ia, j.ib)\n const comps = new Map<number, number[]>()\n for (let i = 0; i < n; i++) {\n if (isLost(o.parts[i])) continue\n const r = find(i)\n const l = comps.get(r)\n if (l) l.push(i)\n else comps.set(r, [i])\n }\n const list = [...comps.values()].map((ix) => ({\n ix,\n anchored: ix.some((i) => o.parts[i].anchored),\n mass: ix.reduce((s, i) => s + o.parts[i].st.mass, 0),\n }))\n list.sort((a, b) => (a.anchored === b.anchored ? (b.mass - a.mass) || (a.ix[0] - b.ix[0]) : a.anchored ? -1 : 1))\n o.st.groups = list.map((g) => g.ix.map((i) => o.parts[i].spec.id))\n for (const p of o.parts) if (isLost(p)) p.st.group = -1\n list.forEach((g, gi) => g.ix.forEach((i) => (o.parts[i].st.group = gi)))\n }\n\n /** Which part `r` rests on over joint `j` (index), or -1 when the joint does not let `r` rest on its other end. */\n const restsOn = (j: JointRT, r: number): number => {\n const b = j.bears\n if (!b) return -1\n if (b === true) return j.ia === r ? j.ib : j.ia\n if (b === 'a_on_b') return j.ia === r ? j.ib : -1\n return j.ib === r ? j.ia : -1\n }\n\n /** Distribute own mass plus carried load down the bearing graph to the anchored parts; mark parts without any support path. */\n const solveStructure = (o: ObjRT) => {\n o.maxStress = 0\n if (!o.hasStructure) return\n const parts = o.parts\n const n = parts.length\n const dist = new Array<number>(n).fill(-1)\n const queue: number[] = []\n const ok = (i: number) => parts[i].structural && !isLost(parts[i])\n const isPartition = (i: number) => parts[i].spec.structure?.role === 'partition'\n for (let i = 0; i < n; i++) if (ok(i) && parts[i].anchored) {\n dist[i] = 0\n queue.push(i)\n }\n for (let h = 0; h < queue.length; h++) {\n const s = queue[h]\n if (isPartition(s)) continue\n for (const j of o.byPart.get(parts[s].spec.id)!) {\n if (j.st.open || !j.bears) continue\n const r = j.ia === s ? j.ib : j.ia\n if (dist[r] >= 0 || !ok(r) || restsOn(j, r) !== s) continue\n dist[r] = dist[s] + 1\n queue.push(r)\n }\n }\n const incoming = new Array<number>(n).fill(0)\n for (let h = queue.length - 1; h >= 0; h--) {\n const i = queue[h]\n const total = parts[i].st.mass + incoming[i]\n parts[i].st.load = total\n const lower: number[] = []\n for (const j of o.byPart.get(parts[i].spec.id)!) {\n if (j.st.open || !j.bears) continue\n const k = restsOn(j, i)\n if (k >= 0 && dist[k] >= 0 && dist[k] < dist[i] && !isPartition(k)) lower.push(k)\n }\n for (const k of lower) incoming[k] += total / lower.length\n }\n for (let i = 0; i < n; i++) {\n const p = parts[i]\n o.unsup[i] = false\n if (!p.structural) continue\n if (dist[i] < 0 || isLost(p)) {\n p.st.load = p.st.mass\n p.st.stress = 0\n o.unsup[i] = o.anyAnchor && !isLost(p)\n continue\n }\n p.st.stress = p.st.load! / (p.cap * capacityScale(p))\n if (p.st.stress > o.maxStress) o.maxStress = p.st.stress\n }\n if (o.maxStress > 0.8) o.active = true\n }\n\n /**\n * Ask for a collapse report. It is not computed right away: a blow can break several parts in one go (a column and the roof's supports, or a\n * column whose joint opens just before the column itself fractures), so the groups are examined once, after every loss of the operation.\n */\n const collapseCheck = (o: ObjRT, src?: string) => {\n if (!o.hasStructure || !o.parts.some((p) => p.anchored)) return\n if (!pendingCollapse.has(o)) pendingCollapse.set(o, src)\n }\n\n /** Report the groups of remaining structural parts that lost every anchor (each part is reported once). */\n const flushCollapse = () => {\n for (const [o, src] of [...pendingCollapse]) {\n pendingCollapse.delete(o)\n if (!objects.has(o.id) || objects.get(o.id) !== o) continue\n for (const g of o.st.groups) {\n const ps = g.map((id) => o.byId.get(id)!).filter((p) => !isLost(p) && !o.collapsed.has(p.spec.id))\n if (ps.length === 0 || g.some((id) => o.byId.get(id)!.anchored) || !ps.some((p) => p.structural)) continue\n for (const p of ps) {\n o.collapsed.add(p.spec.id)\n p.st.status = 'collapsed'\n setStage(o, p, 3, {}, src)\n }\n emit({ ...base(o, src), type: 'collapse', parts: ps.map((p) => p.spec.id), mass: ps.reduce((sum, p) => sum + p.st.mass, 0) })\n }\n }\n }\n\n const getObj = (id: string): ObjRT => {\n const o = objects.get(id)\n if (!o) throw new Error(`unknown object \"${id}\"`)\n return o\n }\n const getPart = (o: ObjRT, id: string): PartRT => {\n const p = o.byId.get(id)\n if (!p) throw new Error(`unknown part \"${id}\" in object \"${o.id}\"`)\n return p\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Geometry in world space\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n const partXf = (o: ObjRT, p: PartRT): { c: Vec3; q: Quat } => ({ c: toWorld(o.st.position, o.st.rotation, p.pos), q: quat.mul(o.st.rotation, p.q) })\n const objLocal = (o: ObjRT, w: Vec3) => toLocal(o.st.position, o.st.rotation, w)\n const objLocalDir = (o: ObjRT, w: Vec3) => rotateVec(quat.conjugate(o.st.rotation), w)\n const jointWorld = (o: ObjRT, j: JointRT) => toWorld(o.st.position, o.st.rotation, j.pos)\n const distToPart = (o: ObjRT, p: PartRT, w: Vec3) => {\n const { c, q } = partXf(o, p)\n return distanceToShape(p.spec.shape, toLocal(c, q, w))\n }\n const partWorldAabb = (o: ObjRT, p: PartRT) => {\n const { c, q } = partXf(o, p)\n return aabbOf(p.spec.shape, c, q)\n }\n\n interface PartRay { t0: number; t1: number; n: Vec3 }\n const rayPartRaw = (pos: Vec3, rot: Quat, spec: PartSpec, pq: Quat, origin: Vec3, d: Vec3, lp: Vec3 = spec.position): PartRay | null => {\n const c = toWorld(pos, rot, lp)\n const q = quat.mul(rot, pq)\n const qi = quat.conjugate(q)\n const r = rayShape(spec.shape, rotateVec(qi, vec.sub(origin, c)), rotateVec(qi, d))\n return r ? { t0: r.t0, t1: r.t1, n: rotateVec(q, r.n0) } : null\n }\n const rayPart = (o: ObjRT, p: PartRT, origin: Vec3, d: Vec3): PartRay | null => rayPartRaw(o.st.position, o.st.rotation, p.spec, p.q, origin, d, p.pos)\n\n const raySphereMiss = (origin: Vec3, d: Vec3, c: Vec3, r: number, maxDist: number): boolean => {\n const oc = vec.sub(origin, c)\n const b = vec.dot(oc, d)\n const cc = vec.dot(oc, oc) - r * r\n if (cc > 0 && b > 0) return true\n const disc = b * b - cc\n if (disc < 0) return true\n return -b - Math.sqrt(disc) > maxDist\n }\n\n const raycastInternal = (origin: Vec3, dir: Vec3, maxDist: number, ignore?: Set<string>, worldOnly = false): (RayHit & { pathLen: number }) | null => {\n const d = vec.normalize(dir)\n let best: (RayHit & { pathLen: number }) | null = null\n for (const o of objects.values()) {\n if (raySphereMiss(origin, d, toWorld(o.st.position, o.st.rotation, o.bc), o.br, best ? Math.min(maxDist, best.distance) : maxDist)) continue\n for (const p of o.parts) {\n if (isLost(p) || ignore?.has(`${o.id}\\0${p.spec.id}`)) continue\n const r = rayPart(o, p, origin, d)\n if (!r || r.t0 < 0 || r.t0 > maxDist) continue\n if (p.st.opening && insideOpening(o, p, vec.madd(origin, d, r.t0))) continue\n if (!best || r.t0 < best.distance) best = { object: o.id, part: p.spec.id, point: vec.madd(origin, d, r.t0), normal: r.n, distance: r.t0, pathLen: r.t1 - r.t0 }\n }\n }\n for (const im of worldOnly ? [] : impls.values()) {\n for (const ps of im.impl.describe().parts) {\n if (ignore?.has(`${im.impl.id}\\0${ps.id}`)) continue\n const ov = im.poses.get(ps.id)\n const r = rayPartRaw(im.position, im.rotation, ps, ov?.q ?? quatFromEuler(...(ps.rotation ?? [0, 0, 0])), origin, d, ov?.pos)\n if (!r || r.t0 < 0 || r.t0 > maxDist) continue\n if (!best || r.t0 < best.distance) best = { 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 }\n }\n }\n return best\n }\n\n // impl hosting\n const implHit = (im: ImplRT, hit: Hit): HitResult => {\n let h = hit\n if (hit.space === 'local') {\n h = { ...hit, space: 'world', point: toWorld(im.position, im.rotation, hit.point) }\n if (hit.direction) h.direction = rotateVec(im.rotation, hit.direction)\n }\n const start = cur.length\n for (const e of im.impl.hit(h) ?? []) emit(e.time === undefined ? { ...e, time } : e)\n const mine = cur.slice(start)\n const res: HitResult = { object: im.impl.id, damage: 0, penetrated: false, exitEnergy: 0, events: mine, point: hit.point }\n for (const e of mine) {\n if (e.type === 'damage') res.damage += e.amount\n if (e.type === 'hole' && e.hole.through) res.penetrated = true\n if (res.part === undefined && 'part' in e) res.part = (e as { part: string }).part\n }\n return res\n }\n\n const implJointPos = (im: ImplRT, a: string, b: string): Vec3 | null => {\n const parts = im.impl.describe().parts\n const pa = parts.find((p) => p.id === a), pb = parts.find((p) => p.id === b)\n if (!pa || !pb) return null\n const A = aabbOf(pa.shape, pa.position, quatFromEuler(...(pa.rotation ?? [0, 0, 0])))\n const B = aabbOf(pb.shape, pb.position, quatFromEuler(...(pb.rotation ?? [0, 0, 0])))\n const pos: Vec3 = [0, 0, 0]\n for (let k = 0; k < 3; k++) pos[k] = (Math.max(A.min[k], B.min[k]) + Math.min(A.max[k], B.max[k])) / 2\n return toWorld(im.position, im.rotation, pos)\n }\n\n /** Find the part a hit lands on: a short ray along `dir`, else the nearest part within `tol`. */\n const locate = (o: ObjRT, point: Vec3, dir: Vec3 | undefined, tol: number, only?: PartRT): Loc | null => {\n const cands = only ? [only] : o.parts\n if (dir && vec.length(dir) > 1e-9) {\n const d = vec.normalize(dir)\n const origin = vec.madd(point, d, -0.05)\n let best: Loc | null = null\n let bestT = Infinity\n let inside: Loc | null = null\n for (const p of cands) {\n if (isLost(p)) continue\n const r = rayPart(o, p, origin, d)\n if (!r) continue\n if (r.t0 >= 0 && r.t0 <= 0.15) {\n if (r.t0 < bestT) {\n bestT = r.t0\n best = { p, point: vec.madd(origin, d, r.t0), normal: r.n, dir: d, pathLen: Math.max(r.t1 - r.t0, 1e-4) }\n }\n } else if (r.t0 < 0 && r.t1 > 0 && !inside) {\n inside = { p, point, normal: vec.scale(d, -1), dir: d, pathLen: Math.max(r.t1 - 0.05, p.thickness) }\n }\n }\n if (best) return best\n if (inside) return inside\n }\n let np: PartRT | null = null\n let nd = Infinity\n for (const p of cands) {\n if (isLost(p)) continue\n const dd = distToPart(o, p, point)\n if (dd < nd) {\n nd = dd\n np = p\n }\n }\n if (!np || nd > tol) return null\n const { c, q } = partXf(o, np)\n const sp = surfacePoint(np.spec.shape, toLocal(c, q, point))\n const normal = rotateVec(q, sp.normal)\n return { p: np, point: toWorld(c, q, sp.point), normal, dir: dir && vec.length(dir) > 1e-9 ? vec.normalize(dir) : vec.scale(normal, -1), pathLen: np.thickness }\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Marks on parts\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n const markDamaged = (p: PartRT) => {\n if (p.st.status === 'intact') p.st.status = 'damaged'\n }\n\n const addDent = (o: ObjRT, p: PartRT, wp: Vec3, wn: Vec3, radius: number, depth: number, src?: string) => {\n const dent: Dent = { point: objLocal(o, wp), normal: objLocalDir(o, wn), radius, depth }\n const arr = p.st.dents\n let ni = -1, nd = Infinity\n for (let i = 0; i < arr.length; i++) {\n const dd = vec.distance(arr[i].point, dent.point)\n if (dd < nd) {\n nd = dd\n ni = i\n }\n }\n if (ni >= 0 && (arr.length >= maxDents || nd < arr[ni].radius * 0.6)) {\n arr[ni].depth = Math.min(0.1, Math.max(arr[ni].depth, depth) + depth * 0.3)\n arr[ni].radius = Math.max(arr[ni].radius, radius)\n } else arr.push(dent)\n markDamaged(p)\n emit({ ...base(o, src), type: 'dent', part: p.spec.id, dent, worldPoint: wp })\n }\n\n const addHole = (o: ObjRT, p: PartRT, wp: Vec3, wn: Vec3, diameter: number, through: boolean, exit?: Vec3, src?: string) => {\n const hole: Hole = { point: objLocal(o, wp), normal: objLocalDir(o, wn), diameter, through }\n p.st.holes.push(hole)\n if (p.st.holes.length > maxHoles) p.st.holes.shift()\n markDamaged(p)\n emit({ ...base(o, src), type: 'hole', part: p.spec.id, hole, worldPoint: wp, ...(exit ? { exitPoint: exit } : {}) })\n setStage(o, p, 1, {}, src)\n return hole\n }\n\n const addCrack = (o: ObjRT, p: PartRT, wp: Vec3, wn: Vec3, length: number, src?: string) => {\n const crack: Crack = { point: objLocal(o, wp), normal: objLocalDir(o, wn), length: Math.min(length, Math.max(p.bound, 0.05)), rays: 5 + Math.floor(rnd() * 5) }\n p.st.cracks.push(crack)\n if (p.st.cracks.length > 16) p.st.cracks.shift()\n markDamaged(p)\n emit({ ...base(o, src), type: 'crack', part: p.spec.id, crack, worldPoint: wp })\n setStage(o, p, 1, {}, src)\n }\n\n const debris = (o: ObjRT, p: PartRT, kind: DebrisKind, point: Vec3, normal: Vec3, count: number, speed: number, src?: string) =>\n emit({ ...base(o, src), type: 'debris', part: p.spec.id, kind, point, normal, count, speed })\n\n const holeRate = (hole: Hole, pressurized: boolean) => (pressurized ? 0.5 : 0.1) * (hole.diameter / 0.009)\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Failure, joints\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n const detachEvents = (o: ObjRT, opened: JointRT[], by: 'break' | 'tool' | 'part_lost', src?: string) => {\n 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]) })\n }\n\n const checkDestroyed = (o: ObjRT, src?: string) => {\n if (!o.st.destroyed && o.parts.length > 0 && o.parts.every(isLost)) {\n o.st.destroyed = true\n emit({ ...base(o, src), type: 'destroyed' })\n }\n }\n\n const partLost = (o: ObjRT, p: PartRT, src?: string) => {\n const opened: JointRT[] = []\n for (const j of o.byPart.get(p.spec.id) ?? []) {\n if (j.st.open) continue\n j.st.open = true\n j.st.openedBy = 'part_lost'\n opened.push(j)\n }\n solveStructure(o)\n recomputeGroups(o)\n detachEvents(o, opened, 'part_lost', src)\n collapseCheck(o, src)\n checkDestroyed(o, src)\n }\n\n /**\n * Distance from a world point to the joint's contact region: the overlap box of the two parts' bounds (or, when they only nearly touch, the box\n * of the gap between them). Measuring to the joint centre would make a thick part untouchable: a blow on a trunk's surface is half the trunk's\n * width away from a joint that sits on its axis.\n */\n const jointReach = (o: ObjRT, j: JointRT, point: Vec3): number => {\n const A = partWorldAabb(o, o.parts[j.ia]), B = partWorldAabb(o, o.parts[j.ib])\n let d2 = 0\n for (let k = 0; k < 3; k++) {\n const lo = Math.min(Math.max(A.min[k], B.min[k]), Math.min(A.max[k], B.max[k]))\n const hi = Math.max(Math.max(A.min[k], B.min[k]), Math.min(A.max[k], B.max[k]))\n const d = point[k] < lo ? lo - point[k] : point[k] > hi ? point[k] - hi : 0\n d2 += d * d\n }\n return Math.sqrt(d2)\n }\n /** How far from the contact region a blow still counts: half the smallest dimension of the smaller part, at least 6 cm. */\n const jointReachLimit = (o: ObjRT, j: JointRT): number => {\n const pa = o.parts[j.ia], pb = o.parts[j.ib]\n const small = pa.dims[0] * pa.dims[1] * pa.dims[2] <= pb.dims[0] * pb.dims[1] * pb.dims[2] ? pa : pb\n return Math.max(0.06, 0.5 * Math.min(small.dims[0], small.dims[1], small.dims[2]))\n }\n\n const wearJoints = (o: ObjRT, p: PartRT, amount: number, near?: Vec3, radius = 0.06, src?: string, split = false) => {\n if (amount <= 0) return\n const mine = (o.byPart.get(p.spec.id) ?? []).filter((j) => !j.st.open)\n if (split && mine.length) amount /= mine.length\n for (const j of mine) {\n if (j.st.open) continue\n // the rebar of a reinforced part is its cage: blows do not wear it, only a torch or a saw cuts it (or the cage itself giving way)\n if (j.spec.kind === 'rebar' && (o.parts[j.ia].spec.reinforcement || o.parts[j.ib].spec.reinforcement)) continue\n if (near && jointReach(o, j, near) > Math.max(radius, jointReachLimit(o, j))) continue\n j.st.hp -= amount\n if (j.st.hp <= 0) {\n j.st.hp = 0\n j.st.open = true\n j.st.openedBy = 'break'\n solveStructure(o)\n recomputeGroups(o)\n detachEvents(o, [j], 'break', src)\n collapseCheck(o, src)\n }\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Damage stages: spall, breach, reinforcement cage\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n const setStage = (o: ObjRT, p: PartRT, stage: DamageStage, extra: { opening?: { center: Vec3; radius: number }; fragments?: Fragment[] } = {}, src?: string) => {\n if (!p.staged || (p.st.stage ?? 0) >= stage) return\n p.st.stage = stage\n emit({ ...base(o, src), type: 'stage', part: p.spec.id, stage, ...extra })\n }\n\n /** `1` when the outward normal points along the part's local +thin axis, else `-1`. */\n const faceOf = (o: ObjRT, p: PartRT, worldNormal: Vec3): number => (rotateVec(quat.conjugate(partXf(o, p).q), worldNormal)[p.thin] >= 0 ? 1 : -1)\n\n const spallOuter = (o: ObjRT, p: PartRT, wp: Vec3, face: number, normal: Vec3, radius: number, src?: string) => {\n if (p.layers.length === 0) return\n const lp = objLocal(o, wp)\n const layer = outerLayer(p.layers, p.rt.spalls, face, lp)\n if (!layer) return\n const spalls = (p.rt.spalls ??= [])\n spalls.push([layer.index, face, lp[0], lp[1], lp[2], radius])\n if (spalls.length > MAX_SPALLS) spalls.shift()\n markDamaged(p)\n emit({ ...base(o, src), type: 'spall', part: p.spec.id, layer: layer.index, point: wp, area: Math.PI * radius * radius })\n debris(o, p, layer.mat.hitDebris, wp, normal, 5, 2, src)\n setStage(o, p, 1, {}, src)\n }\n\n const insideOpening = (o: ObjRT, p: PartRT, objectPoint: Vec3): boolean => {\n const op = p.st.opening\n if (!op) return false\n const [u, v] = planeAxes(p.thin)\n const lp = toLocal(p.pos, p.q, objectPoint)\n const lc = toLocal(p.pos, p.q, op.center)\n return Math.hypot(lp[u] - lc[u], lp[v] - lc[v]) <= op.radius\n }\n\n /** Square metres of wall a blow removes: the volume its damage takes out, over the thickness it crosses. */\n const breachAreaOf = (p: PartRT, damage: number, blast: boolean): number =>\n (damage / (p.mat.hpPerKg * p.mat.density) / Math.max(p.thickness, 0.005)) * (blast ? breachBlastFactor : 1)\n\n const localHolesOf = (p: PartRT): LocalHole[] =>\n p.st.holes.map((h) => ({ point: toLocal(p.pos, p.q, h.point), normal: rotateVec(quat.conjugate(p.q), h.normal), diameter: h.diameter }))\n\n const unitsOf = (p: PartRT) => p.spec.units ?? { size: [p.mat.fragmentSize?.[1] ?? 0.2, p.mat.fragmentSize?.[1] ?? 0.2, p.thickness] as Vec3, bond: 'stack' as const }\n\n const FRAGMENT_SHAPE = { shatter: 'shard', splinter: 'splinter', tear: 'scrap' } as const\n\n /** Unit-sized fragments of `cells` (part-local), thrown from `hitW`; the holes that fell on a unit stay on it as `marks`. */\n const cellFragments = (o: ObjRT, p: PartRT, cells: readonly UnitCell[], hitW: Vec3, dir: Vec3 | null, speed: number, mass: number, tag: string): Fragment[] => {\n const { c, q } = partXf(o, p)\n const holes = p.st.holes.length > 0 ? localHolesOf(p) : []\n const [u, v] = planeAxes(p.thin)\n const faceArea = (cell: UnitCell) => cell.size[u] * cell.size[v]\n const total = cells.reduce((sum, cell) => sum + faceArea(cell), 0) || 1\n const shape = p.spec.units ? 'chunk' : FRAGMENT_SHAPE[p.mat.fracture as keyof typeof FRAGMENT_SHAPE] ?? 'chunk'\n return cells.map((cell, i) => {\n const cw = toWorld(c, q, cell.center)\n const out = vec.normalize(vec.sub(cw, hitW), [0, 1, 0])\n const dv = dir ? vec.normalize(vec.madd(out, dir, 0.6)) : out\n const k = speed * (0.6 + 0.8 * rnd())\n const marks = marksInBox(cell.center, cell.size, undefined, holes)\n return {\n id: `${p.spec.id}#${tag}${i}`, part: p.spec.id, material: p.spec.material, shape, center: cw, size: [cell.size[0], cell.size[1], cell.size[2]], rotation: q,\n velocity: [dv[0] * k, dv[1] * k + 0.5 * rnd(), dv[2] * k], angularVelocity: [(rnd() - 0.5) * 8, (rnd() - 0.5) * 8, (rnd() - 0.5) * 8],\n mass: (mass * faceArea(cell)) / total, ...(marks.length > 0 ? { marks } : {}),\n }\n })\n }\n\n const worldBars = (o: ObjRT, p: PartRT, bars: ReadonlyArray<readonly [Vec3, Vec3]>): Array<[Vec3, Vec3]> => {\n const { c, q } = partXf(o, p)\n return bars.map(([a, b]) => [toWorld(c, q, a), toWorld(c, q, b)])\n }\n\n /** A blow that made through damage of `area` m² at `wp` (world): adds up with the earlier ones within the breach radius, and opens the part past its threshold. */\n const addBreach = (o: ObjRT, p: PartRT, wp: Vec3, area: number, energy: number, dir: Vec3 | null, src?: string) => {\n if (!p.staged || area <= 0 || (p.st.stage ?? 0) >= 2 || p.st.stripped || isLost(p)) return\n const lp = objLocal(o, wp)\n const list = (p.rt.breach ??= [])\n list.push([lp[0], lp[1], lp[2], area])\n if (list.length > MAX_SPALLS) list.shift()\n let total = 0\n const sum: Vec3 = [0, 0, 0]\n for (const [x, y, z, a] of list) {\n if (vec.distance([x, y, z], lp) > breachRadius) continue\n total += a\n sum[0] += x * a\n sum[1] += y * a\n sum[2] += z * a\n }\n if (total < (p.spec.breach?.area ?? BREACH_AREA)) return\n openBreach(o, p, [sum[0] / total, sum[1] / total, sum[2] / total], total, energy, dir, src)\n }\n\n /**\n * Stage 2: the units around `center` (object-local) come out as fragments the size of one unit, the part keeps an opening and its mass drops. An\n * opening as wide as the part cuts it in two (a column, a lintel): that is a fracture instead.\n */\n const openBreach = (o: ObjRT, p: PartRT, center: Vec3, total: number, energy: number, dir: Vec3 | null, src?: string) => {\n const [u, v] = planeAxes(p.thin)\n const radius = clamp(Math.sqrt(total / Math.PI), Math.sqrt((p.spec.breach?.area ?? BREACH_AREA) / Math.PI), breachRadius)\n const lc = toLocal(p.pos, p.q, center)\n lc[p.thin] = 0\n const { c, q } = partXf(o, p)\n const worldCenter = toWorld(c, q, lc)\n if (2 * radius >= Math.min(p.dims[u], p.dims[v])) {\n failPart(o, p, worldCenter, dir, energy, 12, src)\n return\n }\n const cells = cellsWithin(unitGrid(p.dims, p.thin, unitsOf(p), BREACH_GRID_CAP), p.thin, lc, radius)\n const removed = (p.st.mass * cells.reduce((sum, cell) => sum + cell.size[u] * cell.size[v], 0)) / (p.dims[u] * p.dims[v])\n const speed = clamp(Math.sqrt((2 * energy * 0.1) / Math.max(removed, 0.05)), 0.5, 8)\n const fragments = cellFragments(o, p, cells, worldCenter, dir, speed, removed, 'b')\n const holes = localHolesOf(p)\n p.st.holes = p.st.holes.filter((_, i) => !cells.some((cell) => marksInBox(cell.center, cell.size, undefined, [holes[i]!]).length > 0))\n p.st.mass = Math.max(0, p.st.mass - removed)\n p.rt.removed = (p.rt.removed ?? 0) + removed\n p.st.opening = { center: objLocal(o, worldCenter), radius }\n markDamaged(p)\n setStage(o, p, 1, {}, src)\n setStage(o, p, 2, { opening: { center: worldCenter, radius }, fragments }, src)\n debris(o, p, p.mat.breakDebris, worldCenter, vec.scale(dir ?? [0, 1, 0], -1), 14, 3, src)\n const reinforcement = p.spec.reinforcement\n if (reinforcement) {\n const bars = worldBars(o, p, clipBarsToDisc(rebarBars(p.dims, p.thin, reinforcement.spacing), u, v, [lc[u], lc[v]], radius + 0.05))\n if (bars.length > 0) emit({ ...base(o, src), type: 'expose', part: p.spec.id, bars })\n }\n if (p.structural) solveStructure(o)\n }\n\n /** The concrete of a reinforced part is gone: the part stays as its rebar cage, with the capacity the reinforcement leaves it. */\n const stripPart = (o: ObjRT, p: PartRT, reinforcement: NonNullable<PartSpec['reinforcement']>, src?: string) => {\n const bars = rebarBars(p.dims, p.thin, reinforcement.spacing)\n p.st.stripped = true\n p.st.hp = p.st.maxHp\n p.st.mass = rebarMass(bars, reinforcement.diameter, materials.get(reinforcement.material)?.density)\n p.st.holes = []\n p.st.burning = false\n p.rt.jet = false\n markDamaged(p)\n emit({ ...base(o, src), type: 'expose', part: p.spec.id, bars: worldBars(o, p, bars) })\n solveStructure(o)\n collapseCheck(o, src)\n }\n\n /** The units of the part that are still there (the opening of a breach is already gone), as a fragment plan. */\n const unitFragmentPlan = (p: PartRT, cap: number): PlannedFragment[] => {\n const grid = unitGrid(p.dims, p.thin, unitsOf(p), cap)\n const op = p.st.opening\n const cells = op ? cellsOutside(grid, p.thin, toLocal(p.pos, p.q, op.center), op.radius) : grid\n const [u, v] = planeAxes(p.thin)\n return cells.map((cell) => ({ center: cell.center, size: cell.size, q: quat.identity(), shape: 'chunk' as const, weight: cell.size[u] * cell.size[v] }))\n }\n\n /** The bare cage gives way (overload, a blast, a cut that finishes): the part is lost for good. */\n const loseCage = (o: ObjRT, p: PartRT, src?: string) => {\n p.st.status = 'broken'\n p.st.hp = 0\n p.st.mass = 0\n emit({ ...base(o, src), type: 'expose', part: p.spec.id, bars: [] })\n debris(o, p, 'sparks', partXf(o, p).c, [0, 1, 0], 6, 3, src)\n partLost(o, p, src)\n }\n\n /** Part hit points reached 0 (or it was forced to explode): fragments, debris, joints open. */\n const failPart = (o: ObjRT, p: PartRT, origin: Vec3 | null, dir: Vec3 | null, fragEnergy: number, cap: number, src?: string) => {\n if (isLost(p)) return\n if (p.st.stripped) {\n loseCage(o, p, src)\n return\n }\n const ex = p.spec.explodes\n const style = p.mat.fracture === 'none' ? 'snap' : p.mat.fracture\n const { c, q } = partXf(o, p)\n const hitW = origin ?? c\n const grain = p.spec.grain ? AXIS[p.spec.grain] : undefined\n const hitLocal = toLocal(c, q, hitW)\n const unitPlan = p.spec.units ? unitFragmentPlan(p, maxFragments * UNIT_FRAGMENT_FACTOR) : []\n const plan = unitPlan.length > 0 ? unitPlan : planFragments({\n style, dims: p.dims, thickness: p.thickness, grain, hit: hitLocal, fragmentSize: p.mat.fragmentSize ?? [0.04, 0.2], maxFragments, rnd,\n })\n const holes = p.st.holes.length > 0 ? localHolesOf(p) : []\n const mass = p.st.mass\n const totW = plan.reduce((s, f) => s + f.weight, 0) || 1\n const energy = ex ? ex.energy * 0.2 : fragEnergy\n const speed = clamp(Math.sqrt((2 * energy) / Math.max(mass, 0.05)), 0.3, ex ? 40 : cap)\n const fragments: Fragment[] = plan.map((f, i) => {\n const cw = toWorld(c, q, f.center)\n const out = vec.normalize(vec.sub(cw, hitW), [0, 1, 0])\n const dv = dir ? vec.normalize(vec.madd(out, dir, 0.6)) : out\n const k = speed * (0.6 + 0.8 * rnd())\n const marks = marksInBox(f.center, f.size, f.q, holes)\n return {\n id: `${p.spec.id}#${i}`, part: p.spec.id, material: p.spec.material, shape: f.shape, center: cw, size: f.size, rotation: quat.mul(q, f.q),\n velocity: [dv[0] * k, dv[1] * k + 0.5 * rnd(), dv[2] * k],\n angularVelocity: [(rnd() - 0.5) * 12, (rnd() - 0.5) * 12, (rnd() - 0.5) * 12],\n mass: (mass * f.weight) / totW, ...(marks.length > 0 ? { marks } : {}),\n }\n })\n const reinforcement = p.spec.reinforcement\n if (!reinforcement) {\n p.st.status = 'broken'\n p.st.hp = 0\n p.st.mass = 0\n p.st.burning = false\n p.rt.jet = false\n }\n emit({ ...base(o, src), type: 'fracture', part: p.spec.id, style, fragments, point: hitW })\n debris(o, p, p.mat.breakDebris, c, [0, 1, 0], clamp(Math.round(Math.cbrt(partVolume(p.spec.shape)) * 30), 3, 20), 2, src)\n setStage(o, p, 3, {}, src)\n if (reinforcement) {\n stripPart(o, p, reinforcement, src)\n return\n }\n if (ex) {\n emit({ ...base(o, src), type: 'explode', part: p.spec.id, point: c, energy: ex.energy, radius: ex.radius, ...(ex.effect !== undefined ? { effect: ex.effect } : {}) })\n blasts.push({ point: c, energy: ex.energy, radius: ex.radius, source: src })\n }\n partLost(o, p, src)\n }\n\n /**\n * Sets an explosive part off from outside (`explodes.chain`): it will explode after the delay of `trigger`, once. The delay is one draw\n * from the world seed, so the same inputs give the same order of blasts.\n */\n const prime = (o: ObjRT, p: PartRT, trigger: ChainTrigger, src?: string) => {\n const spec = chainDelayOf(p.spec, trigger)\n if (spec === undefined || isLost(p) || p.rt.chainDue !== undefined) return\n const delay = drawChainDelay(spec, rnd)\n p.rt.chainDue = time + delay\n primed.set(p, o)\n o.active = true\n emit({ ...base(o, src), type: 'primed', part: p.spec.id, point: partXf(o, p).c, trigger, delay })\n }\n\n const CHAIN_TRIGGER_OF: Partial<Record<DamageType, ChainTrigger>> = { ballistic: 'shot', explosive: 'explosion' }\n\n /** Remove hit points. Returns the amount actually removed. */\n const applyDamage = (o: ObjRT, p: PartRT, amount: number, type: DamageType, origin: Vec3 | null, dir: Vec3 | null, fragEnergy: number, cap: number, src?: string): number => {\n if (isLost(p) || amount <= 0) return 0\n const prev = p.st.hp\n p.st.hp -= amount\n markDamaged(p)\n const trigger = CHAIN_TRIGGER_OF[type]\n const chained = trigger !== undefined && chainDelayOf(p.spec, trigger) !== undefined\n // a bullet or a blast sets a chained part off after its delay instead of tearing it apart on the spot\n if (chained && p.st.hp <= 0 && p.rt.chainDue === undefined) p.st.hp = Math.min(prev, 1)\n if (p.st.hp <= 0 && p.mat.fracture === 'none' && !p.spec.explodes) p.st.hp = Math.min(prev, 1)\n const done = prev - p.st.hp\n if (done > 0) emit({ ...base(o, src), type: 'damage', part: p.spec.id, amount: done, hp: Math.max(0, p.st.hp), damageType: type })\n if (p.st.hp <= 0) failPart(o, p, origin, dir, fragEnergy, cap, src)\n else if (chained && (trigger === 'explosion' || 1 - p.st.hp / p.st.maxHp >= shotDamageFractionOf(p.spec))) prime(o, p, trigger, src)\n return done\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Hits\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n interface BallisticOut { penetrated: boolean; exitEnergy: number; exitPoint?: Vec3; damage: number }\n\n const ballistic = (o: ObjRT, p: PartRT, entry: Vec3, n: Vec3, d: Vec3, E: number, caliber: number, pathLen: number, src?: string, piercing = 1): BallisticOut => {\n const mat = p.mat\n // a bare cage and an opening do not stop a bullet\n if (p.st.stripped || (p.st.opening && insideOpening(o, p, objLocal(o, entry)))) {\n return { penetrated: true, exitEnergy: E, exitPoint: vec.madd(entry, d, Math.min(pathLen, p.thickness)), damage: 0 }\n }\n const sin = Math.min(1, Math.abs(vec.dot(d, n)))\n const angle = (Math.asin(sin) * 180) / Math.PI\n const slant = Math.max(sin, 0.3)\n const effM = p.thickness / slant\n const face = p.layers.length > 0 ? faceOf(o, p, n) : 1\n const exitLocal = objLocal(o, vec.madd(entry, d, Math.min(pathLen, effM)))\n const coats = p.layers.length > 0 ? layersEnergy(p.layers, p.rt.spalls, face, objLocal(o, entry)) + layersEnergy(p.layers, p.rt.spalls, -face, exitLocal) : 0\n // each coat adds penetration x thickness to the core's; a part without layers keeps the plain formula\n const thr = coats > 0 ? (mat.penetration * p.thickness * 1000 + coats) / slant : mat.penetration * effM * 1000\n // the bullet's kind matters against hard targets (steel, masonry); wood, flesh and the like take every bullet for its energy\n const hard = mat.tags?.includes('metal') || mat.tags?.includes('masonry')\n const Ep = piercing === 1 || !hard ? E : E * piercing\n const penetrated = Ep > thr\n // a thin brittle shell that shatters (a pane, a bottle) is lost to one bullet that a thick block of the same glass shrugs off: the same\n // fragility factor that melee uses for blunt hits (1 for ductile materials and for shells 2 cm or thicker, up to x118 for 3 mm glass)\n const scale = (mat.damageScale?.ballistic ?? 1) * (mat.fracture === 'shatter' ? fragility(mat.ductility, p.thickness) : 1)\n const id = p.spec.id\n if (!penetrated && mat.ricochetDeg && angle < mat.ricochetDeg) {\n const r = vec.sub(d, vec.scale(n, 2 * vec.dot(d, n)))\n emit({ ...base(o, src), type: 'ricochet', part: id, point: entry, direction: vec.normalize(r), energy: E * 0.4 })\n debris(o, p, mat.hitDebris, entry, n, 3, 3, src)\n const dmg = applyDamage(o, p, E * DMG_PER_J * scale * 0.2, 'ballistic', entry, d, E * 0.1, 12, src)\n return { penetrated: false, exitEnergy: 0, damage: dmg }\n }\n if (p.layers.length > 0) spallOuter(o, p, entry, face, n, Math.max(0.03, (caliber / 1000) * 4), src)\n const brittle = mat.ductility < 0.3\n const ratio = Ep / Math.max(thr, 1e-6)\n const crackLen = clamp(0.03 + ratio * 0.2, 0.03, 0.8)\n let exitPoint: Vec3 | undefined\n if (penetrated) {\n exitPoint = vec.madd(entry, d, Math.min(pathLen, effM + layersThickness(p.layers, face) / slant + layersThickness(p.layers, -face) / slant))\n const hole = addHole(o, p, entry, n, (caliber / 1000) * (mat.ductility >= 0.3 ? 1 : 1.5), true, exitPoint, src)\n if (p.layers.length > 0) spallOuter(o, p, exitPoint, -face, vec.scale(n, -1), Math.max(0.03, (caliber / 1000) * 4), src)\n addBreach(o, p, entry, Math.PI * (hole.diameter / 2) * (hole.diameter / 2), E, d, src)\n if (brittle && mat.fracture === 'shatter') addCrack(o, p, entry, n, crackLen, src)\n if (p.spec.contains && (p.st.liters ?? 0) > 0) {\n emit({\n ...base(o, src), type: 'leak', part: id, fluid: p.spec.contains.fluid, point: entry, direction: n, rate: holeRate(hole, !!p.spec.contains.pressurized),\n pressurized: !!p.spec.contains.pressurized,\n })\n }\n } else if (mat.ductility >= 0.5) {\n addDent(o, p, entry, n, Math.max((caliber * 3) / 1000, 0.012), clamp(Math.min(Math.max(p.thickness * 3, 0.003), ratio * 0.01), 0.001, 0.05), src)\n } else if (brittle) {\n addCrack(o, p, entry, n, crackLen, src)\n if (mat.fracture !== 'shatter') addHole(o, p, entry, n, caliber / 1000, false, undefined, src)\n } else addHole(o, p, entry, n, caliber / 1000, false, undefined, src)\n debris(o, p, mat.hitDebris, entry, n, clamp(Math.round(E / 60) + 2, 2, 14), clamp(Math.sqrt(E) / 6, 1, 8), src)\n // a bullet only wears the joints of the part it hits, by the energy the part absorbed (a through-and-through shot transfers little)\n wearJoints(o, p, (penetrated ? thr : E) * 0.02, undefined, 0, src, true)\n const dmg = applyDamage(o, p, E * DMG_PER_J * scale, 'ballistic', entry, d, E * 0.1, 12, src)\n return { penetrated, exitEnergy: penetrated ? E - thr / (hard ? piercing : 1) : 0, exitPoint, damage: dmg }\n }\n\n const melee = (o: ObjRT, p: PartRT, kind: 'blunt' | 'slash', E: number, point: Vec3, n: Vec3, d: Vec3, contactR: number, src?: string): number => {\n const mat = p.mat\n const thrMm = mat.penetration * p.thickness * 1000\n // brittle thin shells (a bottle, a mug, a pane) break from a knock that a thick block shrugs off\n const fragile = kind === 'blunt' ? fragility(mat.ductility, p.thickness) : 1\n const Ec = E * fragile\n if (E > 0) {\n if (kind === 'blunt') {\n if (mat.ductility >= 0.5) addDent(o, p, point, n, Math.max(contactR, 0.015), clamp(E * 0.0001, 0.001, 0.06), src)\n else if (mat.ductility < 0.3) {\n if (Ec >= 5) addCrack(o, p, point, n, clamp(0.04 + Math.min(Ec, E * 6) * 0.0008, 0.04, 0.6), src)\n } else if (E >= thrMm * 0.2) addDent(o, p, point, n, Math.max(contactR, 0.015), clamp(E * 0.00006, 0.001, 0.04), src)\n } else if (mat.fracture === 'tear') {\n addHole(o, p, point, n, clamp(0.02 + E * 0.0005, 0.02, 0.3), true, undefined, src)\n } else if (mat.ductility >= 0.5) {\n addDent(o, p, point, n, Math.max(contactR, 0.01), clamp(E * 0.00004, 0.0005, 0.02), src)\n }\n debris(o, p, mat.hitDebris, point, n, clamp(Math.round(E / 25) + 1, 1, 10), clamp(Math.sqrt(E) / 8, 1, 6), src)\n }\n if (kind === 'blunt') wearJoints(o, p, E * 0.3, undefined, 0, src)\n else wearJoints(o, p, E * 0.3, point, 0.06, src)\n if (kind === 'blunt' && E > 0 && p.layers.length > 0) spallOuter(o, p, point, faceOf(o, p, n), n, Math.max(contactR, 0.05), src)\n const scale = mat.damageScale?.[kind] ?? 1\n const done = applyDamage(o, p, Ec * DMG_PER_J * scale * (kind === 'slash' ? p.cutFactor : 1), kind, point, d, E * 0.1, 12, src)\n addBreach(o, p, point, breachAreaOf(p, done, false), E, d, src)\n return done\n }\n\n /**\n * What one part takes of a blast: dents, cracks, debris, heat, joint wear and the hit points. `reach` is the share of the blast that gets to the\n * part (`blast.shelter`; 1 without it) and it comes back, so a caller can report it. It is computed from the point of the part nearest to the centre.\n */\n const blastPart = (o: ObjRT, p: PartRT, point: Vec3, energy: number, radius: number, src: string | undefined, res: HitResult, reachAt?: (wp: Vec3, p: PartRT) => number): number | null => {\n if (isLost(p)) return null\n const { c, q } = partXf(o, p)\n const lp = toLocal(c, q, point)\n const dist = distanceToShape(p.spec.shape, lp)\n if (dist >= radius) return null\n const sp = surfacePoint(p.spec.shape, lp)\n const wp = toWorld(c, q, sp.point)\n const reach = reachAt ? reachAt(wp, p) : 1\n const f = (1 - dist / radius) ** 2 * reach\n const Ein = energy * f * BLAST_COUPLING\n const wn = rotateVec(q, sp.normal)\n if (!res.part) {\n res.part = p.spec.id\n res.point = wp\n }\n const mat = p.mat\n if (Ein > 20) {\n if (mat.ductility >= 0.5) addDent(o, p, wp, wn, clamp(0.05 + Math.sqrt(Ein) * 0.002, 0.05, 0.4), clamp(0.004 + Ein * 0.00002, 0.004, 0.08), src)\n else if (mat.ductility < 0.3 && Ein > 60) addCrack(o, p, wp, wn, clamp(0.05 + Ein * 0.0005, 0.05, 1), src)\n debris(o, p, mat.hitDebris, wp, wn, clamp(Math.round(Ein / 80) + 1, 1, 12), clamp(Math.sqrt(Ein) / 4, 2, 15), src)\n }\n const th = mat.thermal\n if (th.ignitionC !== undefined && p.st.fuel > 0) {\n p.st.temperature += 300 * f\n o.active = true\n if (f >= 0.25 && !p.st.burning) {\n p.st.temperature = Math.max(p.st.temperature, th.ignitionC + 1)\n checkIgnite(o, p, src)\n }\n }\n wearJoints(o, p, Ein * 0.5, undefined, 0, src)\n const amount = Ein * DMG_PER_J * (mat.damageScale?.explosive ?? 1)\n if (blastFrontSpeed > 0 && dist > 0 && mat.tags?.includes('glass')) {\n frontQueue.push({ o, p, due: time + dist / blastFrontSpeed, amount, fragEnergy: Ein * 0.3, point, ...(src !== undefined ? { src } : {}) })\n return reach\n }\n if (Ein > 20 && p.layers.length > 0) spallOuter(o, p, wp, faceOf(o, p, wn), wn, clamp(0.05 + Math.sqrt(Ein) * 0.002, 0.05, 0.4), src)\n const dealt = applyDamage(o, p, amount, 'explosive', point, null, Ein * 0.3, 40, src)\n res.damage += dealt\n if (dist <= breachBlastReach * Math.cbrt(Math.max(0, energy) / 1000)) addBreach(o, p, wp, breachAreaOf(p, dealt, true), Ein, null, src)\n return reach\n }\n\n const blastObject = (o: ObjRT, point: Vec3, energy: number, radius: number, src?: string): HitResult => {\n const start = cur.length\n const res: HitResult = { object: o.id, damage: 0, penetrated: false, exitEnergy: 0, events: [] }\n for (const p of o.parts) blastPart(o, p, point, energy, radius, src, res)\n res.events = cur.slice(start)\n return res\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Blast options: shelter, fragment hits, confinement (all off by default)\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n interface BlastCfg {\n shelter: Required<ShelterOptions> | null\n frag: Required<FragmentHitOptions> | null\n /** A number is the multiplier itself. */\n conf: Required<ConfinementOptions> | number | null\n }\n\n const blastCfg = (call?: BlastOptions): BlastCfg => {\n const pick = <K extends keyof BlastOptions>(key: K): BlastOptions[K] => (call && call[key] !== undefined ? call[key] : options.blast?.[key])\n const merge = <T extends object>(v: boolean | T | undefined, defaults: Required<T>): Required<T> | null => {\n if (!v) return null\n const out = { ...defaults }\n if (v !== true) for (const [key, value] of Object.entries(v)) if (value !== undefined) (out as Record<string, unknown>)[key] = value\n return out\n }\n const conf = pick('confinement')\n return {\n shelter: merge(pick('shelter'), SHELTER_DEFAULTS),\n frag: merge(pick('fragmentHits'), FRAGMENT_HIT_DEFAULTS),\n conf: typeof conf === 'number' ? (Number.isFinite(conf) ? Math.max(0, conf) : 1) : merge(conf, CONFINEMENT_DEFAULTS),\n }\n }\n\n /** Same directions in every blast of this world: a Fibonacci lattice turned by the world seed. */\n const confinementRays = new Map<number, Vec3[]>()\n const raysOf = (n: number): Vec3[] => {\n let rays = confinementRays.get(n)\n if (rays) return rays\n const r = createRng((options.seed ?? 1) ^ 0x5bd1e995)\n const off = r.next()\n const phi0 = r.next() * Math.PI * 2\n rays = []\n for (let i = 0; i < n; i++) {\n const y = 1 - (2 * (i + off)) / n\n const s = Math.sqrt(Math.max(0, 1 - y * y))\n const phi = phi0 + i * 2.399963229728653\n rays.push([Math.cos(phi) * s, y, Math.sin(phi) * s])\n }\n confinementRays.set(n, rays)\n return rays\n }\n\n /** Pressure multiplier of a blast at `point`: the host's number, or an estimate from rays that hit parts (never the ones that are lost or open). */\n const confinementOf = (conf: BlastCfg['conf'], point: Vec3, radius: number): number => {\n if (conf === null) return 1\n if (typeof conf === 'number') return conf\n let hits = 0\n let sum = 0\n for (const d of raysOf(Math.max(1, Math.round(conf.rays)))) {\n const h = raycastInternal(point, d, radius * conf.reach, undefined, true)\n if (h) {\n hits++\n sum += h.distance\n }\n }\n if (hits === 0) return 1\n const closed = hits / Math.max(1, Math.round(conf.rays))\n const ratio = clamp(radius / Math.max(sum / hits, 1e-3), 0, 2)\n return Math.min(Math.max(1, conf.max), 1 + conf.gain * closed ** conf.power * ratio)\n }\n\n const FLAG_LOST = 1\n const FLAG_OPEN = 2\n\n /** The legacy blast: every part of every object, then every impl, each at full strength. */\n const blastPlain = (point: Vec3, energy: number, radius: number, src?: string): HitResult[] => {\n const out: HitResult[] = []\n for (const o of [...objects.values()]) {\n if (vec.distance(toWorld(o.st.position, o.st.rotation, o.bc), point) - o.br >= radius) continue\n const r = blastObject(o, point, energy, radius, src)\n if (r.part) out.push(r)\n }\n for (const im of [...impls.values()]) {\n if (implInRange(im, point, radius)) out.push(implHit(im, { type: 'explosive', point, energy, radius, ...(src !== undefined ? { source: src } : {}) }))\n }\n return out\n }\n\n const implParts = (im: ImplRT) =>\n im.impl.describe().parts.map((ps) => {\n const ov = im.poses.get(ps.id)\n return { ps, c: toWorld(im.position, im.rotation, ov?.pos ?? ps.position), q: quat.mul(im.rotation, ov?.q ?? quatFromEuler(...(ps.rotation ?? [0, 0, 0]))) }\n })\n\n const implInRange = (im: ImplRT, point: Vec3, radius: number): boolean => implParts(im).some(({ ps, c, q }) => distanceToShape(ps.shape, toLocal(c, q, point)) < radius)\n\n /** A blast with shelter, fragment hits or confinement. Parts are served from the nearest to the farthest, so a wall takes the blast (and may break) before what is behind it. */\n const blastScene = (point: Vec3, energy: number, radius: number, src: string | undefined, cfg: BlastCfg, only?: ObjRT | ImplRT): HitResult[] => {\n const mult = confinementOf(cfg.conf, point, radius)\n const E = energy * mult\n const shelter = cfg.shelter\n const flags = new Map<PartRT, number>()\n const inRange: ObjRT[] = []\n for (const o of objects.values()) {\n if (vec.distance(toWorld(o.st.position, o.st.rotation, o.bc), point) - o.br >= radius) continue\n inRange.push(o)\n if (shelter) for (const p of o.parts) flags.set(p, (isLost(p) ? FLAG_LOST : 0) | (p.st.opening || p.st.stripped ? FLAG_OPEN : 0))\n }\n // what each blocker stands in front of, to aim its fragments\n const shields = new Map<PartRT, Vec3[]>()\n /** Share of the blast that gets to `tp` (world) through everything between it and the centre; `self` never blocks. */\n const reachAt = (tp: Vec3, self: PartRT | null): number => {\n if (!shelter) return 1\n const L = vec.distance(point, tp)\n if (L < 1e-4) return 1\n const d = vec.scale(vec.sub(tp, point), 1 / L)\n let t = 1\n for (const o of inRange) {\n if (raySphereMiss(point, d, toWorld(o.st.position, o.st.rotation, o.bc), o.br, L)) continue\n for (const p of o.parts) {\n if (p === self) continue\n const was = flags.get(p) ?? 0\n if (was & FLAG_LOST) continue\n const r = rayPart(o, p, point, d)\n if (!r) continue\n const t0 = Math.max(r.t0, 0)\n const path = Math.min(r.t1, L) - t0\n if (path < shelter.minPath) continue\n const mid = vec.madd(point, d, t0 + path / 2)\n const opening = p.st.opening && insideOpening(o, p, mid)\n if (opening && was & FLAG_OPEN) continue\n if (p.st.stripped && was & FLAG_OPEN) continue\n const resistance = p.mat.hpPerKg * p.mat.density * path * (p.mat.damageScale?.shelter ?? 1)\n let ti = Math.exp(-resistance / shelter.k)\n // destroyed or breached by this same blast: part of what it held back goes through\n if (isLost(p) || opening || (p.st.stripped && !(was & FLAG_OPEN))) ti += (1 - ti) * shelter.brokenTransmission\n t *= ti\n if (cfg.frag) {\n let list = shields.get(p)\n if (!list) shields.set(p, (list = []))\n list.push(tp)\n }\n }\n }\n return t\n }\n\n interface Item { dist: number; order: number; o?: ObjRT; p?: PartRT; im?: ImplRT }\n const items: Item[] = []\n let order = 0\n for (const o of inRange) {\n if (only && only !== o) continue\n for (const p of o.parts) {\n if (isLost(p)) continue\n const dist = distToPart(o, p, point)\n if (dist < radius) items.push({ dist, order: order++, o, p })\n }\n }\n for (const im of impls.values()) {\n if (only && only !== im) continue\n let dist = Infinity\n for (const { ps, c, q } of implParts(im)) dist = Math.min(dist, distanceToShape(ps.shape, toLocal(c, q, point)))\n if (dist < radius) items.push({ dist, order: order++, im })\n }\n items.sort((a, b) => a.dist - b.dist || a.order - b.order)\n\n const results = new Map<ObjRT | ImplRT, HitResult>()\n const reports = new Map<ObjRT | ImplRT, BlastReport>()\n const report = (key: ObjRT | ImplRT): BlastReport => {\n let r = reports.get(key)\n if (!r) reports.set(key, (r = { shelter: 0, confinement: mult, fragmentHits: 0 }))\n return r\n }\n const thrown: Array<{ frag: Fragment; object: string; part: PartRT | null }> = []\n const sweep = (from: number) => {\n if (!cfg.frag) return\n for (let i = from; i < cur.length; i++) {\n const e = cur[i]!\n if (e.type !== 'fracture' && e.type !== 'stage') continue\n for (const frag of e.fragments ?? []) thrown.push({ frag, object: e.object, part: objects.get(e.object)?.byId.get(e.part) ?? null })\n }\n }\n\n for (const it of items) {\n if (it.o && it.p) {\n const o = it.o\n let res = results.get(o)\n if (!res) results.set(o, (res = { object: o.id, damage: 0, penetrated: false, exitEnergy: 0, events: [] }))\n const start = cur.length\n const k = blastPart(o, it.p, point, E, radius, src, res, shelter ? reachAt : undefined)\n res.events.push(...cur.slice(start))\n sweep(start)\n if (k !== null) {\n const rep = report(o)\n rep.shelter = Math.max(rep.shelter, k)\n if (shelter) (rep.parts ??= {})[it.p.spec.id] = k\n }\n } else if (it.im) {\n const im = it.im\n // the impl takes one hit: the share of the blast that gets to its parts, weighted by how hard the blast hits each\n let num = 0\n let den = 0\n for (const { ps, c, q } of implParts(im)) {\n const lp = toLocal(c, q, point)\n const dist = distanceToShape(ps.shape, lp)\n if (dist >= radius) continue\n const f = (1 - dist / radius) ** 2\n const sp = surfacePoint(ps.shape, lp)\n num += f * reachAt(toWorld(c, q, sp.point), null)\n den += f\n }\n const k = den > 0 ? num / den : 1\n const res = implHit(im, { type: 'explosive', point, energy: E * k, radius, ...(shelter ? { shelter: k } : {}), ...(src !== undefined ? { source: src } : {}) })\n results.set(im, res)\n report(im).shelter = k\n }\n }\n\n if (cfg.frag && thrown.length > 0) {\n const g = cfg.frag\n const energyOf = (f: Fragment) => 0.5 * f.mass * (f.velocity[0] ** 2 + f.velocity[1] ** 2 + f.velocity[2] ** 2)\n const list = thrown\n .map((t, i) => ({ ...t, i, e: energyOf(t.frag) }))\n .sort((a, b) => b.e - a.e || a.i - b.i)\n .slice(0, Math.max(0, Math.floor(g.max)))\n list.forEach((t, i) => throwFragment(t.frag, t.object, t.part, g, point, i, src, shields, results, reports, mult))\n }\n\n const out: HitResult[] = []\n const reportShelter = (key: ObjRT | ImplRT, res: HitResult) => {\n res.blast = reports.get(key) ?? { shelter: 1, confinement: mult, fragmentHits: 0 }\n }\n const summary: Array<{ object: string; part?: string; factor: number }> = []\n let fragmentHits = 0\n for (const o of objects.values()) {\n const r = results.get(o)\n if (!r?.part) continue\n reportShelter(o, r)\n out.push(r)\n for (const [part, factor] of Object.entries(r.blast?.parts ?? {})) summary.push({ object: o.id, part, factor })\n fragmentHits += r.blast?.fragmentHits ?? 0\n }\n for (const im of impls.values()) {\n const r = results.get(im)\n if (!r) continue\n reportShelter(im, r)\n out.push(r)\n if (shelter) summary.push({ object: im.impl.id, factor: r.blast?.shelter ?? 1 })\n fragmentHits += r.blast?.fragmentHits ?? 0\n }\n emit({ type: 'blast', object: '', time, ...(src !== undefined ? { source: src } : {}), point, energy: E, radius, confinement: mult, shelter: summary, fragmentHits })\n return out\n }\n\n /** Integer seed from numbers: a fragment's flight depends only on the blast and on the fragment, not on what the world did before. */\n const seedOf = (...nums: number[]): number => {\n let h = 2166136261\n for (const n of nums) {\n h = Math.imul(h ^ (Math.round(n * 1000) | 0), 16777619)\n h ^= h >>> 15\n }\n return h | 0\n }\n\n /** One fragment of a part the blast broke flies on: a low-energy hit on the first part or impl it reaches within its throw. */\n const throwFragment = (\n frag: Fragment, objectId: string, from: PartRT | null, g: Required<FragmentHitOptions>, centre: Vec3, index: number, src: string | undefined,\n shields: Map<PartRT, Vec3[]>, results: Map<ObjRT | ImplRT, HitResult>, reports: Map<ObjRT | ImplRT, BlastReport>, mult: number,\n ) => {\n const v = frag.velocity\n const speed = Math.hypot(v[0], v[1], v[2])\n const energy = g.energyFactor * 0.5 * frag.mass * speed * speed\n if (speed < 0.5 || energy < 1) return\n const r = createRng(seedOf(options.seed ?? 1, centre[0], centre[1], centre[2], index, frag.center[0], frag.center[1], frag.center[2]))\n let dir = vec.scale(v, 1 / speed)\n // a fragment of a blocker whose flight points at a target behind it goes for that target\n const behind = from ? shields.get(from) : undefined\n if (behind) {\n let best = Math.cos((g.aim * Math.PI) / 180)\n for (const tp of behind) {\n const to = vec.sub(tp, frag.center)\n const len = vec.length(to)\n if (len < 1e-4) continue\n const cos = vec.dot(dir, to) / len\n if (cos >= best) {\n best = cos\n dir = vec.scale(to, 1 / len)\n }\n }\n }\n const spread = Math.tan((g.spread * Math.PI) / 180)\n dir = vec.normalize([dir[0] + (r.next() - 0.5) * 2 * spread, dir[1] + (r.next() - 0.5) * 2 * spread, dir[2] + (r.next() - 0.5) * 2 * spread], dir)\n const range = Math.min(g.range, speed * g.flightTime)\n const origin = vec.madd(frag.center, dir, 0.02)\n const rh = raycastInternal(origin, dir, range, from ? new Set([`${objectId}\\0${from.spec.id}`]) : undefined)\n if (!rh) return\n const hit: Hit = {\n type: g.hitType, point: rh.point, direction: dir, energy, radius: 0.05, part: rh.part,\n ...(g.hitType === 'ballistic' ? { caliber: clamp(Math.max(...frag.size) * 1000, 3, 30), mass: frag.mass * 1000 } : {}),\n ...(src !== undefined ? { source: src } : {}),\n }\n emit({ type: 'fragment_hit', object: objectId, time, ...(src !== undefined ? { source: src } : {}), from: { object: objectId, part: frag.part }, target: { object: rh.object, part: rh.part }, point: rh.point, direction: dir, energy, mass: frag.mass, speed })\n const im = impls.get(rh.object)\n const o = im ? undefined : objects.get(rh.object)\n const key = im ?? o\n if (!key) return\n const res = im ? implHit(im, hit) : doHit(o!, hit, o!.byId.get(rh.part))\n const have = results.get(key)\n if (have) {\n have.damage += res.damage\n have.events.push(...res.events)\n if (!have.part) have.part = res.part\n if (res.penetrated) have.penetrated = true\n } else results.set(key, { ...res, events: [...res.events] })\n let rep = reports.get(key)\n if (!rep) reports.set(key, (rep = { shelter: 1, confinement: mult, fragmentHits: 0 }))\n rep.fragmentHits++\n }\n\n const blastWorld = (point: Vec3, energy: number, radius: number, src?: string, call?: BlastOptions, only?: ObjRT | ImplRT): HitResult[] => {\n const cfg = blastCfg(call)\n if (!cfg.shelter && !cfg.frag && cfg.conf === null) return blastPlain(point, energy, radius, src)\n return blastScene(point, energy, radius, src, cfg, only)\n }\n\n const heatObject = (o: ObjRT, point: Vec3, T: number, radius: number, duration: number, src?: string): HitResult => {\n const start = cur.length\n const res: HitResult = { object: o.id, damage: 0, penetrated: false, exitEnergy: 0, events: [] }\n for (const p of o.parts) {\n if (isLost(p)) continue\n const dist = distToPart(o, p, point)\n if (dist >= radius) continue\n const f = clamp(1 - dist / radius, 0.25, 1)\n if (!res.part) {\n res.part = p.spec.id\n res.point = point\n }\n if (T > p.st.temperature) {\n const k = (0.8 * f) / (p.mat.thermal.heatCapacity ?? 1)\n p.st.temperature += (T - p.st.temperature) * (1 - Math.exp(-k * duration))\n }\n o.active = true\n checkIgnite(o, p, src)\n }\n res.events = cur.slice(start)\n return res\n }\n\n const doHit = (o: ObjRT, hit: Hit, only?: PartRT): HitResult => {\n let point = hit.point\n let dir = hit.direction\n if (hit.space === 'local') {\n point = toWorld(o.st.position, o.st.rotation, point)\n if (dir) dir = rotateVec(o.st.rotation, dir)\n }\n const src = hit.source\n const start = cur.length\n let res: HitResult = { object: o.id, damage: 0, penetrated: false, exitEnergy: 0, events: [] }\n const E = hit.energy ?? 0\n if (hit.type === 'ballistic') {\n const loc = locate(o, point, dir, 0.05, only)\n if (loc) {\n const out = ballistic(o, loc.p, loc.point, loc.normal, loc.dir, E, hit.caliber ?? 9, loc.pathLen, src, hit.piercing ?? 1)\n res = { ...res, part: loc.p.spec.id, point: loc.point, damage: out.damage, penetrated: out.penetrated, exitEnergy: out.exitEnergy }\n }\n } else if (hit.type === 'blunt' || hit.type === 'slash') {\n const radius = hit.radius ?? 0\n const loc = locate(o, point, dir, Math.max(0.05, radius), only)\n if (loc) {\n res.part = loc.p.spec.id\n res.point = loc.point\n res.damage += melee(o, loc.p, hit.type, E, loc.point, loc.normal, loc.dir, radius || 0.03, src)\n if (radius > 0.1 && !only) {\n for (const p of o.parts) {\n if (p === loc.p || isLost(p)) continue\n const dd = distToPart(o, p, point)\n if (dd >= radius) continue\n const { c, q } = partXf(o, p)\n const sp = surfacePoint(p.spec.shape, toLocal(c, q, point))\n res.damage += melee(o, p, hit.type, E * (1 - dd / radius) ** 2, toWorld(c, q, sp.point), rotateVec(q, sp.normal), loc.dir, radius, src)\n }\n }\n }\n } else if (hit.type === 'explosive') {\n const call = hit.blast || hit.confinement !== undefined ? { ...hit.blast, ...(hit.confinement !== undefined ? { confinement: hit.confinement } : {}) } : undefined\n const cfg = blastCfg(call)\n if (!cfg.shelter && !cfg.frag && cfg.conf === null) res = blastObject(o, point, E, hit.radius ?? 2, src)\n else {\n res = blastWorld(point, E, hit.radius ?? 2, src, call, o)[0] ?? res\n res.events = cur.slice(start)\n }\n } else {\n res = heatObject(o, point, hit.temperature ?? 800, hit.radius ?? 0.25, hit.duration ?? 1, src)\n }\n res.events = cur.slice(start)\n return res\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Fire, heat, melting, leaks\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n const checkIgnite = (o: ObjRT, p: PartRT, src?: string) => {\n const th = p.mat.thermal\n if (isLost(p) || p.st.burning || th.ignitionC === undefined || p.st.fuel <= 0 || p.st.temperature < th.ignitionC) return\n p.st.burning = true\n p.st.temperature = Math.max(p.st.temperature, th.flameC ?? 800)\n o.active = true\n markDamaged(p)\n emit({ ...base(o, src), type: 'ignite', part: p.spec.id, point: partXf(o, p).c })\n }\n\n const syncMass = (p: PartRT) => {\n p.st.mass = Math.max(0, p.mass0 * (1 - p.st.melt) - (p.fuel0 - p.st.fuel))\n }\n\n const burnStep = (o: ObjRT, p: PartRT, dt: number) => {\n const th = p.mat.thermal\n const use = Math.min((th.burnRate ?? 0.01) * p.area * dt, p.st.fuel)\n p.st.fuel -= use\n syncMass(p)\n if (p.structural) o.dirty = true\n p.st.temperature = th.flameC ?? 800\n markDamaged(p)\n if (p.fuel0 > 0) {\n p.st.char = clamp(1 - p.st.fuel / p.fuel0, 0, 1)\n p.st.hp = Math.min(p.st.hp, Math.max(1, p.st.maxHp * (p.st.fuel / p.fuel0)))\n }\n if (p.st.fuel <= 1e-9) {\n p.st.fuel = 0\n p.st.burning = false\n p.st.char = 1\n const c = partXf(o, p).c\n if ((th.fuelFraction ?? 0) >= 0.8) {\n p.st.status = 'ashes'\n p.st.hp = 0\n p.st.mass = p.mass0 * (1 - (th.fuelFraction ?? 0))\n emit({ ...base(o), type: 'burnout', part: p.spec.id, point: c })\n debris(o, p, 'ash', c, [0, 1, 0], clamp(Math.round(Math.cbrt(partVolume(p.spec.shape)) * 30), 3, 20), 1)\n partLost(o, p)\n } else {\n emit({ ...base(o), type: 'burnout', part: p.spec.id, point: c })\n }\n }\n }\n\n const meltStep = (o: ObjRT, p: PartRT, dt: number) => {\n const th = p.mat.thermal\n if (th.meltC === undefined || p.st.temperature <= th.meltC) return\n const rate = (th.meltRate ?? 0.05) * ((p.st.temperature - th.meltC) / 100)\n p.st.melt = Math.min(1, p.st.melt + rate * dt)\n syncMass(p)\n if (p.structural) o.dirty = true\n markDamaged(p)\n p.rt.dripT += dt\n if (p.rt.dripT >= 0.25) {\n p.rt.dripT -= 0.25\n const b = partWorldAabb(o, p)\n const pt: Vec3 = [b.min[0] + (b.max[0] - b.min[0]) * (0.2 + 0.6 * rnd()), b.min[1], b.min[2] + (b.max[2] - b.min[2]) * (0.2 + 0.6 * rnd())]\n emit({ ...base(o), type: 'drip', part: p.spec.id, point: pt, material: p.mat.id })\n }\n if (p.st.melt - p.rt.meltEmitted >= 0.05 || p.st.melt >= 1) {\n p.rt.meltEmitted = p.st.melt\n emit({ ...base(o), type: 'melt', part: p.spec.id, melt: p.st.melt })\n }\n if (p.st.melt >= 1) {\n p.st.status = 'melted'\n p.st.hp = 0\n p.st.mass = 0\n p.st.burning = false\n p.rt.jet = false\n partLost(o, p)\n }\n }\n\n const stepObject = (o: ObjRT, dt: number, sources: Array<{ o: ObjRT; p: PartRT; flame: number }>) => {\n const parts = o.parts\n const T0 = o.tmp\n T0.length = parts.length\n for (let i = 0; i < parts.length; i++) T0[i] = parts[i].st.temperature\n let hot = false\n for (let i = 0; i < parts.length; i++) {\n const p = parts[i]\n if (isLost(p)) continue\n const th = p.mat.thermal\n const hc = th.heatCapacity ?? 1\n const s = p.st\n if (p.rt.jet) {\n s.temperature = Math.max(s.temperature, 900)\n } else if (s.burning) {\n burnStep(o, p, dt)\n if (isLost(p)) continue\n }\n if (!s.burning && !p.rt.jet) {\n // conduction from hotter neighbours through closed joints, then cooling\n let dT = 0\n let maxN = s.temperature\n for (const j of o.byPart.get(p.spec.id)!) {\n if (j.st.open) continue\n const k = j.ia === i ? j.ib : j.ia\n if (isLost(parts[k]) || T0[k] <= T0[i]) continue\n const c = (th.conductivity + parts[k].mat.thermal.conductivity) / 2\n dT += (T0[k] - T0[i]) * (1 - Math.exp((-1.2 * c * dt) / hc))\n if (T0[k] > maxN) maxN = T0[k]\n }\n if (dT > 0) s.temperature = Math.min(s.temperature + dT, maxN)\n s.temperature += (ambient - s.temperature) * (1 - Math.exp(-dt / (20 * hc)))\n if (Math.abs(s.temperature - ambient) < 0.05) s.temperature = ambient\n }\n meltStep(o, p, dt)\n if (isLost(p)) continue\n checkIgnite(o, p)\n const ex = p.spec.explodes\n if (ex && chainDelayOf(p.spec, 'fire') !== undefined) {\n if (s.temperature >= (ex.atC ?? FIRE_PRIME_C)) prime(o, p, 'fire')\n } else if (ex && ex.atC !== undefined && s.temperature >= ex.atC) {\n failPart(o, p, null, null, 0, 40)\n continue\n }\n // leaks\n const cont = p.spec.contains\n if (cont && (s.liters ?? 0) > 0) {\n let rate = 0\n for (const h of s.holes) if (h.through) rate += holeRate(h, !!cont.pressurized)\n if (rate > 0) {\n s.liters = Math.max(0, (s.liters ?? 0) - rate * dt)\n hot = true\n if (FLAMMABLE_FLUIDS.includes(cont.fluid) && s.temperature >= 350 && !p.rt.jet) {\n if (ex && chainDelayOf(p.spec, 'fire') !== undefined) {\n prime(o, p, 'fire')\n continue\n }\n if (ex) {\n failPart(o, p, null, null, 0, 40)\n continue\n }\n p.rt.jet = true\n s.burning = true\n emit({ ...base(o), type: 'ignite', part: p.spec.id, point: partXf(o, p).c })\n }\n }\n }\n if (p.rt.jet && (s.liters ?? 0) <= 0) {\n p.rt.jet = false\n s.burning = false\n emit({ ...base(o), type: 'extinguish', part: p.spec.id })\n }\n // thermal shock\n const sc = th.thermalShockC\n if (sc !== undefined) {\n p.rt.shockT = Math.max(0, p.rt.shockT - dt)\n const rate = Math.abs(s.temperature - p.rt.prevTemp) / dt\n p.rt.prevTemp = s.temperature\n if (rate > sc && p.rt.shockT <= 0) {\n p.rt.shockT = 1\n const { c, q } = partXf(o, p)\n const lp: Vec3 = [(rnd() - 0.5) * p.dims[0], (rnd() - 0.5) * p.dims[1], (rnd() - 0.5) * p.dims[2]]\n const sp = surfacePoint(p.spec.shape, lp)\n addCrack(o, p, toWorld(c, q, sp.point), rotateVec(q, sp.normal), 0.1 + (rate / sc) * 0.1)\n applyDamage(o, p, p.st.maxHp * 0.25, 'heat', null, null, 5, 3)\n if (isLost(p)) continue\n }\n }\n if (s.burning || p.rt.jet) sources.push({ o, p, flame: p.rt.jet ? 900 : th.flameC ?? 800 })\n if (s.burning || p.rt.jet || s.temperature > ambient + 0.5) hot = true\n }\n if (o.hasStructure) {\n if (o.dirty) {\n o.dirty = false\n solveStructure(o)\n }\n for (const p of parts) {\n if (!p.structural || isLost(p)) continue\n const stress = p.st.stress ?? 0\n p.rt.stressT = Math.max(0, (p.rt.stressT ?? 0) - dt)\n if (stress > 1) {\n if (p.rt.stressT <= 0) {\n p.rt.stressT = 0.5\n emit({ ...base(o), type: 'stress', part: p.spec.id, stress, load: p.st.load ?? 0 })\n }\n applyDamage(o, p, overloadRate(stress) * p.st.maxHp * dt, 'blunt', null, null, 5, 3)\n } else if (stress > 0.8 && p.mat.ductility < 0.3 && p.rt.stressT <= 0 && p.st.cracks.length < 6) {\n p.rt.stressT = 0.5\n const { c, q } = partXf(o, p)\n const sp = surfacePoint(p.spec.shape, [(rnd() - 0.5) * p.dims[0], (rnd() - 0.5) * p.dims[1], (rnd() - 0.5) * p.dims[2]])\n addCrack(o, p, toWorld(c, q, sp.point), rotateVec(q, sp.normal), 0.1 + (stress - 0.8) * 0.5)\n }\n }\n if (o.maxStress > 0.8) hot = true\n }\n o.active = hot\n }\n\n const spread = (sources: Array<{ o: ObjRT; p: PartRT; flame: number }>, dt: number) => {\n for (const src of sources) {\n if (!src.p.st.burning && !src.p.rt.jet) continue\n const sc = toWorld(src.o.st.position, src.o.st.rotation, src.p.pos)\n const A = partWorldAabb(src.o, src.p)\n for (const o of objects.values()) {\n if (o === src.o) continue\n if (vec.distance(toWorld(o.st.position, o.st.rotation, o.bc), sc) > o.br + src.p.bound + fireSpread) continue\n for (const q of o.parts) {\n if (isLost(q) || q.st.burning) continue\n const B = partWorldAabb(o, q)\n const gap = Math.hypot(\n Math.max(0, A.min[0] - B.max[0], B.min[0] - A.max[0]),\n Math.max(0, A.min[1] - B.max[1], B.min[1] - A.max[1]),\n Math.max(0, A.min[2] - B.max[2], B.min[2] - A.max[2]),\n )\n if (gap >= fireSpread || src.flame <= q.st.temperature) continue\n const f = 1 - gap / fireSpread\n q.st.temperature += (src.flame - q.st.temperature) * (1 - Math.exp((-0.6 * f * dt) / (q.mat.thermal.heatCapacity ?? 1)))\n o.active = true\n }\n }\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // World API\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n /** The primed part that goes off first: earliest due time, then the older object, then the part listed first. */\n const nextPrimed = (until: number): { o: ObjRT; p: PartRT } | null => {\n let best: { o: ObjRT; p: PartRT } | null = null\n for (const [p, o] of primed) {\n if (objects.get(o.id) !== o || isLost(p)) {\n primed.delete(p)\n continue\n }\n const due = p.rt.chainDue as number\n if (due > until) continue\n if (!best) best = { o, p }\n else {\n const bestDue = best.p.rt.chainDue as number\n if (due < bestDue || (due === bestDue && (o.order < best.o.order || (o.order === best.o.order && (o.idx.get(p.spec.id) ?? 0) < (best.o.idx.get(best.p.spec.id) ?? 0))))) best = { o, p }\n }\n }\n return best\n }\n\n /**\n * Explodes the primed parts whose delay ran out by `until`, one at a time in order of time; each blast is resolved before the next part goes off,\n * so a part it primes counts its delay from that moment, not from the end of the frame.\n */\n const detonatePrimed = (until: number) => {\n const end = time\n for (let next = nextPrimed(until); next; next = nextPrimed(until)) {\n primed.delete(next.p)\n time = Math.max(0, Math.min(end, next.p.rt.chainDue as number))\n next.p.rt.chainDue = undefined\n failPart(next.o, next.p, null, null, 0, 40)\n drainBlasts()\n }\n time = end\n }\n\n /** Lands the damage of the glass the blast front has reached by `time`, the nearest first. */\n const releaseFront = () => {\n if (frontQueue.length === 0) return\n frontQueue.sort((a, b) => a.due - b.due)\n while (frontQueue.length > 0 && frontQueue[0]!.due <= time) {\n const hit = frontQueue.shift()!\n if (objects.get(hit.o.id) !== hit.o) continue\n applyDamage(hit.o, hit.p, hit.amount, 'explosive', hit.point, null, hit.fragEnergy, 40, hit.src)\n }\n }\n\n /** Collapse events are produced after the whole operation: make sure the result of the operation carries them. */\n const withCollapses = (r: { value: HitResult[]; events: DestructionEvent[] }): HitResult[] => {\n const last = r.value[r.value.length - 1]\n if (!last) return r.value\n for (const e of r.events) if (e.type === 'collapse' && !r.value.some((h) => h.events.includes(e))) last.events.push(e)\n return r.value\n }\n\n /** An explosive hit on an impl: a blast of its own when blast options are on, else the plain hit. */\n const blastImpl = (im: ImplRT, h: Hit): HitResult => {\n const call = h.blast || h.confinement !== undefined ? { ...h.blast, ...(h.confinement !== undefined ? { confinement: h.confinement } : {}) } : undefined\n const cfg = blastCfg(call)\n if (!cfg.shelter && !cfg.frag && cfg.conf === null) return implHit(im, h)\n const world = h.space === 'local' ? toWorld(im.position, im.rotation, h.point) : h.point\n const r = blastWorld(world, h.energy ?? 0, h.radius ?? 2, h.source, call, im)\n return r.find((x) => x.object === im.impl.id) ?? implHit(im, h)\n }\n\n const whole = (fn: () => HitResult): HitResult => {\n const r = run(fn)\n r.value.events = r.events\n return r.value\n }\n\n const world: DestructionWorld = {\n materials,\n get time() {\n return time\n },\n add(spec, opts: AddOptions = {}) {\n const id = opts.id ?? nextId()\n if (taken(id)) throw new Error(`object \"${id}\" already exists`)\n objects.set(id, build(resolveSpec(spec), id, opts.position ?? [0, 0, 0], opts.rotation ?? [0, 0, 0, 1]))\n return id\n },\n register(impl, opts: AddOptions = {}) {\n const id = opts.id ?? impl.id\n if (taken(id)) throw new Error(`object \"${id}\" already exists`)\n impls.set(id, { impl, position: opts.position ?? [0, 0, 0], rotation: opts.rotation ?? [0, 0, 0, 1], poses: new Map() })\n return id\n },\n setPartPose(objectId, partId, position, rotation) {\n const q = quatFromEuler(...(rotation ?? [0, 0, 0]))\n const im = impls.get(objectId)\n if (im) {\n im.impl.setPartPose?.(partId, position, rotation)\n im.poses.set(partId, { pos: [position[0], position[1], position[2]], q })\n return\n }\n const o = getObj(objectId)\n const p = getPart(o, partId)\n p.pos = [position[0], position[1], position[2]]\n p.q = q\n updateBound(o)\n },\n remove(id) {\n objects.delete(id)\n impls.delete(id)\n },\n has: (id) => taken(id),\n ids: () => [...objects.keys(), ...impls.keys()],\n setTransform(id, position, rotation) {\n const im = impls.get(id)\n if (im) {\n im.position = [position[0], position[1], position[2]]\n im.rotation = [rotation[0], rotation[1], rotation[2], rotation[3]]\n return\n }\n const o = getObj(id)\n o.st.position = [position[0], position[1], position[2]]\n o.st.rotation = [rotation[0], rotation[1], rotation[2], rotation[3]]\n },\n splitGroup(id, group, newId) {\n if (impls.has(id)) throw new Error(`object \"${id}\" is a registered DestructibleImpl and cannot be split; its module owns its pieces`)\n const o = getObj(id)\n if (o.st.groups.length < 2) return id\n const names = o.st.groups[group]\n if (!names) throw new Error(`object \"${id}\" has no group ${group}`)\n const moved = new Set(names)\n const nid = newId ?? nextId()\n if (objects.has(nid)) throw new Error(`object \"${nid}\" already exists`)\n // an open joint between the two objects stays with the original\n const carryFor = (keep: (pid: string) => boolean, keepOpen: (a: string, b: string) => boolean = () => false): Carry => ({\n parts: new Map(o.parts.filter((p) => keep(p.spec.id)).map((p) => [p.spec.id, { st: p.st, rt: p.rt }])),\n joints: new Map([\n ...o.joints.filter((j) => (keep(j.spec.a) && keep(j.spec.b)) || (j.st.open && keepOpen(j.spec.a, j.spec.b))).map((j): [string, { st: JointState; step: number }] => [j.spec.id, { st: j.st, step: j.step }]),\n ...o.st.joints.filter((st) => st.open && !o.jointMap.has(st.id) && keepOpen(st.a, st.b)).map((st): [string, { st: JointState; step: number }] => [st.id, { st, step: 0 }]),\n ]),\n collapsed: [...o.collapsed].filter(keep),\n })\n const sub = (keep: (pid: string) => boolean): DestructibleSpec => {\n const s: DestructibleSpec = { parts: o.spec.parts.filter((p) => keep(p.id)), joints: (o.spec.joints ?? []).filter((j) => keep(j.a) && keep(j.b)) }\n if (o.spec.name !== undefined) s.name = o.spec.name\n if (o.spec.tags) s.tags = [...o.spec.tags]\n return clone(s)\n }\n const inNew = (pid: string) => moved.has(pid)\n const inOld = (pid: string) => !moved.has(pid)\n const pos = o.st.position, rot = o.st.rotation\n const fresh = build(sub(inNew), nid, pos, rot, carryFor(inNew, (a, b) => inNew(a) && inNew(b)))\n const rest = build(sub(inOld), id, pos, rot, carryFor(inOld, (a, b) => !(inNew(a) && inNew(b))))\n objects.set(id, rest)\n objects.set(nid, fresh)\n return nid\n },\n hit(objectId, h) {\n const im = impls.get(objectId)\n if (im) return whole(() => (h.type === 'explosive' ? blastImpl(im, h) : implHit(im, h)))\n const o = getObj(objectId)\n return whole(() => doHit(o, h))\n },\n hitPart(objectId, partId, h) {\n const im = impls.get(objectId)\n if (im) return whole(() => implHit(im, h))\n const o = getObj(objectId)\n const p = getPart(o, partId)\n return whole(() => doHit(o, h, p))\n },\n explode(point, energy, radius, source, blast) {\n return withCollapses(run(() => blastWorld(point, energy, radius, source, blast)))\n },\n raycast(origin, direction, maxDistance = Infinity) {\n const r = raycastInternal(origin, direction, maxDistance)\n return r ? { object: r.object, part: r.part, point: r.point, normal: r.normal, distance: r.distance } : null\n },\n shoot(origin, direction, energy, caliber, source, piercing) {\n return withCollapses(run(() => {\n const results: HitResult[] = []\n const d = vec.normalize(direction)\n const ignore = new Set<string>()\n let org = origin\n let E = energy\n for (let i = 0; i < 4 && E > 0; i++) {\n const rh = raycastInternal(org, d, Infinity, ignore)\n if (!rh) break\n const im = impls.get(rh.object)\n if (im) {\n const r = implHit(im, { type: 'ballistic', point: rh.point, direction: d, energy: E, caliber, ...(piercing !== undefined ? { piercing } : {}), ...(source !== undefined ? { source } : {}) })\n r.part = rh.part\n r.point = rh.point\n r.exitEnergy = r.penetrated ? E * 0.5 : 0\n results.push(r)\n ignore.add(`${im.impl.id}\\0${rh.part}`)\n if (!r.penetrated) break\n org = vec.madd(rh.point, d, Math.min(rh.pathLen, 0.05) + 0.001)\n E = r.exitEnergy\n continue\n }\n const o = getObj(rh.object)\n const p = getPart(o, rh.part)\n const start = cur.length\n const out = ballistic(o, p, rh.point, rh.normal, d, E, caliber, rh.pathLen, source, piercing ?? 1)\n results.push({ object: o.id, part: p.spec.id, point: rh.point, damage: out.damage, penetrated: out.penetrated, exitEnergy: out.exitEnergy, events: cur.slice(start) })\n ignore.add(`${o.id}\\0${p.spec.id}`)\n if (!out.penetrated || !out.exitPoint) break\n org = vec.madd(out.exitPoint, d, 0.001)\n E = out.exitEnergy\n }\n return results\n }))\n },\n disassemble(objectId, jointId, tool: ToolKind, dt) {\n const im = impls.get(objectId)\n if (im) return im.impl.disassemble ? im.impl.disassemble(jointId, tool, dt) : -1\n const o = getObj(objectId)\n const j = o.jointMap.get(jointId)\n if (!j || !j.spec.tools.includes(tool)) return -1\n if (j.st.open) return 1\n return run(() => {\n j.st.progress = Math.min(1, j.st.progress + (j.spec.seconds > 0 ? dt / j.spec.seconds : 1))\n if (j.st.progress >= 1 - 1e-9) j.st.progress = 1\n const step = Math.floor(j.st.progress * 10 + 1e-9)\n if (step > j.step || j.st.progress >= 1) {\n j.step = step\n emit({ ...base(o), type: 'disassemble_progress', joint: j.spec.id, tool, progress: j.st.progress })\n }\n if (j.st.progress >= 1) {\n j.st.open = true\n j.st.openedBy = 'tool'\n solveStructure(o)\n recomputeGroups(o)\n detachEvents(o, [j], 'tool')\n collapseCheck(o)\n }\n return j.st.progress\n }).value\n },\n workableJoints(objectId, tool) {\n const im = impls.get(objectId)\n if (im) {\n const spec = im.impl.describe()\n return im.impl.state().joints.filter((js) => {\n const j = (spec.joints ?? []).find((x) => (x.id ?? `${x.a}~${x.b}`) === js.id)\n return !js.open && !!j && (j.tools ?? JOINT_DEFAULTS[j.kind].tools).includes(tool)\n })\n }\n return getObj(objectId).joints.filter((j) => !j.st.open && j.spec.tools.includes(tool)).map((j) => j.st)\n },\n nearestJoint(objectId, point, maxDistance = 0.3, tool) {\n const im = impls.get(objectId)\n // Candidates: closed joints with their world position and whether `tool` can undo them.\n const cands: { st: JointState; d: number; ok: boolean }[] = []\n if (im) {\n const spec = im.impl.describe()\n for (const js of im.impl.state().joints) {\n if (js.open) continue\n const pos = implJointPos(im, js.a, js.b)\n const j = (spec.joints ?? []).find((x) => (x.id ?? `${x.a}~${x.b}`) === js.id)\n cands.push({ st: js, d: pos ? vec.distance(pos, point) : Infinity, ok: !!j && (j.tools ?? JOINT_DEFAULTS[j.kind].tools).includes(tool as ToolKind) })\n }\n } else {\n const o = getObj(objectId)\n for (const j of o.joints) {\n if (j.st.open) continue\n cands.push({ st: j.st, d: vec.distance(jointWorld(o, j), point), ok: tool ? j.spec.tools.includes(tool) : true })\n }\n }\n const pick = (only: boolean): JointState | null => {\n let best: JointState | null = null\n let bd = maxDistance\n for (const c of cands) {\n if (only && !c.ok) continue\n if (c.d <= bd) {\n bd = c.d\n best = c.st\n }\n }\n return best\n }\n return (tool ? pick(true) : null) ?? pick(false)\n },\n extinguish(objectId, partId, coolC = 200) {\n const im = impls.get(objectId)\n if (im) {\n run(() => im.impl.extinguish?.(partId))\n return\n }\n const o = getObj(objectId)\n run(() => {\n for (const p of partId ? [getPart(o, partId)] : o.parts) {\n if (isLost(p)) continue\n if (p.st.burning) {\n p.st.burning = false\n p.rt.jet = false\n emit({ ...base(o), type: 'extinguish', part: p.spec.id })\n }\n p.st.temperature = Math.max(ambient, p.st.temperature - coolC)\n }\n o.active = true\n })\n },\n setLiters(objectId, partId, liters) {\n if (impls.has(objectId)) return\n const p = getPart(getObj(objectId), partId)\n if (!p.spec.contains) return\n p.st.liters = clamp(liters, 0, p.spec.contains.liters)\n getObj(objectId).active = true\n },\n update(dt) {\n if (!(dt > 0)) return []\n return run(() => {\n time += dt\n const sources: Array<{ o: ObjRT; p: PartRT; flame: number }> = []\n for (const o of [...objects.values()]) if (o.active) stepObject(o, dt, sources)\n if (sources.length) spread(sources, dt)\n detonatePrimed(time)\n releaseFront()\n for (const im of [...impls.values()]) {\n if (!im.impl.update) continue\n for (const e of im.impl.update(dt) ?? []) emit(e.time === undefined ? { ...e, time } : e)\n }\n }).events\n },\n state: (id) => objects.get(id)?.st ?? impls.get(id)?.impl.state() ?? null,\n snapshot: (id) => {\n const st = objects.get(id)?.st ?? impls.get(id)?.impl.state()\n return st ? clone(st) : null\n },\n part: (id, partId) => objects.get(id)?.byId.get(partId)?.st ?? impls.get(id)?.impl.state().parts.find((p) => p.id === partId) ?? null,\n reset(id) {\n const im = impls.get(id)\n if (im) {\n im.impl.reset?.()\n return\n }\n const o = getObj(id)\n objects.set(id, build(o.spec, id, o.st.position, o.st.rotation))\n },\n on(type: DestructionEventType | '*', fn) {\n let set = listeners.get(type)\n if (!set) listeners.set(type, (set = new Set()))\n set.add(fn)\n return () => {\n set!.delete(fn)\n }\n },\n serialize(): DestructionSnapshot {\n return {\n version: 1,\n time,\n rng: rng.state(),\n counter,\n objects: [...objects.values()].map((o) => {\n const runtime: ObjectRuntime = { parts: {}, joints: {}, collapsed: [...o.collapsed] }\n for (const p of o.parts) runtime.parts[p.spec.id] = clone(p.rt)\n for (const j of o.joints) runtime.joints[j.spec.id] = j.step\n return { id: o.id, spec: clone(o.spec), state: clone(o.st), runtime }\n }),\n ...(impls.size\n ? { impls: [...impls.values()].map((im) => ({ id: im.impl.id, position: [...im.position] as Vec3, rotation: [...im.rotation] as Quat, data: im.impl.serialize?.() })) }\n : {}),\n }\n },\n load(snap) {\n if (snap.version !== 1) throw new Error(`unsupported snapshot version ${String(snap.version)}`)\n objects.clear()\n time = snap.time\n rng.set(snap.rng)\n counter = snap.counter ?? 0\n for (const e of snap.objects) {\n const state = clone(e.state)\n const carry: Carry = {\n parts: new Map(\n state.parts.map((st) => [st.id, { st, rt: e.runtime?.parts[st.id] ? clone(e.runtime.parts[st.id]) : { ...freshRuntime(), prevTemp: st.temperature } }]),\n ),\n joints: new Map(state.joints.map((st) => [st.id, { st, step: e.runtime?.joints[st.id] ?? 0 }])),\n collapsed: e.runtime?.collapsed,\n }\n objects.set(e.id, build(clone(e.spec), e.id, state.position, state.rotation, carry))\n }\n for (const e of snap.impls ?? []) {\n const im = impls.get(e.id)\n if (!im) continue\n im.position = [e.position[0], e.position[1], e.position[2]]\n im.rotation = [e.rotation[0], e.rotation[1], e.rotation[2], e.rotation[3]]\n if (e.data !== undefined) im.impl.load?.(e.data)\n }\n },\n }\n return world\n}\n","/**\n * How well a bullet cuts through for its energy (`Hit.piercing`, the 6th argument of `shoot`). The material's `penetration` is joules per\n * millimetre for a hard bullet; soft lead deforms on steel and concrete and a core of hardened steel does better. A host that knows the kind\n * of the bullet (`CaliberDef.kind` of `@adatechnology/game-weapons`) takes the number from here, or replaces the tables with its own.\n *\n * Reference: a 12 ga slug (3000 J) does not go through 8 mm of mild steel, a .50 BMG (18000 J) goes through 20 mm and more.\n */\nexport const PIERCING_BY_KIND: Readonly<Record<string, number>> = {\n fmj: 1, hp: 0.6, ap: 1.6, buck: 0.5, slug: 0.25, birdshot: 0.3, rimfire: 1, arrow: 1, bolt: 1,\n}\n\n/** Caliber ids whose bullet is lighter on the target than its kind says (a soft-core 5.56 ball does not go through a steel flange). */\nexport const PIERCING_BY_CALIBER: Readonly<Record<string, number>> = { '5_56x45': 0.5, '5_45x39': 0.5, '22lr': 0.5 }\n\nexport const piercingOf = (caliber: string, kind?: string): number => PIERCING_BY_CALIBER[caliber] ?? PIERCING_BY_KIND[kind ?? 'fmj'] ?? 1\n","[\n {\n \"id\": \"brick_wall_plastered\",\n \"name\": \"Plastered brick wall\",\n \"core\": { \"material\": \"brick\", \"thickness\": 0.09 },\n \"layers\": [{ \"material\": \"plaster\", \"thickness\": 0.02, \"faces\": \"both\" }],\n \"units\": { \"size\": [0.23, 0.075, 0.11], \"bond\": \"running\", \"mortar\": \"plaster\" },\n \"breach\": { \"area\": 0.25 }\n },\n {\n \"id\": \"concrete_block_wall\",\n \"name\": \"Concrete block wall\",\n \"core\": { \"material\": \"concrete\", \"thickness\": 0.14 },\n \"fill\": 0.55,\n \"units\": { \"size\": [0.39, 0.19, 0.14], \"bond\": \"running\", \"mortar\": \"plaster\" },\n \"breach\": { \"area\": 0.25 }\n },\n {\n \"id\": \"reinforced_concrete\",\n \"name\": \"Reinforced concrete wall\",\n \"core\": { \"material\": \"concrete\", \"thickness\": 0.2 },\n \"reinforcement\": { \"material\": \"steel\", \"spacing\": 0.18, \"diameter\": 0.008, \"residualCapacity\": 0.15 },\n \"units\": { \"size\": [0.6, 0.42, 0.2], \"bond\": \"stack\", \"mortar\": \"concrete\" },\n \"breach\": { \"area\": 0.25 }\n },\n {\n \"id\": \"drywall\",\n \"name\": \"Drywall partition on steel studs\",\n \"core\": { \"material\": \"plaster\", \"thickness\": 0.0125 },\n \"layers\": [{ \"material\": \"plaster\", \"thickness\": 0.0125, \"faces\": \"+\" }],\n \"depth\": 0.095,\n \"breach\": { \"area\": 0.25 }\n },\n {\n \"id\": \"wood_frame_wall\",\n \"name\": \"Wood frame wall\",\n \"core\": { \"material\": \"plywood\", \"thickness\": 0.012 },\n \"layers\": [{ \"material\": \"plaster\", \"thickness\": 0.0125, \"faces\": \"-\" }],\n \"depth\": 0.1135,\n \"breach\": { \"area\": 0.25 }\n },\n {\n \"id\": \"log_wall\",\n \"name\": \"Log wall\",\n \"core\": { \"material\": \"wood_soft\", \"thickness\": 0.2 },\n \"fill\": 0.785,\n \"breach\": { \"area\": 0.25 }\n },\n {\n \"id\": \"sheet_metal_shack\",\n \"name\": \"Corrugated sheet metal wall\",\n \"core\": { \"material\": \"steel\", \"thickness\": 0.0006 },\n \"depth\": 0.02,\n \"breach\": { \"area\": 0.25 }\n },\n {\n \"id\": \"glass_pane\",\n \"name\": \"Glass pane\",\n \"core\": { \"material\": \"glass\", \"thickness\": 0.006 },\n \"breach\": { \"area\": 0.1 }\n }\n]\n","import assembliesJson from './data/assemblies.json'\nimport { MATERIALS } from './materials'\nimport type { MaterialDef, MaterialId, PartBreach, PartSpec, PartUnits, Reinforcement, SurfaceLayer, Vec3 } from './types'\n\n/**\n * 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\n * `src/data/assemblies.json`); `assemblyPart` turns one into a `PartSpec`. Extend or override with `registerAssembly`.\n */\nexport interface AssemblyDef {\n id: string\n name: string\n /** `thickness` is the core's, in metres: what a bullet has to get through besides the coats. */\n core: { material: MaterialId; thickness: number }\n /** Coats, outermost first. */\n layers?: readonly SurfaceLayer[]\n /** Physical depth of the wall when it is not core plus coats (a drywall partition is mostly air between the boards). */\n depth?: number\n /** Solid fraction of the core (hollow blocks, round logs): scales its mass and the thickness a bullet crosses. Default 1. */\n fill?: number\n units?: PartUnits\n reinforcement?: Reinforcement\n breach?: PartBreach\n}\n\nexport interface AssemblyPartOptions {\n id: string\n /** Along the part's x axis. */\n width: number\n /** Along the part's y axis. */\n height: number\n position: Vec3\n rotation?: Vec3\n structure?: PartSpec['structure']\n /** Other `PartSpec` fields (tags, anchored, hp...). */\n extra?: Partial<PartSpec>\n /** Materials to read densities from (default the built-in `MATERIALS`). */\n materials?: ReadonlyMap<MaterialId, MaterialDef>\n}\n\n/** Built-in assemblies; `registerAssembly` adds to this list. */\nexport const ASSEMBLIES: AssemblyDef[] = assembliesJson as unknown as AssemblyDef[]\n\nexport const registerAssembly = (def: AssemblyDef): void => {\n const at = ASSEMBLIES.findIndex((a) => a.id === def.id)\n if (at >= 0) ASSEMBLIES[at] = def\n else ASSEMBLIES.push(def)\n}\n\nexport const getAssembly = (id: string): AssemblyDef | undefined => ASSEMBLIES.find((a) => a.id === id)\n\nconst faceCount = (layer: SurfaceLayer): number => (layer.faces === 'both' ? 2 : 1)\n\n/** Physical depth of the wall in metres. */\nexport const assemblyDepth = (def: AssemblyDef): number => def.depth ?? def.core.thickness + (def.layers ?? []).reduce((sum, l) => sum + l.thickness * faceCount(l), 0)\n\n/**\n * 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`)\n * plus the coats; `thickness` is the core's, so each coat adds its own `penetration x thickness` to what a bullet must cross.\n */\nexport const assemblyPart = (assemblyId: string, options: AssemblyPartOptions): PartSpec => {\n const def = getAssembly(assemblyId)\n if (!def) throw new Error(`unknown assembly \"${assemblyId}\"`)\n const densityOf = (id: MaterialId): number => {\n const m = options.materials?.get(id) ?? MATERIALS.find((x) => x.id === id)\n if (!m) throw new Error(`unknown material \"${id}\" in assembly \"${assemblyId}\"`)\n return m.density\n }\n const fill = def.fill ?? 1\n const area = options.width * options.height\n const coreMass = area * def.core.thickness * fill * densityOf(def.core.material)\n const layerMass = (def.layers ?? []).reduce((sum, l) => sum + area * l.thickness * faceCount(l) * densityOf(l.material), 0)\n return {\n id: options.id,\n material: def.core.material,\n shape: { kind: 'box', size: [options.width, options.height, assemblyDepth(def)] },\n position: options.position,\n ...(options.rotation ? { rotation: options.rotation } : {}),\n mass: coreMass + layerMass,\n thickness: def.core.thickness * fill,\n ...(def.layers ? { layers: def.layers.map((l) => ({ ...l })) } : {}),\n ...(def.units ? { units: { ...def.units, size: [...def.units.size] as Vec3 } } : {}),\n ...(def.reinforcement ? { reinforcement: { ...def.reinforcement } } : {}),\n ...(def.breach ? { breach: { ...def.breach } } : {}),\n ...(options.structure ? { structure: options.structure } : {}),\n ...options.extra,\n }\n}\n","import type { DestructibleSpec, JointSpec, MaterialId, PartSpec } from './types'\n\nexport interface FrameOptions {\n /** Total length along x between the outer column centres, metres (default 8). */\n spanX?: number\n /** Total length along z (default 8). */\n spanZ?: number\n /** Columns along x (at least 2, default 3). */\n columnsX?: number\n /** Columns along z (at least 2, default 3). */\n columnsZ?: number\n /** Height of one floor from slab top to the underside of the next slab, metres (default 3). */\n height?: number\n /** Number of floors (default 1). */\n floors?: number\n /** Brick walls on every perimeter bay of every floor; the first bay of the ground floor on the -z side gets a door opening (default false). */\n walls?: boolean\n /** A thin roof slab resting on the top beams (default true); without it the top floor is open. */\n roof?: boolean\n columnSize?: number\n beamHeight?: number\n slabThickness?: number\n wallThickness?: number\n doorWidth?: number\n doorHeight?: number\n /** Material of foundations, columns, beams, slabs and roof (default `concrete`). */\n material?: MaterialId\n wallMaterial?: MaterialId\n /** Override the load capacity of every column, kg (see `PartState.load`). */\n columnCapacity?: number\n}\n\n/**\n * A parametric test structure: a grid of columns on foundations, beams between the column tops, one slab per floor (the last one a roof), and\n * optional brick walls with a door. Joints are explicit and directional: columns rest on foundations (or on the slab below) with `rebar`, beams on\n * columns, slabs on beams, the roof rests on the top beams, walls hang on their columns with `mortar`. Part ids: `foundation_i_j`, `column_f_i_j`,\n * `beam_x_f_i_j`, `beam_z_f_i_j`, `slab_f`, `roof`, `wall_*`, `door`. Ground is y = 0 (the top of the foundations).\n */\nexport const buildFrame = (o: FrameOptions = {}): DestructibleSpec => {\n const spanX = o.spanX ?? 8, spanZ = o.spanZ ?? 8\n const nx = Math.max(2, o.columnsX ?? 3), nz = Math.max(2, o.columnsZ ?? 3)\n const H = o.height ?? 3, floors = Math.max(1, o.floors ?? 1)\n const cs = o.columnSize ?? 0.3, bh = o.beamHeight ?? 0.3, bw = 0.2, T = o.slabThickness ?? 0.2, wt = o.wallThickness ?? 0.2\n const dw = o.doorWidth ?? 1, dh = o.doorHeight ?? 2.1\n const mat = o.material ?? 'concrete', wmat = o.wallMaterial ?? 'brick'\n const roof = o.roof ?? true\n const xs = Array.from({ length: nx }, (_, i) => -spanX / 2 + (i * spanX) / (nx - 1))\n const zs = Array.from({ length: nz }, (_, j) => -spanZ / 2 + (j * spanZ) / (nz - 1))\n const parts: PartSpec[] = []\n const joints: JointSpec[] = []\n const on = (a: string, b: string, kind: JointSpec['kind']) => joints.push({ id: `${a}~${b}`, a, b, kind, bears: 'a_on_b' })\n\n for (let i = 0; i < nx; i++) {\n for (let j = 0; j < nz; j++) {\n parts.push({\n id: `foundation_${i}_${j}`, material: mat, shape: { kind: 'box', size: [cs * 2.2, 0.3, cs * 2.2] }, position: [xs[i], -0.15, zs[j]],\n structure: { role: 'foundation' }, anchored: true,\n })\n }\n }\n for (let f = 0; f < floors; f++) {\n const yb = f * (H + T)\n const top = yb + H\n const last = f === floors - 1\n const slabId = last && roof ? 'roof' : `slab_${f}`\n for (let i = 0; i < nx; i++) {\n for (let j = 0; j < nz; j++) {\n const id = `column_${f}_${i}_${j}`\n parts.push({\n id, material: mat, shape: { kind: 'box', size: [cs, H, cs] }, position: [xs[i], yb + H / 2, zs[j]],\n structure: o.columnCapacity === undefined ? { role: 'column' } : { role: 'column', capacity: o.columnCapacity },\n })\n on(id, f === 0 ? `foundation_${i}_${j}` : `slab_${f - 1}`, 'rebar')\n }\n }\n const beams: string[] = []\n const beam = (id: string, size: [number, number, number], pos: [number, number, number], c1: string, c2: string) => {\n parts.push({ id, material: mat, shape: { kind: 'box', size }, position: pos, structure: { role: 'beam' } })\n on(id, c1, 'rebar')\n on(id, c2, 'rebar')\n beams.push(id)\n }\n for (let j = 0; j < nz; j++) {\n for (let i = 0; i < nx - 1; i++) {\n beam(`beam_x_${f}_${i}_${j}`, [xs[i + 1] - xs[i] - cs, bh, bw], [(xs[i] + xs[i + 1]) / 2, top - bh / 2, zs[j]], `column_${f}_${i}_${j}`, `column_${f}_${i + 1}_${j}`)\n }\n }\n for (let i = 0; i < nx; i++) {\n for (let j = 0; j < nz - 1; j++) {\n beam(`beam_z_${f}_${i}_${j}`, [bw, bh, zs[j + 1] - zs[j] - cs], [xs[i], top - bh / 2, (zs[j] + zs[j + 1]) / 2], `column_${f}_${i}_${j}`, `column_${f}_${i}_${j + 1}`)\n }\n }\n const thick = last && roof ? T * 0.75 : T\n parts.push({\n id: slabId, material: mat, shape: { kind: 'box', size: [spanX + cs + 0.2, thick, spanZ + cs + 0.2] }, position: [0, top + thick / 2, 0],\n structure: { role: last && roof ? 'roof' : 'slab' },\n })\n for (const b of beams) on(slabId, b, last && roof ? 'resting' : 'rebar')\n\n if (o.walls) {\n const wh = H - bh\n const wy = yb + wh / 2\n const wall = (id: string, size: [number, number, number], pos: [number, number, number], supports: string[]) => {\n parts.push({ id, material: wmat, shape: { kind: 'box', size }, position: pos, structure: { role: 'wall' } })\n for (const s of supports) on(id, s, 'mortar')\n }\n for (const j of [0, nz - 1]) {\n for (let i = 0; i < nx - 1; i++) {\n const c1 = `column_${f}_${i}_${j}`, c2 = `column_${f}_${i + 1}_${j}`\n const avail = xs[i + 1] - xs[i] - cs\n if (f === 0 && j === 0 && i === 0 && avail > dw + 0.4) {\n const side = (avail - dw) / 2\n const lx = xs[i] + cs / 2 + side / 2, rx = xs[i + 1] - cs / 2 - side / 2\n wall(`wall_door_left`, [side, wh, wt], [lx, wy, zs[j]], [c1])\n wall(`wall_door_right`, [side, wh, wt], [rx, wy, zs[j]], [c2])\n const lh = wh - dh\n wall(`wall_door_lintel`, [dw, lh, wt], [xs[i] + cs / 2 + side + dw / 2, yb + dh + lh / 2, zs[j]], ['wall_door_left', 'wall_door_right'])\n parts.push({ id: 'door', material: 'wood_hard', shape: { kind: 'box', size: [dw - 0.04, dh, 0.05] }, position: [xs[i] + cs / 2 + side + dw / 2, yb + dh / 2, zs[j]], tags: ['door'] })\n joints.push({ id: 'door~wall_door_left', a: 'door', b: 'wall_door_left', kind: 'hinge', bears: false })\n } else wall(`wall_x_${f}_${i}_${j}`, [avail, wh, wt], [(xs[i] + xs[i + 1]) / 2, wy, zs[j]], [c1, c2])\n }\n }\n for (const i of [0, nx - 1]) {\n for (let j = 0; j < nz - 1; j++) {\n wall(`wall_z_${f}_${i}_${j}`, [wt, wh, zs[j + 1] - zs[j] - cs], [xs[i], wy, (zs[j] + zs[j + 1]) / 2], [`column_${f}_${i}_${j}`, `column_${f}_${i}_${j + 1}`])\n }\n }\n }\n }\n return { name: 'frame', parts, joints, tags: ['structure'] }\n}\n","import { createDestruction } from './world'\nimport type { DestructibleSpec, SizeStructureOptions, StructureRole } from './types'\n\n/**\n * 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\n * same load solver `createDestruction` uses, and each structural part (`structure.role` other than `none`) gets `structure.capacity = load / safety`,\n * so its at-rest stress is exactly `safety` (`safetyByRole` overrides it per role). With `redundancy` set, every part whose role is in\n * `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\n * `redundancy`. Parts without `structure`, with role `none`, or with no support path to an\n * anchored part are left as they are. The spec is not modified; a copy is returned.\n */\nexport const sizeStructure = (spec: DestructibleSpec, options: SizeStructureOptions = {}): DestructibleSpec => {\n const safety = options.safety ?? 0.65\n const redundancy = options.redundancy\n const redundancyRoles: readonly StructureRole[] = options.redundancyRoles ?? ['column']\n const safetyOf = (role: StructureRole): number => options.safetyByRole?.[role] ?? safety\n const loads = (s: DestructibleSpec): Map<string, { load: number; stress: number }> => {\n const w = createDestruction(options.materials ? { materials: options.materials } : {})\n const id = w.add(s)\n return new Map(w.state(id)!.parts.map((p) => [p.id, { load: p.load ?? 0, stress: p.stress ?? 0 }]))\n }\n const out = structuredClone(spec)\n const base = loads(out)\n const need = new Map<string, number>()\n for (const p of out.parts) {\n if (!p.structure || p.structure.role === 'none') continue\n const b = base.get(p.id)\n if (!b || b.stress <= 0) continue\n need.set(p.id, b.load / safetyOf(p.structure.role))\n }\n if (redundancy !== undefined) {\n for (const col of out.parts) {\n if (!col.structure || !redundancyRoles.includes(col.structure.role)) continue\n const reduced: DestructibleSpec = {\n ...out,\n parts: out.parts.filter((p) => p.id !== col.id),\n joints: (out.joints ?? []).filter((j) => j.a !== col.id && j.b !== col.id),\n }\n // joints are inferred when the spec has none; removing a part then removes its joints with it\n if (!out.joints) delete reduced.joints\n const l = loads(reduced)\n for (const [id, n] of need) {\n const r = l.get(id)\n if (r && r.stress > 0) need.set(id, Math.max(n, r.load / redundancy))\n }\n }\n }\n for (const p of out.parts) {\n const n = need.get(p.id)\n if (n !== undefined) p.structure = { ...p.structure!, capacity: n }\n }\n return out\n}\n","import type { DamageType, DestructionEventType, FractureStyle, JointKind, PartStatus, StructureRole, ToolKind } from './types'\n\n/** Locales shipped with the package. Unknown locales fall back to `en`. */\nexport type DestructionLocale = 'en' | 'pt-BR'\n\nexport interface DestructionStrings {\n /** Display name per material id (see `MATERIALS`). Unknown ids are not listed. */\n materialNames: Record<string, string>\n partStatus: Record<PartStatus, string>\n jointKinds: Record<JointKind, string>\n toolKinds: Record<ToolKind, string>\n damageTypes: Record<DamageType, string>\n /** Short label per event type, for logs and kill-feed style text. */\n eventLabels: Record<DestructionEventType, string>\n fractureStyles: Record<FractureStyle, string>\n structureRoles: Record<StructureRole, string>\n}\n\nexport const locales: Record<DestructionLocale, DestructionStrings> = {\n en: {\n materialNames: {\n steel: 'steel', cast_iron: 'cast iron', aluminium: 'aluminium', copper: 'copper', wood_soft: 'softwood', wood_hard: 'hardwood', plywood: 'plywood',\n mdf: 'MDF', glass: 'glass', tempered_glass: 'tempered glass', ceramic: 'ceramic', concrete: 'concrete', brick: 'brick', plaster: 'plaster',\n stone: 'stone', plastic: 'plastic', rubber: 'rubber', fabric: 'fabric', foam: 'foam', leather: 'leather', paper: 'paper', foliage: 'foliage',\n green_wood: 'green wood', cactus: 'cactus', flesh_fruit: 'fruit', wax: 'wax', soil: 'soil',\n },\n partStatus: { intact: 'intact', damaged: 'damaged', collapsed: 'collapsed', broken: 'broken', melted: 'melted', ashes: 'ashes' },\n jointKinds: {\n screw: 'screw', bolt: 'nut and bolt', nail: 'nail', weld: 'weld', glue: 'glue', hinge: 'hinge', clip: 'clip', tie: 'tie', mortar: 'mortar',\n fused: 'fused', stem: 'stem', rebar: 'rebar', resting: 'resting',\n },\n toolKinds: {\n hand: 'hand', screwdriver: 'screwdriver', wrench: 'wrench', pry_bar: 'pry bar', saw: 'saw', cutting_torch: 'cutting torch', knife: 'knife', hammer: 'hammer',\n },\n damageTypes: { ballistic: 'ballistic', blunt: 'blunt', slash: 'slash', explosive: 'explosive', fire: 'fire', heat: 'heat' },\n eventLabels: {\n damage: 'damage', dent: 'dent', hole: 'hole', crack: 'crack', ricochet: 'ricochet', debris: 'debris', fracture: 'broke', detach: 'came loose',\n disassemble_progress: 'taking apart', ignite: 'caught fire', extinguish: 'put out', burnout: 'burned to ash', melt: 'melting', drip: 'dripping',\n leak: 'leak', explode: 'exploded', primed: 'about to explode', stress: 'overload', collapse: 'collapsed', spall: 'plaster came off', stage: 'damage stage', expose: 'rebar bare', body: 'body', blast: 'blast', fragment_hit: 'fragment hit', destroyed: 'destroyed',\n },\n fractureStyles: { shatter: 'shatter', crumble: 'crumble', splinter: 'splinter', tear: 'tear', snap: 'snap', none: 'none' },\n structureRoles: { foundation: 'foundation', column: 'column', beam: 'beam', slab: 'slab', wall: 'wall', partition: 'partition', roof: 'roof', stair: 'stairs', none: 'none' },\n },\n 'pt-BR': {\n materialNames: {\n steel: 'aço', cast_iron: 'ferro fundido', aluminium: 'alumínio', copper: 'cobre', wood_soft: 'madeira macia', wood_hard: 'madeira de lei',\n plywood: 'compensado', mdf: 'MDF', glass: 'vidro', tempered_glass: 'vidro temperado', ceramic: 'cerâmica', concrete: 'concreto', brick: 'tijolo',\n plaster: 'gesso', stone: 'pedra', plastic: 'plástico', rubber: 'borracha', fabric: 'tecido', foam: 'espuma', leather: 'couro', paper: 'papel',\n foliage: 'folhagem', green_wood: 'madeira verde', cactus: 'cacto', flesh_fruit: 'fruta', wax: 'cera', soil: 'terra',\n },\n partStatus: { intact: 'intacto', damaged: 'danificado', collapsed: 'desabado', broken: 'quebrado', melted: 'derretido', ashes: 'cinzas' },\n jointKinds: {\n screw: 'parafuso', bolt: 'porca e parafuso', nail: 'prego', weld: 'solda', glue: 'cola', hinge: 'dobradiça', clip: 'encaixe', tie: 'amarração',\n mortar: 'argamassa', fused: 'fundido', stem: 'caule', rebar: 'vergalhão', resting: 'apoiado',\n },\n toolKinds: {\n hand: 'mão', screwdriver: 'chave de fenda', wrench: 'chave inglesa', pry_bar: 'pé de cabra', saw: 'serra', cutting_torch: 'maçarico', knife: 'faca', hammer: 'martelo',\n },\n damageTypes: { ballistic: 'tiro', blunt: 'impacto', slash: 'corte', explosive: 'explosão', fire: 'fogo', heat: 'calor' },\n eventLabels: {\n damage: 'dano', dent: 'amassado', hole: 'furo', crack: 'trinca', ricochet: 'ricochete', debris: 'estilhaços', fracture: 'quebrou', detach: 'soltou',\n disassemble_progress: 'desmontando', ignite: 'pegou fogo', extinguish: 'apagou', burnout: 'virou cinza', melt: 'derretendo', drip: 'pingando',\n leak: 'vazamento', explode: 'explodiu', primed: 'prestes a explodir', stress: 'sobrecarga', collapse: 'desabou', spall: 'reboco soltou', stage: 'estágio de dano', expose: 'vergalhão à mostra', body: 'corpo', blast: 'explosão', fragment_hit: 'estilhaço atingiu', destroyed: 'destruído',\n },\n fractureStyles: { shatter: 'estilhaçar', crumble: 'esfarelar', splinter: 'lascar', tear: 'rasgar', snap: 'partir', none: 'nenhuma' },\n structureRoles: { foundation: 'fundação', column: 'pilar', beam: 'viga', slab: 'laje', wall: 'parede', partition: 'divisória', roof: 'telhado', stair: 'escada', none: 'nenhum' },\n },\n}\n\nexport const resolveStrings = (locale: string | undefined): DestructionStrings => locales[(locale as DestructionLocale) ?? 'en'] ?? locales.en\n","import { checkDestructible as check } from '@adatechnology/game-contracts'\nimport type { CheckOptions as ContractCheckOptions, DestructibleImpl } from '@adatechnology/game-contracts'\nimport { MATERIALS } from './materials'\n\n// The contract itself lives in @adatechnology/game-contracts (a module depends only on that); re-exported here so that no import breaks.\nexport { IMPACT_CONTRACT, checkHit } from '@adatechnology/game-contracts'\nexport type { DestructibleImpl, ImpactContract } from '@adatechnology/game-contracts'\n\nexport interface CheckOptions {\n /** Ids of custom materials the impl uses besides the built-in `MATERIALS`. */\n materials?: string[]\n}\n\n/**\n * `checkDestructible` of `@adatechnology/game-contracts`, with the built-in `MATERIALS` (plus `options.materials`) as the known material ids.\n * It hits the impl (and calls `reset()` afterwards when there is one).\n */\nexport const checkDestructible = (impl: DestructibleImpl, options: CheckOptions = {}): { ok: boolean; problems: string[] } => {\n const contractOptions: ContractCheckOptions = { materials: [...MATERIALS.map((m) => m.id), ...(options.materials ?? [])] }\n return check(impl, contractOptions)\n}\n","import { GROUND } from './types'\nimport type { StructurePart, Support } from './types'\n\n/**\n * Load each part carries at rest, by the rules of the Visor de casas 3D (which the destruction world shares): load only goes down to supports closer to\n * the ground, shared equally, and a partition wall carries nothing, so what rests only on partitions has no load. `without` leaves one part out (as if it\n * had failed). Parts that are not structural (the tank) are not loaded.\n */\nexport function loadsAtRest(parts: readonly StructurePart[], supports: readonly Support[], without?: string): Map<string, number> {\n const byId = new Map(parts.filter((part) => part.id !== without).map((part) => [part.id, part]))\n const resting = new Map<string, string[]>()\n const carrying = new Map<string, string[]>()\n const push = (map: Map<string, string[]>, key: string, value: string): void => {\n const list = map.get(key)\n if (list) list.push(value)\n else map.set(key, [value])\n }\n for (const support of supports) {\n if (support.bears === false) continue\n if (!byId.has(support.part) || (support.on !== GROUND && !byId.has(support.on))) continue\n push(resting, support.part, support.on)\n push(carrying, support.on, support.part)\n }\n const partition = (id: string): boolean => byId.get(id)?.role === 'partition'\n const structural = (id: string): boolean => byId.has(id) && byId.get(id)!.role !== 'none'\n const distance = new Map<string, number>([[GROUND, 0]])\n const queue = [GROUND]\n for (let head = 0; head < queue.length; head++) {\n const current = queue[head]!\n if (current !== GROUND && partition(current)) continue\n for (const above of carrying.get(current) ?? []) {\n if (distance.has(above) || !structural(above)) continue\n distance.set(above, distance.get(current)! + 1)\n queue.push(above)\n }\n }\n const incoming = new Map<string, number>()\n const loads = new Map<string, number>()\n for (let head = queue.length - 1; head >= 1; head--) {\n const id = queue[head]!\n const total = (byId.get(id)!.mass || 1) + (incoming.get(id) ?? 0)\n loads.set(id, total)\n const below = (resting.get(id) ?? []).filter((other) => distance.has(other) && distance.get(other)! < distance.get(id)! && !(other !== GROUND && partition(other)))\n for (const other of below) incoming.set(other, (incoming.get(other) ?? 0) + total / below.length)\n }\n return loads\n}\n\nexport interface SizingOptions {\n /** Fraction of its capacity a pillar or bearing wall uses at rest. */\n safety: number\n /** The most of its capacity a pillar or bearing wall uses after any other pillar or bearing wall is lost. */\n redundancy: number\n /** Fraction of capacity every other structural part uses at rest. */\n safetyOthers: number\n}\n\nconst isBearing = (part: StructurePart): boolean => part.role === 'column' || part.role === 'wall'\n\n/**\n * Capacity of each loaded part, as a designer would size it: a pillar or bearing wall uses `safety` of it at rest and stays under `redundancy` when\n * any other pillar or bearing wall is lost (the house holds one loss and falls with two); every other part uses `safetyOthers`.\n * `sizeStructure` of game-destruction gives the same numbers except for beams of a framed building (it holds them under `redundancy` too).\n */\nexport function sizeCapacities(parts: readonly StructurePart[], supports: readonly Support[], options: SizingOptions): Map<string, number> {\n const loads = loadsAtRest(parts, supports)\n const worst = new Map<string, number>()\n for (const part of parts.filter(isBearing)) {\n for (const [id, load] of loadsAtRest(parts, supports, part.id)) {\n const before = loads.get(id)\n if (before && load / before > (worst.get(id) ?? 1)) worst.set(id, load / before)\n }\n }\n const capacities = new Map<string, number>()\n for (const part of parts) {\n const load = loads.get(part.id)\n if (load === undefined || part.role === 'none') continue\n const factor = isBearing(part) ? Math.max(1 / options.safety, (worst.get(part.id) ?? 1) / options.redundancy) : 1 / options.safetyOthers\n capacities.set(part.id, Math.max(1, load * factor))\n }\n return capacities\n}\n","import { touches } from '../geometry'\nimport type { Rect, StructurePart, Support } from '../types'\nimport type { WallSplit } from './panels'\n\nexport interface PartsAndSupports {\n parts: StructurePart[]\n supports: Support[]\n}\n\n/** Replaces each part that has a split by its pieces, and re-points what rested on it or what it rested on (the pieces touching the part resting on it get the load). */\nexport function applySplits(input: PartsAndSupports, splits: ReadonlyMap<string, WallSplit>): PartsAndSupports {\n if (!splits.size) return input\n const boxes = new Map<string, Rect>(input.parts.map((part) => [part.id, part.aabb]))\n const pieceBox = new Map<string, Rect>()\n for (const split of splits.values()) for (const piece of split.pieces) pieceBox.set(piece.id, piece.aabb)\n const parts = input.parts.flatMap((part) => splits.get(part.id)?.pieces ?? [part])\n const supports: Support[] = []\n for (const support of input.supports) {\n const own = splits.get(support.part)\n const host = splits.get(support.on)\n const resting = boxes.get(support.part)\n const targets = host ? host.top.filter((id) => resting && touches(pieceBox.get(id)!, resting, 0.05)) : [support.on]\n const carriers = host ? (targets.length ? targets : host.top) : targets\n for (const part of own ? own.base : [support.part]) for (const on of carriers) supports.push({ ...support, part, on })\n }\n for (const split of splits.values()) supports.push(...split.internal)\n return { parts, supports }\n}\n","import type { JointKind } from '@adatechnology/game-contracts'\n\nimport { round2 } from '../geometry'\nimport type { Opening, Rect, StructurePart, Support } from '../types'\nimport type { WallSplit } from './panels'\n\nexport interface CourseSpec {\n rowHeight: number\n /** Length of a unit along the wall; without it a course is one piece per stretch (a log). */\n unitLength?: number\n bond: 'running' | 'stack'\n /** Joint of a unit on the units under it. */\n joint: JointKind\n assembly: string\n}\n\nconst MIN_UNIT = 0.02\n\ninterface Cell {\n from: number\n to: number\n row: number\n y0: number\n y1: number\n}\n\nfunction cutAt(from: number, to: number, openings: readonly Opening[], y0: number, y1: number): [number, number][] {\n let stretches: [number, number][] = [[from, to]]\n for (const opening of openings.filter((o) => o.y0 < y1 - MIN_UNIT && o.y1 > y0 + MIN_UNIT)) {\n stretches = stretches.flatMap(([a, b]): [number, number][] => {\n if (opening.to <= a || opening.from >= b) return [[a, b]]\n return [[a, Math.min(b, opening.from)], [Math.max(a, opening.to), b]].filter(([x, y]) => (y as number) - (x as number) > MIN_UNIT) as [number, number][]\n })\n }\n return stretches\n}\n\nfunction unitsOf(from: number, to: number, row: number, spec: CourseSpec): [number, number][] {\n const length = spec.unitLength\n if (!length) return [[from, to]]\n const offset = spec.bond === 'running' && row % 2 === 1 ? length / 2 : 0\n const cuts: number[] = [from]\n for (let at = from + (offset || length); at < to - MIN_UNIT; at += length) cuts.push(at)\n cuts.push(to)\n return cuts.slice(0, -1).map((start, k): [number, number] => [start, cuts[k + 1]!]).filter(([a, b]) => b - a > MIN_UNIT)\n}\n\n/**\n * Cuts a wall into courses of units (bricks laid in bond, or logs): each course is cut at the openings it meets, and each unit rests on the units of the course\n * below that it overlaps. A wall whose lowest course goes loses every course above it. The mass of the wall is shared among the units by volume.\n */\nexport function splitIntoCourses(wall: StructurePart, openings: readonly Opening[], spec: CourseSpec): WallSplit {\n const alongU = wall.aabb[2] - wall.aabb[0] >= wall.aabb[3] - wall.aabb[1]\n const from = alongU ? wall.aabb[0] : wall.aabb[1]\n const to = alongU ? wall.aabb[2] : wall.aabb[3]\n const cross: [number, number] = alongU ? [wall.aabb[1], wall.aabb[3]] : [wall.aabb[0], wall.aabb[2]]\n const rows = Math.max(1, Math.round((wall.y1 - wall.y0) / spec.rowHeight))\n const rowHeight = (wall.y1 - wall.y0) / rows\n const cells: Cell[] = []\n for (let row = 0; row < rows; row++) {\n const y0 = wall.y0 + row * rowHeight\n const y1 = wall.y0 + (row + 1) * rowHeight\n for (const [a, b] of cutAt(from, to, openings.filter((o) => o.wall === wall.id), y0, y1)) for (const [x0, x1] of unitsOf(a, b, row, spec)) cells.push({ from: x0, to: x1, row, y0, y1 })\n }\n const total = cells.reduce((sum, cell) => sum + (cell.to - cell.from) * (cell.y1 - cell.y0), 0)\n const box = (cell: Cell): Rect => (alongU ? [cell.from, cross[0], cell.to, cross[1]] : [cross[0], cell.from, cross[1], cell.to])\n const pieces = cells.map((cell, index): StructurePart => ({\n id: `${wall.id}_${spec.unitLength ? 'u' : 'log'}${cell.row}_${index}`, role: wall.role, material: wall.material, aabb: box(cell), y0: cell.y0, y1: cell.y1, floor: wall.floor,\n mass: round2(Math.max(0.1, (wall.mass * (cell.to - cell.from) * (cell.y1 - cell.y0)) / total)), host: wall.id, assembly: spec.assembly, unit: true,\n }))\n const internal: Support[] = []\n cells.forEach((cell, index) => {\n if (cell.row === 0) return\n const below = cells.map((other, k) => ({ other, k })).filter(({ other }) => other.row === cell.row - 1 && Math.min(other.to, cell.to) - Math.max(other.from, cell.from) > MIN_UNIT)\n for (const { k } of below) internal.push({ part: pieces[index]!.id, on: pieces[k]!.id, joint: spec.joint })\n })\n return { pieces, internal, base: pieces.filter((_, i) => cells[i]!.row === 0).map((p) => p.id), top: pieces.filter((_, i) => cells[i]!.row === rows - 1).map((p) => p.id) }\n}\n","import type { JointKind } from '@adatechnology/game-contracts'\n\nimport { round2 } from '../geometry'\nimport type { Opening, Rect, StructurePart, Support } from '../types'\n\nexport interface PanelStyle {\n lintelMaterial: string\n lintelAssembly?: string\n /** Joint of a lintel on its piers and of the wall above it on the lintel. */\n lintelJoint: JointKind\n wallJoint: JointKind\n}\n\nexport interface WallSplit {\n pieces: StructurePart[]\n /** What the pieces rest on among themselves (lintel on piers, spandrel on lintel). */\n internal: Support[]\n /** Pieces that rest on what the wall rests on. */\n base: string[]\n /** Pieces that carry what rests on the wall. */\n top: string[]\n}\n\nexport const LINTEL_DEPTH = 0.2\nexport const LINTEL_BEARING = 0.2\nconst MIN_PIECE = 0.05\n\ninterface Frame {\n alongU: boolean\n from: number\n to: number\n cross: [number, number]\n}\n\nconst frameOf = (wall: StructurePart): Frame => {\n const alongU = wall.aabb[2] - wall.aabb[0] >= wall.aabb[3] - wall.aabb[1]\n return alongU ? { alongU, from: wall.aabb[0], to: wall.aabb[2], cross: [wall.aabb[1], wall.aabb[3]] } : { alongU, from: wall.aabb[1], to: wall.aabb[3], cross: [wall.aabb[0], wall.aabb[2]] }\n}\n\nconst boxOf = (frame: Frame, from: number, to: number): Rect => (frame.alongU ? [from, frame.cross[0], to, frame.cross[1]] : [frame.cross[0], from, frame.cross[1], to])\n\ninterface Draft {\n id: string\n role: StructurePart['role']\n material: string\n assembly?: string\n from: number\n to: number\n y0: number\n y1: number\n /** Volume that counts for the mass share (pieces tile the wall: a lintel keeps the bearing it shares with the piers). */\n volume: number\n}\n\n/**\n * Cuts a wall at its windows: piers between them at full height, a sill wall under each window, a lintel over it that bears 0.2 m on the piers and the wall\n * above the lintel up to the top. The mass of the wall is shared among the pieces by volume, so the total is the wall's.\n */\nexport function splitIntoPanels(wall: StructurePart, openings: readonly Opening[], style: PanelStyle): WallSplit {\n const frame = frameOf(wall)\n const own = openings.filter((o) => o.wall === wall.id && o.to > frame.from + MIN_PIECE && o.from < frame.to - MIN_PIECE).sort((a, b) => a.from - b.from)\n if (!own.length) return { pieces: [wall], internal: [], base: [wall.id], top: [wall.id] }\n const drafts: Draft[] = []\n const piers: Draft[] = []\n const lintels: Draft[] = []\n const spandrels: (Draft | undefined)[] = []\n const height = wall.y1 - wall.y0\n let cursor = frame.from\n const roleOf = wall.role\n const addPier = (to: number): void => {\n if (to - cursor < MIN_PIECE) return\n piers.push({ id: `${wall.id}_pier_${piers.length}`, role: roleOf, material: wall.material, from: cursor, to, y0: wall.y0, y1: wall.y1, volume: (to - cursor) * height })\n }\n own.forEach((opening, k) => {\n addPier(Math.max(cursor, opening.from))\n const lintelTop = Math.min(wall.y1, opening.y1 + LINTEL_DEPTH)\n const lintelFrom = Math.max(frame.from, opening.from - LINTEL_BEARING)\n const lintelTo = Math.min(frame.to, opening.to + LINTEL_BEARING)\n const lintelHeight = lintelTop - opening.y1\n if (opening.y0 - wall.y0 > MIN_PIECE) drafts.push({ id: `${wall.id}_sill_${k}`, role: 'partition', material: wall.material, from: opening.from, to: opening.to, y0: wall.y0, y1: opening.y0, volume: (opening.to - opening.from) * (opening.y0 - wall.y0) })\n lintels.push({ id: `${wall.id}_lintel_${k}`, role: 'beam', material: style.lintelMaterial, from: lintelFrom, to: lintelTo, y0: opening.y1, y1: lintelTop, volume: (lintelTo - lintelFrom) * lintelHeight })\n spandrels.push(wall.y1 - lintelTop > MIN_PIECE ? { id: `${wall.id}_spandrel_${k}`, role: roleOf, material: wall.material, from: opening.from, to: opening.to, y0: lintelTop, y1: wall.y1, volume: (opening.to - opening.from) * (wall.y1 - lintelTop) } : undefined)\n cursor = opening.to\n })\n addPier(frame.to)\n // the piers give the bearing zone of each lintel to it\n for (const pier of piers) {\n for (const lintel of lintels) {\n const overlap = Math.max(0, Math.min(pier.to, lintel.to) - Math.max(pier.from, lintel.from))\n pier.volume -= overlap * (lintel.y1 - lintel.y0)\n }\n }\n const all = [...piers, ...drafts, ...lintels, ...spandrels.filter((d): d is Draft => d !== undefined)]\n const total = all.reduce((sum, d) => sum + d.volume, 0)\n const pieces = all.map((d): StructurePart => ({\n id: d.id, role: d.role, material: d.material, aabb: boxOf(frame, d.from, d.to), y0: d.y0, y1: d.y1, floor: wall.floor, mass: round2(Math.max(0.1, (wall.mass * d.volume) / total)), host: wall.id,\n ...(d.role === 'beam' ? (style.lintelAssembly ? { assembly: style.lintelAssembly } : {}) : wall.assembly ? { assembly: wall.assembly } : {}),\n }))\n const internal: Support[] = []\n lintels.forEach((lintel, k) => {\n for (const pier of piers) if (Math.min(pier.to, lintel.to) - Math.max(pier.from, lintel.from) > 0) internal.push({ part: lintel.id, on: pier.id, joint: style.lintelJoint })\n const spandrel = spandrels[k]\n if (spandrel) internal.push({ part: spandrel.id, on: lintel.id, joint: style.wallJoint })\n })\n const base = [...piers, ...drafts.filter((d) => d.id.includes('_sill_'))].map((d) => d.id)\n const top = [...piers.map((p) => p.id), ...lintels.map((l, k) => spandrels[k]?.id ?? l.id)]\n return { pieces, internal, base, top }\n}\n","import { getAssembly } from '@adatechnology/game-destruction'\n\nimport type { Construction, Rect, Structure, StructurePart, WallDetail } from '../types'\nimport { applySplits } from './apply'\nimport type { PartsAndSupports } from './apply'\nimport { splitIntoCourses } from './courses'\nimport type { CourseSpec } from './courses'\nimport { splitIntoPanels } from './panels'\nimport type { WallSplit } from './panels'\nimport { CONSTRUCTION_SYSTEMS } from '../registry'\n\nconst LOG_DIAMETER = 0.26\nconst isWall = (part: StructurePart): boolean => part.id.startsWith('wall_') && part.assembly !== undefined && (part.role === 'wall' || part.role === 'partition')\n\nfunction logSpec(construction: Construction, part: StructurePart): CourseSpec {\n const diameter = (construction.walls.logDiameter as number | undefined) ?? LOG_DIAMETER\n return { rowHeight: diameter, bond: 'stack', joint: CONSTRUCTION_SYSTEMS.get(construction.system)!.joints.wall, assembly: part.assembly! }\n}\n\n/** Walls cut at their windows (piers, sills, lintels, spandrels); the walls of logs as courses of logs. */\nfunction panelSplits(input: PartsAndSupports, structure: Structure): Map<string, WallSplit> {\n const { construction } = structure\n const system = CONSTRUCTION_SYSTEMS.get(construction.system)!\n const splits = new Map<string, WallSplit>()\n for (const part of input.parts.filter(isWall)) {\n if (construction.system === 'log') {\n splits.set(part.id, splitIntoCourses(part, structure.openings, logSpec(construction, part)))\n continue\n }\n const split = splitIntoPanels(part, structure.openings, {\n lintelMaterial: system.timber ? construction.frame.timber : 'concrete', ...(system.timber ? {} : { lintelAssembly: 'reinforced_concrete' }), lintelJoint: system.joints.beam, wallJoint: system.joints.wall,\n })\n if (split.pieces.length > 1) splits.set(part.id, split)\n }\n return splits\n}\n\n/** Splits the walls the way `detail` says: `coarse` keeps one part per wall, `panels` cuts them at the windows, `units` goes on to bricks and blocks. */\nexport function applyPanels(input: PartsAndSupports, structure: Structure, detail: WallDetail): PartsAndSupports {\n if (detail === 'coarse') return input\n return applySplits(input, panelSplits(input, structure))\n}\n\nexport interface Sized extends PartsAndSupports {\n capacities: Map<string, number>\n}\n\n/** Cuts each wall piece that its assembly lays in units (bricks, blocks, concrete panels) into those units; a unit takes the share of the piece's capacity its width has (it carries its column of the wall). */\nexport function applyUnits(input: Sized, structure: Structure): Sized {\n const splits = new Map<string, WallSplit>()\n for (const part of input.parts) {\n if (part.unit || !part.assembly || part.role === 'beam' || part.role === 'none') continue\n const units = getAssembly(part.assembly)?.units\n if (!units) continue\n const joint = CONSTRUCTION_SYSTEMS.get(structure.construction.system)!.joints.wall\n splits.set(part.id, splitIntoCourses(part, [], { rowHeight: units.size[1], unitLength: units.size[0], bond: units.bond, joint: units.mortar === 'concrete' ? 'mortar' : joint, assembly: part.assembly }))\n }\n const next = applySplits(input, splits)\n const capacities = new Map(input.capacities)\n for (const [id, split] of splits) {\n const capacity = input.capacities.get(id)\n capacities.delete(id)\n if (capacity === undefined) continue\n const along = (box: Rect): number => Math.max(box[2] - box[0], box[3] - box[1])\n const length = along(input.parts.find((part) => part.id === id)!.aabb)\n for (const piece of split.pieces) capacities.set(piece.id, Math.max(1, (capacity * along(piece.aabb)) / length))\n }\n return { ...next, capacities }\n}\n","import type { DestructibleSpec, JointSpec, PartSpec, StructureRole } from '@adatechnology/game-contracts'\nimport { assemblyPart } from '@adatechnology/game-destruction'\nimport { sizeCapacities } from './loads'\nimport { GROUND } from './types'\nimport { applyPanels, applyUnits } from './wall-detail'\nimport type { PartRole, Structure, StructurePart, WallDetail } from './types'\n\nexport interface DestructibleSpecOptions {\n /** Fraction of its capacity a pillar or bearing wall uses at rest (default 0.65). */\n safety?: number\n /** After losing any other pillar or bearing wall, the most of its capacity one of them uses (default 0.97: the house holds one loss and falls with two). */\n redundancy?: number\n /** Fraction of capacity beams, slabs, roofs, stairs and partitions use at rest (default 0.45). */\n safetyOthers?: number\n /** Bearing walls close but do not carry: a frame of pillars and beams carries the building. Default: for a framed building unless the detail is `coarse`. */\n portico?: boolean\n /** How finely the walls are split (default `panels`; `coarse` is one part per wall as the Visor de casas 3D builds it). */\n wallDetail?: WallDetail\n /** Name of the spec (default `house`). */\n name?: string\n /** Leaves parts out (and what rests on them is dropped from the joints). */\n filter?: (part: StructurePart) => boolean\n /** `false` keeps the capacity of the material instead of sizing it from the load. */\n sized?: boolean\n /** Metres the anchored terrain slab reaches beyond the parts (default 6). */\n terrainMargin?: number\n}\n\nconst CONTRACT_ROLE: Record<PartRole, StructureRole> = { column: 'column', beam: 'beam', slab: 'slab', wall: 'wall', partition: 'partition', roof: 'roof', stair: 'stair', none: 'none' }\n\nconst TERRAIN_MARGIN = 6\nconst TERRAIN_THICKNESS = 0.5\n\nconst boxSpec = (part: StructurePart, capacity: number | undefined): PartSpec => {\n const [u0, v0, u1, v1] = part.aabb\n return {\n id: part.id, material: part.material, shape: { kind: 'box', size: [Math.max(0.01, u1 - u0), Math.max(0.01, part.y1 - part.y0), Math.max(0.01, v1 - v0)] },\n position: [(u0 + u1) / 2, (part.y0 + part.y1) / 2, (v0 + v1) / 2], mass: Math.max(0.1, part.mass || 1),\n structure: capacity === undefined ? { role: CONTRACT_ROLE[part.role] } : { role: CONTRACT_ROLE[part.role], capacity },\n }\n}\n\n/** A wall piece as its assembly builds it (layers, rebar, units, breach), with the mass the structure gave it. A brick or log is the unit itself, so it keeps no units or breach. */\nconst assemblySpec = (part: StructurePart, capacity: number | undefined): PartSpec => {\n const [u0, v0, u1, v1] = part.aabb\n const alongU = u1 - u0 >= v1 - v0\n const spec = assemblyPart(part.assembly!, {\n id: part.id, width: alongU ? u1 - u0 : v1 - v0, height: part.y1 - part.y0, position: [(u0 + u1) / 2, (part.y0 + part.y1) / 2, (v0 + v1) / 2], ...(alongU ? {} : { rotation: [0, Math.PI / 2, 0] }),\n structure: capacity === undefined ? { role: CONTRACT_ROLE[part.role] } : { role: CONTRACT_ROLE[part.role], capacity }, extra: { mass: Math.max(0.1, part.mass || 1) },\n })\n if (part.unit) {\n delete spec.units\n delete spec.breach\n }\n return spec\n}\n\nconst partSpecOf = (part: StructurePart, capacity: number | undefined, detailed: boolean): PartSpec => (detailed && part.assembly ? assemblySpec(part, capacity) : boxSpec(part, capacity))\n\n/**\n * The structure as a `DestructibleSpec` in the space of the house (x = u, y = height, z = v; the ground is y = 0), one box per part and a terrain slab\n * that anchors it. Capacities are sized from the loads at rest, as a designer would: a house stands whole, holds the loss of one pillar or bearing wall\n * and falls with two.\n */\nexport function toDestructibleSpec(structure: Structure, options: DestructibleSpecOptions = {}): DestructibleSpec {\n const { safety = 0.65, redundancy = 0.97, safetyOthers = 0.45 } = options\n const kept = structure.parts.filter((part) => !options.filter || options.filter(part))\n const portico = options.portico ?? (options.wallDetail !== 'coarse' && structure.framed)\n const roled = portico ? kept.map((part): StructurePart => (part.role === 'wall' ? { ...part, role: 'partition' } : part)) : kept\n const ids = new Set(roled.map((part) => part.id))\n const filtered = structure.supports.filter((support) => !options.filter || (ids.has(support.part) && (support.on === GROUND || ids.has(support.on))))\n const detail = options.wallDetail ?? 'panels'\n const panels = applyPanels({ parts: roled, supports: filtered }, structure, detail)\n const sizing = { safety, redundancy, safetyOthers }\n const sized = { ...panels, capacities: options.sized === false ? new Map<string, number>() : sizeCapacities(panels.parts, panels.supports, sizing) }\n const { parts, supports, capacities } = detail === 'units' ? applyUnits(sized, structure) : sized\n const specs = parts.map((part) => partSpecOf(part, capacities.get(part.id), detail !== 'coarse'))\n const margin = options.terrainMargin ?? TERRAIN_MARGIN\n const x0 = Math.min(...parts.map((part) => part.aabb[0]))\n const z0 = Math.min(...parts.map((part) => part.aabb[1]))\n const x1 = Math.max(...parts.map((part) => part.aabb[2]))\n const z1 = Math.max(...parts.map((part) => part.aabb[3]))\n if (parts.length) specs.push({ id: GROUND, material: 'concrete', shape: { kind: 'box', size: [x1 - x0 + margin, TERRAIN_THICKNESS, z1 - z0 + margin] }, position: [(x0 + x1) / 2, -TERRAIN_THICKNESS / 2, (z0 + z1) / 2], hp: 1e12, structure: { role: 'foundation' }, anchored: true, tags: ['terrain'] })\n const present = new Set([...parts.map((part) => part.id), GROUND])\n const joints: JointSpec[] = supports.filter((s) => present.has(s.part) && present.has(s.on)).map((s) => ({ id: `${s.part}~${s.on}`, a: s.part, b: s.on, kind: s.joint, bears: s.bears === false ? false : 'a_on_b' }))\n return { name: options.name ?? 'house', parts: specs, joints, tags: ['structure', 'house'] }\n}\n","import type { DestructibleSpec } from '@adatechnology/game-contracts'\nimport { assemblyDepth, assemblyPart, getAssembly } from '@adatechnology/game-destruction'\n\nimport { GROUND } from './types'\nimport { constructionOfSystem } from './presets'\nimport { CONSTRUCTION_SYSTEMS } from './registry'\nimport { toDestructibleSpec } from './to-destructible-spec'\nimport type { Opening, StructureSource, WallDetail } from './types'\n\nexport interface WallSpecimenOptions {\n /** Wall assembly of `game-destruction` (`brick_wall_plastered`, `concrete_block_wall`, `reinforced_concrete`, `drywall`, `wood_frame_wall`, `log_wall`, `sheet_metal_shack`...). */\n assembly: string\n /** Width and height in metres (the test area uses 2.4 x 2.1). */\n w: number\n h: number\n opening?: 'door' | 'window' | null\n /** Default `panels`: piers, lintel with its 0.2 m bearing, sill, plaster and rebar; `units` also lays the bricks, blocks or concrete panels one by one. */\n detail?: WallDetail\n}\n\nconst SYSTEM_OF_ASSEMBLY: Record<string, string> = { log_wall: 'log', wood_frame_wall: 'wood_frame', sheet_metal_shack: 'improvised' }\nconst DOOR_WIDTH = 0.9\nconst WINDOW_WIDTH = 1.0\n\nfunction openingOf(kind: 'door' | 'window', height: number): Opening {\n return kind === 'door'\n ? { id: 'door', kind, wall: 'wall_specimen', from: -DOOR_WIDTH / 2, to: DOOR_WIDTH / 2, y0: 0, y1: height * 0.8 }\n : { id: 'window', kind, wall: 'wall_specimen', from: -WINDOW_WIDTH / 2, to: WINDOW_WIDTH / 2, y0: height * 0.33, y1: height * 0.8 }\n}\n\n/**\n * A test wall as its assembly builds it, standing on a plinth: in `panels` the piers beside the opening, the lintel over it (reinforced concrete bearing 0.2 m on\n * the piers; a header in timber walls), the sill under a window and the wall above; with the plaster coat and the rebar of the assembly. The mass is the\n * assembly's for the whole w x h, whatever the detail.\n */\nexport function buildWallSpecimen(options: WallSpecimenOptions): DestructibleSpec {\n const { assembly, w, h, opening = null, detail = 'panels' } = options\n const def = getAssembly(assembly)\n if (!def) throw new Error(`unknown assembly \"${assembly}\"`)\n const system = SYSTEM_OF_ASSEMBLY[assembly] ?? 'masonry'\n const depth = assemblyDepth(def)\n const mass = assemblyPart(assembly, { id: 'wall_specimen', width: w, height: h, position: [0, h / 2, 0] }).mass ?? 1\n const construction = constructionOfSystem(system, { facade: {}, floors: [], rooms: [], walls: [], doors: [], items: [], w, d: depth } as StructureSource)!\n const joint = CONSTRUCTION_SYSTEMS.get(system)!.joints.wall\n const structure = {\n parts: [{ id: 'wall_specimen', role: 'wall' as const, material: def.core.material, aabb: [-w / 2, -depth / 2, w / 2, depth / 2] as [number, number, number, number], y0: 0, y1: h, floor: 0, mass, assembly }],\n supports: [{ part: 'wall_specimen', on: GROUND, joint }],\n openings: opening ? [openingOf(opening, h)] : [],\n levels: [0], elevation: 0, construction, framed: false,\n roof: { shape: 'slab' as const, covering: '', material: '', pitch: 0, bearingFloor: 0, panes: [], trusses: 0 },\n }\n return toDestructibleSpec(structure, { wallDetail: detail, sized: false, terrainMargin: 0.6, name: `wall_${assembly}` })\n}\n"],"mappings":"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;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,aAAe;QACd,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,aAAe;MACf,SAAW;QACV,OAAS;QACT,UAAY;QACZ,cAAgB;QAChB,cAAgB;MACjB;MACA,QAAU;QACT,OAAS;MACV;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,aAAe;QACd,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,aAAe;MACf,SAAW;QACV,OAAS;QACT,UAAY;QACZ,cAAgB;QAChB,cAAgB;MACjB;MACA,QAAU;QACT,OAAS;MACV;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;QACT,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;QACT,SAAW;MACZ;MACA,WAAa;MACb,aAAe;MACf,aAAe;MACf,SAAW;QACV,OAAS;QACT,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,eAAiB;MAClB;MACA,QAAU;QACT,OAAS;QACT,aAAe;MAChB;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,WAAa;MACb,aAAe;MACf,aAAe;MACf,SAAW;QACV,OAAS;QACT,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,eAAiB;MAClB;MACA,QAAU;QACT,OAAS;QACT,aAAe;MAChB;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;MACf,aAAe;QACd,SAAW;MACZ;IACD;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,cAAgB;QAChB,cAAgB;QAChB,eAAiB;MAClB;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,WAAa;MACd;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,cAAgB;QAChB,cAAgB;MACjB;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,cAAgB;QAChB,cAAgB;MACjB;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,cAAgB;QAChB,cAAgB;MACjB;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,cAAgB;QAChB,cAAgB;MACjB;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,OAAS;QACT,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;QACT,WAAa;MACd;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;QACT,WAAa;MACd;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;QACT,WAAa;MACd;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,cAAgB;QAChB,cAAgB;MACjB;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,OAAS;QACT,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,cAAgB;QAChB,cAAgB;MACjB;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;EACD;ACv0BA,MAAA,yBAAA;IACC,aAAa;IACb,WAAa;IACb,UAAY;IACZ,OAAS;IACT,OAAS;IACT,MAAQ;IACR,QAAU;IACV,QAAU;IACV,MAAQ;IACR,QAAQ;IACR,QAAQ;IACR,QAAU;IACV,OAAS;IACT,QAAU;IACV,MAAQ;IACR,QAAU;IACV,OAAS;IACT,QAAU;IACV,MAAQ;IACR,UAAY;IACZ,KAAO;IACP,SAAW;IACX,KAAO;IACP,WAAa;IACb,OAAS;IACT,QAAU;IACV,QAAU;IACV,UAAY;IACZ,YAAc;IACd,QAAU;IACV,OAAS;IACT,SAAW;IACX,MAAQ;IACR,SAAW;IACX,QAAU;IACV,SAAW;IACX,QAAU;IACV,MAAQ;IACR,QAAU;IACV,UAAY;IACZ,SAAW;IACX,OAAS;IACT,WAAa;IACb,MAAQ;IACR,QAAU;IACV,SAAW;IACX,MAAQ;IACR,OAAS;IACT,OAAS;IACT,QAAU;IACV,MAAQ;IACR,QAAU;IACV,OAAS;IACT,OAAS;IACT,OAAS;IACT,KAAO;IACP,QAAU;IACV,UAAY;IACZ,QAAU;IACV,OAAS;IACT,MAAQ;IACR,SAAW;IACX,WAAa;IACb,OAAS;IACT,MAAQ;IACR,QAAU;IACV,SAAW;IACX,SAAW;IACX,QAAU;IACV,SAAW;IACX,KAAO;IACP,SAAW;IACX,QAAU;IACV,MAAQ;IACR,MAAQ;IACR,MAAQ;IACR,MAAQ;IACR,SAAW;IACX,KAAO;EACR;AC1EO,MAAM,YAA2B;AAwCxC,MAAM,eAAqD,IAAI,IAAI,UAAU,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAElG,MAAM,QAAQ,OAAO,QAAQ,sBAAmC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM;AGhD1G,MAAA,qBAAA;IACE;MACE,IAAM;MACN,MAAQ;MACR,MAAQ,EAAE,UAAY,SAAS,WAAa,KAAK;MACjD,QAAU,CAAC,EAAE,UAAY,WAAW,WAAa,MAAM,OAAS,OAAO,CAAC;MACxE,OAAS,EAAE,MAAQ,CAAC,MAAM,OAAO,IAAI,GAAG,MAAQ,WAAW,QAAU,UAAU;MAC/E,QAAU,EAAE,MAAQ,KAAK;IAC3B;IACA;MACE,IAAM;MACN,MAAQ;MACR,MAAQ,EAAE,UAAY,YAAY,WAAa,KAAK;MACpD,MAAQ;MACR,OAAS,EAAE,MAAQ,CAAC,MAAM,MAAM,IAAI,GAAG,MAAQ,WAAW,QAAU,UAAU;MAC9E,QAAU,EAAE,MAAQ,KAAK;IAC3B;IACA;MACE,IAAM;MACN,MAAQ;MACR,MAAQ,EAAE,UAAY,YAAY,WAAa,IAAI;MACnD,eAAiB,EAAE,UAAY,SAAS,SAAW,MAAM,UAAY,MAAO,kBAAoB,KAAK;MACrG,OAAS,EAAE,MAAQ,CAAC,KAAK,MAAM,GAAG,GAAG,MAAQ,SAAS,QAAU,WAAW;MAC3E,QAAU,EAAE,MAAQ,KAAK;IAC3B;IACA;MACE,IAAM;MACN,MAAQ;MACR,MAAQ,EAAE,UAAY,WAAW,WAAa,OAAO;MACrD,QAAU,CAAC,EAAE,UAAY,WAAW,WAAa,QAAQ,OAAS,IAAI,CAAC;MACvE,OAAS;MACT,QAAU,EAAE,MAAQ,KAAK;IAC3B;IACA;MACE,IAAM;MACN,MAAQ;MACR,MAAQ,EAAE,UAAY,WAAW,WAAa,MAAM;MACpD,QAAU,CAAC,EAAE,UAAY,WAAW,WAAa,QAAQ,OAAS,IAAI,CAAC;MACvE,OAAS;MACT,QAAU,EAAE,MAAQ,KAAK;IAC3B;IACA;MACE,IAAM;MACN,MAAQ;MACR,MAAQ,EAAE,UAAY,aAAa,WAAa,IAAI;MACpD,MAAQ;MACR,QAAU,EAAE,MAAQ,KAAK;IAC3B;IACA;MACE,IAAM;MACN,MAAQ;MACR,MAAQ,EAAE,UAAY,SAAS,WAAa,KAAO;MACnD,OAAS;MACT,QAAU,EAAE,MAAQ,KAAK;IAC3B;IACA;MACE,IAAM;MACN,MAAQ;MACR,MAAQ,EAAE,UAAY,SAAS,WAAa,KAAM;MAClD,QAAU,EAAE,MAAQ,IAAI;IAC1B;EACF;ACrBO,MAAM,aAA4B;AAQlC,MAAM,cAAc,CAAC,OAAwC,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAEtG,MAAM,YAAY,CAAC,UAAiC,MAAM,UAAU,SAAS,IAAI;AAG1E,MAAM,gBAAgB,CAAC,QAA6B,IAAI,SAAS,IAAI,KAAK,aAAa,IAAI,UAAU,CAAC,GAAG,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,YAAY,UAAU,CAAC,GAAG,CAAC;AAM/J,MAAM,eAAe,CAAC,YAAoB,YAA2C;AAC1F,UAAM,MAAM,YAAY,UAAU;AAClC,QAAI,CAAC,IAAK,OAAM,IAAI,MAAM,qBAAqB,UAAU,GAAG;AAC5D,UAAMC,aAAY,CAAC,OAA2B;AAC5C,YAAM,IAAI,QAAQ,WAAW,IAAI,EAAE,KAAK,UAAU,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AACzE,UAAI,CAAC,EAAG,OAAM,IAAI,MAAM,qBAAqB,EAAE,kBAAkB,UAAU,GAAG;AAC9E,aAAO,EAAE;IACX;AACA,UAAM,OAAO,IAAI,QAAQ;AACzB,UAAM,OAAO,QAAQ,QAAQ,QAAQ;AACrC,UAAM,WAAW,OAAO,IAAI,KAAK,YAAY,OAAOA,WAAU,IAAI,KAAK,QAAQ;AAC/E,UAAM,aAAa,IAAI,UAAU,CAAC,GAAG,OAAO,CAAC,KAAK,MAAM,MAAM,OAAO,EAAE,YAAY,UAAU,CAAC,IAAIA,WAAU,EAAE,QAAQ,GAAG,CAAC;AAC1H,WAAO;MACL,IAAI,QAAQ;MACZ,UAAU,IAAI,KAAK;MACnB,OAAO,EAAE,MAAM,OAAO,MAAM,CAAC,QAAQ,OAAO,QAAQ,QAAQ,cAAc,GAAG,CAAC,EAAE;MAChF,UAAU,QAAQ;MAClB,GAAI,QAAQ,WAAW,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;MACzD,MAAM,WAAW;MACjB,WAAW,IAAI,KAAK,YAAY;MAChC,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC;MAClE,GAAI,IAAI,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI,OAAO,MAAM,CAAC,GAAG,IAAI,MAAM,IAAI,EAAU,EAAE,IAAI,CAAC;MAClF,GAAI,IAAI,gBAAgB,EAAE,eAAe,EAAE,GAAG,IAAI,cAAc,EAAE,IAAI,CAAC;MACvE,GAAI,IAAI,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI,OAAO,EAAE,IAAI,CAAC;MAClD,GAAI,QAAQ,YAAY,EAAE,WAAW,QAAQ,UAAU,IAAI,CAAC;MAC5D,GAAG,QAAQ;IACb;EACF;;;AK9EO,WAAS,YAAY,OAAiC,UAA8B,SAAuC;AAChI,UAAM,OAAO,IAAI,IAAI,MAAM,OAAO,CAAC,SAAS,KAAK,OAAO,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC;AAC/F,UAAM,UAAU,oBAAI,IAAsB;AAC1C,UAAM,WAAW,oBAAI,IAAsB;AAC3C,UAAM,OAAO,CAAC,KAA4B,KAAa,UAAwB;AAC7E,YAAM,OAAO,IAAI,IAAI,GAAG;AACxB,UAAI,KAAM,MAAK,KAAK,KAAK;AAAA,UACpB,KAAI,IAAI,KAAK,CAAC,KAAK,CAAC;AAAA,IAC3B;AACA,eAAW,WAAW,UAAU;AAC9B,UAAI,QAAQ,UAAU,MAAO;AAC7B,UAAI,CAAC,KAAK,IAAI,QAAQ,IAAI,KAAM,QAAQ,OAAO,UAAU,CAAC,KAAK,IAAI,QAAQ,EAAE,EAAI;AACjF,WAAK,SAAS,QAAQ,MAAM,QAAQ,EAAE;AACtC,WAAK,UAAU,QAAQ,IAAI,QAAQ,IAAI;AAAA,IACzC;AACA,UAAM,YAAY,CAAC,OAAwB,KAAK,IAAI,EAAE,GAAG,SAAS;AAClE,UAAM,aAAa,CAAC,OAAwB,KAAK,IAAI,EAAE,KAAK,KAAK,IAAI,EAAE,EAAG,SAAS;AACnF,UAAM,WAAW,oBAAI,IAAoB,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;AACtD,UAAM,QAAQ,CAAC,MAAM;AACrB,aAAS,OAAO,GAAG,OAAO,MAAM,QAAQ,QAAQ;AAC9C,YAAM,UAAU,MAAM,IAAI;AAC1B,UAAI,YAAY,UAAU,UAAU,OAAO,EAAG;AAC9C,iBAAW,SAAS,SAAS,IAAI,OAAO,KAAK,CAAC,GAAG;AAC/C,YAAI,SAAS,IAAI,KAAK,KAAK,CAAC,WAAW,KAAK,EAAG;AAC/C,iBAAS,IAAI,OAAO,SAAS,IAAI,OAAO,IAAK,CAAC;AAC9C,cAAM,KAAK,KAAK;AAAA,MAClB;AAAA,IACF;AACA,UAAM,WAAW,oBAAI,IAAoB;AACzC,UAAM,QAAQ,oBAAI,IAAoB;AACtC,aAAS,OAAO,MAAM,SAAS,GAAG,QAAQ,GAAG,QAAQ;AACnD,YAAM,KAAK,MAAM,IAAI;AACrB,YAAM,SAAS,KAAK,IAAI,EAAE,EAAG,QAAQ,MAAM,SAAS,IAAI,EAAE,KAAK;AAC/D,YAAM,IAAI,IAAI,KAAK;AACnB,YAAM,SAAS,QAAQ,IAAI,EAAE,KAAK,CAAC,GAAG,OAAO,CAAC,UAAU,SAAS,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,IAAK,SAAS,IAAI,EAAE,KAAM,EAAE,UAAU,UAAU,UAAU,KAAK,EAAE;AAClK,iBAAW,SAAS,MAAO,UAAS,IAAI,QAAQ,SAAS,IAAI,KAAK,KAAK,KAAK,QAAQ,MAAM,MAAM;AAAA,IAClG;AACA,WAAO;AAAA,EACT;AAWA,MAAM,YAAY,CAAC,SAAiC,KAAK,SAAS,YAAY,KAAK,SAAS;AAOrF,WAAS,eAAe,OAAiC,UAA8B,SAA6C;AACzI,UAAM,QAAQ,YAAY,OAAO,QAAQ;AACzC,UAAM,QAAQ,oBAAI,IAAoB;AACtC,eAAW,QAAQ,MAAM,OAAO,SAAS,GAAG;AAC1C,iBAAW,CAAC,IAAI,IAAI,KAAK,YAAY,OAAO,UAAU,KAAK,EAAE,GAAG;AAC9D,cAAM,SAAS,MAAM,IAAI,EAAE;AAC3B,YAAI,UAAU,OAAO,UAAU,MAAM,IAAI,EAAE,KAAK,GAAI,OAAM,IAAI,IAAI,OAAO,MAAM;AAAA,MACjF;AAAA,IACF;AACA,UAAM,aAAa,oBAAI,IAAoB;AAC3C,eAAW,QAAQ,OAAO;AACxB,YAAM,OAAO,MAAM,IAAI,KAAK,EAAE;AAC9B,UAAI,SAAS,UAAa,KAAK,SAAS,OAAQ;AAChD,YAAM,SAAS,UAAU,IAAI,IAAI,KAAK,IAAI,IAAI,QAAQ,SAAS,MAAM,IAAI,KAAK,EAAE,KAAK,KAAK,QAAQ,UAAU,IAAI,IAAI,QAAQ;AAC5H,iBAAW,IAAI,KAAK,IAAI,KAAK,IAAI,GAAG,OAAO,MAAM,CAAC;AAAA,IACpD;AACA,WAAO;AAAA,EACT;;;ACvEO,WAAS,YAAY,OAAyB,QAA0D;AAC7G,QAAI,CAAC,OAAO,KAAM,QAAO;AACzB,UAAM,QAAQ,IAAI,IAAkB,MAAM,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC;AACnF,UAAM,WAAW,oBAAI,IAAkB;AACvC,eAAW,SAAS,OAAO,OAAO,EAAG,YAAW,SAAS,MAAM,OAAQ,UAAS,IAAI,MAAM,IAAI,MAAM,IAAI;AACxG,UAAM,QAAQ,MAAM,MAAM,QAAQ,CAAC,SAAS,OAAO,IAAI,KAAK,EAAE,GAAG,UAAU,CAAC,IAAI,CAAC;AACjF,UAAM,WAAsB,CAAC;AAC7B,eAAW,WAAW,MAAM,UAAU;AACpC,YAAM,MAAM,OAAO,IAAI,QAAQ,IAAI;AACnC,YAAM,OAAO,OAAO,IAAI,QAAQ,EAAE;AAClC,YAAM,UAAU,MAAM,IAAI,QAAQ,IAAI;AACtC,YAAM,UAAU,OAAO,KAAK,IAAI,OAAO,CAAC,OAAO,WAAW,QAAQ,SAAS,IAAI,EAAE,GAAI,SAAS,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;AAClH,YAAM,WAAW,OAAQ,QAAQ,SAAS,UAAU,KAAK,MAAO;AAChE,iBAAW,QAAQ,MAAM,IAAI,OAAO,CAAC,QAAQ,IAAI,EAAG,YAAW,MAAM,SAAU,UAAS,KAAK,EAAE,GAAG,SAAS,MAAM,GAAG,CAAC;AAAA,IACvH;AACA,eAAW,SAAS,OAAO,OAAO,EAAG,UAAS,KAAK,GAAG,MAAM,QAAQ;AACpE,WAAO,EAAE,OAAO,SAAS;AAAA,EAC3B;;;ACXA,MAAM,WAAW;AAUjB,WAAS,MAAM,MAAc,IAAY,UAA8B,IAAY,IAAgC;AACjH,QAAI,YAAgC,CAAC,CAAC,MAAM,EAAE,CAAC;AAC/C,eAAWC,YAAW,SAAS,OAAO,CAAC,MAAM,EAAE,KAAK,KAAK,YAAY,EAAE,KAAK,KAAK,QAAQ,GAAG;AAC1F,kBAAY,UAAU,QAAQ,CAAC,CAAC,GAAG,CAAC,MAA0B;AAC5D,YAAIA,SAAQ,MAAM,KAAKA,SAAQ,QAAQ,EAAG,QAAO,CAAC,CAAC,GAAG,CAAC,CAAC;AACxD,eAAO,CAAC,CAAC,GAAG,KAAK,IAAI,GAAGA,SAAQ,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,GAAGA,SAAQ,EAAE,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,MAAO,IAAgB,IAAe,QAAQ;AAAA,MACnI,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAEA,WAAS,QAAQ,MAAc,IAAY,KAAa,MAAsC;AAC5F,UAAM,SAAS,KAAK;AACpB,QAAI,CAAC,OAAQ,QAAO,CAAC,CAAC,MAAM,EAAE,CAAC;AAC/B,UAAM,SAAS,KAAK,SAAS,aAAa,MAAM,MAAM,IAAI,SAAS,IAAI;AACvE,UAAM,OAAiB,CAAC,IAAI;AAC5B,aAASC,MAAK,QAAQ,UAAU,SAASA,MAAK,KAAK,UAAUA,OAAM,OAAQ,MAAK,KAAKA,GAAE;AACvF,SAAK,KAAK,EAAE;AACZ,WAAO,KAAK,MAAM,GAAG,EAAE,EAAE,IAAI,CAAC,OAAO,MAAwB,CAAC,OAAO,KAAK,IAAI,CAAC,CAAE,CAAC,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,MAAM,IAAI,IAAI,QAAQ;AAAA,EACzH;AAMO,WAAS,iBAAiB,MAAqB,UAA8B,MAA6B;AAC/G,UAAM,SAAS,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC;AACxE,UAAM,OAAO,SAAS,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC;AAChD,UAAM,KAAK,SAAS,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC;AAC9C,UAAM,QAA0B,SAAS,CAAC,KAAK,KAAK,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC;AACnG,UAAM,OAAO,KAAK,IAAI,GAAG,KAAK,OAAO,KAAK,KAAK,KAAK,MAAM,KAAK,SAAS,CAAC;AACzE,UAAM,aAAa,KAAK,KAAK,KAAK,MAAM;AACxC,UAAM,QAAgB,CAAC;AACvB,aAAS,MAAM,GAAG,MAAM,MAAM,OAAO;AACnC,YAAM,KAAK,KAAK,KAAK,MAAM;AAC3B,YAAM,KAAK,KAAK,MAAM,MAAM,KAAK;AACjC,iBAAW,CAAC,GAAG,CAAC,KAAK,MAAM,MAAM,IAAI,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,GAAG,IAAI,EAAE,EAAG,YAAW,CAAC,IAAI,EAAE,KAAK,QAAQ,GAAG,GAAG,KAAK,IAAI,EAAG,OAAM,KAAK,EAAE,MAAM,IAAI,IAAI,IAAI,KAAK,IAAI,GAAG,CAAC;AAAA,IACzL;AACA,UAAM,QAAQ,MAAM,OAAO,CAAC,KAAK,SAAS,OAAO,KAAK,KAAK,KAAK,SAAS,KAAK,KAAK,KAAK,KAAK,CAAC;AAC9F,UAAM,MAAM,CAAC,SAAsB,SAAS,CAAC,KAAK,MAAM,MAAM,CAAC,GAAG,KAAK,IAAI,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,KAAK,MAAM,MAAM,CAAC,GAAG,KAAK,EAAE;AAC9H,UAAM,SAAS,MAAM,IAAI,CAAC,MAAM,WAA0B;AAAA,MACxD,IAAI,GAAG,KAAK,EAAE,IAAI,KAAK,aAAa,MAAM,KAAK,GAAG,KAAK,GAAG,IAAI,KAAK;AAAA,MAAI,MAAM,KAAK;AAAA,MAAM,UAAU,KAAK;AAAA,MAAU,MAAM,IAAI,IAAI;AAAA,MAAG,IAAI,KAAK;AAAA,MAAI,IAAI,KAAK;AAAA,MAAI,OAAO,KAAK;AAAA,MACxK,MAAM,OAAO,KAAK,IAAI,KAAM,KAAK,QAAQ,KAAK,KAAK,KAAK,SAAS,KAAK,KAAK,KAAK,MAAO,KAAK,CAAC;AAAA,MAAG,MAAM,KAAK;AAAA,MAAI,UAAU,KAAK;AAAA,MAAU,MAAM;AAAA,IAChJ,EAAE;AACF,UAAM,WAAsB,CAAC;AAC7B,UAAM,QAAQ,CAAC,MAAM,UAAU;AAC7B,UAAI,KAAK,QAAQ,EAAG;AACpB,YAAM,QAAQ,MAAM,IAAI,CAAC,OAAO,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,MAAM,MAAM,QAAQ,KAAK,MAAM,KAAK,KAAK,IAAI,MAAM,IAAI,KAAK,EAAE,IAAI,KAAK,IAAI,MAAM,MAAM,KAAK,IAAI,IAAI,QAAQ;AAClL,iBAAW,EAAE,EAAE,KAAK,MAAO,UAAS,KAAK,EAAE,MAAM,OAAO,KAAK,EAAG,IAAI,IAAI,OAAO,CAAC,EAAG,IAAI,OAAO,KAAK,MAAM,CAAC;AAAA,IAC5G,CAAC;AACD,WAAO,EAAE,QAAQ,UAAU,MAAM,OAAO,OAAO,CAAC,GAAG,MAAM,MAAM,CAAC,EAAG,QAAQ,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,GAAG,KAAK,OAAO,OAAO,CAAC,GAAG,MAAM,MAAM,CAAC,EAAG,QAAQ,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE;AAAA,EAC5K;;;ACtDO,MAAMC,gBAAe;AACrB,MAAMC,kBAAiB;AAC9B,MAAM,YAAY;AASlB,MAAM,UAAU,CAAC,SAA+B;AAC9C,UAAM,SAAS,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC;AACxE,WAAO,SAAS,EAAE,QAAQ,MAAM,KAAK,KAAK,CAAC,GAAG,IAAI,KAAK,KAAK,CAAC,GAAG,OAAO,CAAC,KAAK,KAAK,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,MAAM,KAAK,KAAK,CAAC,GAAG,IAAI,KAAK,KAAK,CAAC,GAAG,OAAO,CAAC,KAAK,KAAK,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC,EAAE;AAAA,EAC9L;AAEA,MAAM,QAAQ,CAAC,OAAc,MAAc,OAAsB,MAAM,SAAS,CAAC,MAAM,MAAM,MAAM,CAAC,GAAG,IAAI,MAAM,MAAM,CAAC,CAAC,IAAI,CAAC,MAAM,MAAM,CAAC,GAAG,MAAM,MAAM,MAAM,CAAC,GAAG,EAAE;AAmB/J,WAAS,gBAAgB,MAAqB,UAA8B,OAA8B;AAC/G,UAAM,QAAQ,QAAQ,IAAI;AAC1B,UAAM,MAAM,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,KAAK,MAAM,EAAE,KAAK,MAAM,OAAO,aAAa,EAAE,OAAO,MAAM,KAAK,SAAS,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI;AACvJ,QAAI,CAAC,IAAI,OAAQ,QAAO,EAAE,QAAQ,CAAC,IAAI,GAAG,UAAU,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,KAAK,EAAE,EAAE;AACxF,UAAM,SAAkB,CAAC;AACzB,UAAM,QAAiB,CAAC;AACxB,UAAM,UAAmB,CAAC;AAC1B,UAAM,YAAmC,CAAC;AAC1C,UAAM,SAAS,KAAK,KAAK,KAAK;AAC9B,QAAI,SAAS,MAAM;AACnB,UAAMC,UAAS,KAAK;AACpB,UAAM,UAAU,CAAC,OAAqB;AACpC,UAAI,KAAK,SAAS,UAAW;AAC7B,YAAM,KAAK,EAAE,IAAI,GAAG,KAAK,EAAE,SAAS,MAAM,MAAM,IAAI,MAAMA,SAAQ,UAAU,KAAK,UAAU,MAAM,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,IAAI,SAAS,KAAK,UAAU,OAAO,CAAC;AAAA,IACzK;AACA,QAAI,QAAQ,CAACC,UAAS,MAAM;AAC1B,cAAQ,KAAK,IAAI,QAAQA,SAAQ,IAAI,CAAC;AACtC,YAAM,YAAY,KAAK,IAAI,KAAK,IAAIA,SAAQ,KAAKH,aAAY;AAC7D,YAAM,aAAa,KAAK,IAAI,MAAM,MAAMG,SAAQ,OAAOF,eAAc;AACrE,YAAM,WAAW,KAAK,IAAI,MAAM,IAAIE,SAAQ,KAAKF,eAAc;AAC/D,YAAM,eAAe,YAAYE,SAAQ;AACzC,UAAIA,SAAQ,KAAK,KAAK,KAAK,UAAW,QAAO,KAAK,EAAE,IAAI,GAAG,KAAK,EAAE,SAAS,CAAC,IAAI,MAAM,aAAa,UAAU,KAAK,UAAU,MAAMA,SAAQ,MAAM,IAAIA,SAAQ,IAAI,IAAI,KAAK,IAAI,IAAIA,SAAQ,IAAI,SAASA,SAAQ,KAAKA,SAAQ,SAASA,SAAQ,KAAK,KAAK,IAAI,CAAC;AAC3P,cAAQ,KAAK,EAAE,IAAI,GAAG,KAAK,EAAE,WAAW,CAAC,IAAI,MAAM,QAAQ,UAAU,MAAM,gBAAgB,MAAM,YAAY,IAAI,UAAU,IAAIA,SAAQ,IAAI,IAAI,WAAW,SAAS,WAAW,cAAc,aAAa,CAAC;AAC1M,gBAAU,KAAK,KAAK,KAAK,YAAY,YAAY,EAAE,IAAI,GAAG,KAAK,EAAE,aAAa,CAAC,IAAI,MAAMD,SAAQ,UAAU,KAAK,UAAU,MAAMC,SAAQ,MAAM,IAAIA,SAAQ,IAAI,IAAI,WAAW,IAAI,KAAK,IAAI,SAASA,SAAQ,KAAKA,SAAQ,SAAS,KAAK,KAAK,WAAW,IAAI,MAAS;AACnQ,eAASA,SAAQ;AAAA,IACnB,CAAC;AACD,YAAQ,MAAM,EAAE;AAEhB,eAAW,QAAQ,OAAO;AACxB,iBAAW,UAAU,SAAS;AAC5B,cAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,IAAI,OAAO,EAAE,IAAI,KAAK,IAAI,KAAK,MAAM,OAAO,IAAI,CAAC;AAC3F,aAAK,UAAU,WAAW,OAAO,KAAK,OAAO;AAAA,MAC/C;AAAA,IACF;AACA,UAAM,MAAM,CAAC,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,OAAO,CAAC,MAAkB,MAAM,MAAS,CAAC;AACrG,UAAM,QAAQ,IAAI,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,QAAQ,CAAC;AACtD,UAAM,SAAS,IAAI,IAAI,CAAC,OAAsB;AAAA,MAC5C,IAAI,EAAE;AAAA,MAAI,MAAM,EAAE;AAAA,MAAM,UAAU,EAAE;AAAA,MAAU,MAAM,MAAM,OAAO,EAAE,MAAM,EAAE,EAAE;AAAA,MAAG,IAAI,EAAE;AAAA,MAAI,IAAI,EAAE;AAAA,MAAI,OAAO,KAAK;AAAA,MAAO,MAAM,OAAO,KAAK,IAAI,KAAM,KAAK,OAAO,EAAE,SAAU,KAAK,CAAC;AAAA,MAAG,MAAM,KAAK;AAAA,MAC/L,GAAI,EAAE,SAAS,SAAU,MAAM,iBAAiB,EAAE,UAAU,MAAM,eAAe,IAAI,CAAC,IAAK,KAAK,WAAW,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;AAAA,IAC5I,EAAE;AACF,UAAM,WAAsB,CAAC;AAC7B,YAAQ,QAAQ,CAAC,QAAQ,MAAM;AAC7B,iBAAW,QAAQ,MAAO,KAAI,KAAK,IAAI,KAAK,IAAI,OAAO,EAAE,IAAI,KAAK,IAAI,KAAK,MAAM,OAAO,IAAI,IAAI,EAAG,UAAS,KAAK,EAAE,MAAM,OAAO,IAAI,IAAI,KAAK,IAAI,OAAO,MAAM,YAAY,CAAC;AAC3K,YAAM,WAAW,UAAU,CAAC;AAC5B,UAAI,SAAU,UAAS,KAAK,EAAE,MAAM,SAAS,IAAI,IAAI,OAAO,IAAI,OAAO,MAAM,UAAU,CAAC;AAAA,IAC1F,CAAC;AACD,UAAM,OAAO,CAAC,GAAG,OAAO,GAAG,OAAO,OAAO,CAAC,MAAM,EAAE,GAAG,SAAS,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE;AACzF,UAAM,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,EAAE,GAAG,GAAG,QAAQ,IAAI,CAAC,GAAG,MAAM,UAAU,CAAC,GAAG,MAAM,EAAE,EAAE,CAAC;AAC1F,WAAO,EAAE,QAAQ,UAAU,MAAM,IAAI;AAAA,EACvC;;;AChGA,MAAM,eAAe;AACrB,MAAM,SAAS,CAAC,SAAiC,KAAK,GAAG,WAAW,OAAO,KAAK,KAAK,aAAa,WAAc,KAAK,SAAS,UAAU,KAAK,SAAS;AAEtJ,WAAS,QAAQ,cAA4B,MAAiC;AAC5E,UAAM,WAAY,aAAa,MAAM,eAAsC;AAC3E,WAAO,EAAE,WAAW,UAAU,MAAM,SAAS,OAAO,qBAAqB,IAAI,aAAa,MAAM,EAAG,OAAO,MAAM,UAAU,KAAK,SAAU;AAAA,EAC3I;AAGA,WAAS,YAAY,OAAyB,WAA8C;AAC1F,UAAM,EAAE,aAAa,IAAI;AACzB,UAAM,SAAS,qBAAqB,IAAI,aAAa,MAAM;AAC3D,UAAM,SAAS,oBAAI,IAAuB;AAC1C,eAAW,QAAQ,MAAM,MAAM,OAAO,MAAM,GAAG;AAC7C,UAAI,aAAa,WAAW,OAAO;AACjC,eAAO,IAAI,KAAK,IAAI,iBAAiB,MAAM,UAAU,UAAU,QAAQ,cAAc,IAAI,CAAC,CAAC;AAC3F;AAAA,MACF;AACA,YAAM,QAAQ,gBAAgB,MAAM,UAAU,UAAU;AAAA,QACtD,gBAAgB,OAAO,SAAS,aAAa,MAAM,SAAS;AAAA,QAAY,GAAI,OAAO,SAAS,CAAC,IAAI,EAAE,gBAAgB,sBAAsB;AAAA,QAAI,aAAa,OAAO,OAAO;AAAA,QAAM,WAAW,OAAO,OAAO;AAAA,MACzM,CAAC;AACD,UAAI,MAAM,OAAO,SAAS,EAAG,QAAO,IAAI,KAAK,IAAI,KAAK;AAAA,IACxD;AACA,WAAO;AAAA,EACT;AAGO,WAAS,YAAY,OAAyB,WAAsB,QAAsC;AAC/G,QAAI,WAAW,SAAU,QAAO;AAChC,WAAO,YAAY,OAAO,YAAY,OAAO,SAAS,CAAC;AAAA,EACzD;AAOO,WAAS,WAAW,OAAc,WAA6B;AACpE,UAAM,SAAS,oBAAI,IAAuB;AAC1C,eAAW,QAAQ,MAAM,OAAO;AAC9B,UAAI,KAAK,QAAQ,CAAC,KAAK,YAAY,KAAK,SAAS,UAAU,KAAK,SAAS,OAAQ;AACjF,YAAM,QAAQ,YAAY,KAAK,QAAQ,GAAG;AAC1C,UAAI,CAAC,MAAO;AACZ,YAAM,QAAQ,qBAAqB,IAAI,UAAU,aAAa,MAAM,EAAG,OAAO;AAC9E,aAAO,IAAI,KAAK,IAAI,iBAAiB,MAAM,CAAC,GAAG,EAAE,WAAW,MAAM,KAAK,CAAC,GAAG,YAAY,MAAM,KAAK,CAAC,GAAG,MAAM,MAAM,MAAM,OAAO,MAAM,WAAW,aAAa,WAAW,OAAO,UAAU,KAAK,SAAS,CAAC,CAAC;AAAA,IAC3M;AACA,UAAM,OAAO,YAAY,OAAO,MAAM;AACtC,UAAM,aAAa,IAAI,IAAI,MAAM,UAAU;AAC3C,eAAW,CAAC,IAAI,KAAK,KAAK,QAAQ;AAChC,YAAM,WAAW,MAAM,WAAW,IAAI,EAAE;AACxC,iBAAW,OAAO,EAAE;AACpB,UAAI,aAAa,OAAW;AAC5B,YAAM,QAAQ,CAAC,QAAsB,KAAK,IAAI,IAAI,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;AAC9E,YAAM,SAAS,MAAM,MAAM,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,EAAE,EAAG,IAAI;AACrE,iBAAW,SAAS,MAAM,OAAQ,YAAW,IAAI,MAAM,IAAI,KAAK,IAAI,GAAI,WAAW,MAAM,MAAM,IAAI,IAAK,MAAM,CAAC;AAAA,IACjH;AACA,WAAO,EAAE,GAAG,MAAM,WAAW;AAAA,EAC/B;;;ACxCA,MAAM,gBAAiD,EAAE,QAAQ,UAAU,MAAM,QAAQ,MAAM,QAAQ,MAAM,QAAQ,WAAW,aAAa,MAAM,QAAQ,OAAO,SAAS,MAAM,OAAO;AAExL,MAAM,iBAAiB;AACvB,MAAM,oBAAoB;AAE1B,MAAM,UAAU,CAAC,MAAqB,aAA2C;AAC/E,UAAM,CAAC,IAAI,IAAI,IAAI,EAAE,IAAI,KAAK;AAC9B,WAAO;AAAA,MACL,IAAI,KAAK;AAAA,MAAI,UAAU,KAAK;AAAA,MAAU,OAAO,EAAE,MAAM,OAAO,MAAM,CAAC,KAAK,IAAI,MAAM,KAAK,EAAE,GAAG,KAAK,IAAI,MAAM,KAAK,KAAK,KAAK,EAAE,GAAG,KAAK,IAAI,MAAM,KAAK,EAAE,CAAC,EAAE;AAAA,MACxJ,UAAU,EAAE,KAAK,MAAM,IAAI,KAAK,KAAK,KAAK,MAAM,IAAI,KAAK,MAAM,CAAC;AAAA,MAAG,MAAM,KAAK,IAAI,KAAK,KAAK,QAAQ,CAAC;AAAA,MACrG,WAAW,aAAa,SAAY,EAAE,MAAM,cAAc,KAAK,IAAI,EAAE,IAAI,EAAE,MAAM,cAAc,KAAK,IAAI,GAAG,SAAS;AAAA,IACtH;AAAA,EACF;AAGA,MAAM,eAAe,CAAC,MAAqB,aAA2C;AACpF,UAAM,CAAC,IAAI,IAAI,IAAI,EAAE,IAAI,KAAK;AAC9B,UAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,UAAM,OAAO,aAAa,KAAK,UAAW;AAAA,MACxC,IAAI,KAAK;AAAA,MAAI,OAAO,SAAS,KAAK,KAAK,KAAK;AAAA,MAAI,QAAQ,KAAK,KAAK,KAAK;AAAA,MAAI,UAAU,EAAE,KAAK,MAAM,IAAI,KAAK,KAAK,KAAK,MAAM,IAAI,KAAK,MAAM,CAAC;AAAA,MAAG,GAAI,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,KAAK,KAAK,GAAG,CAAC,EAAE;AAAA,MAChM,WAAW,aAAa,SAAY,EAAE,MAAM,cAAc,KAAK,IAAI,EAAE,IAAI,EAAE,MAAM,cAAc,KAAK,IAAI,GAAG,SAAS;AAAA,MAAG,OAAO,EAAE,MAAM,KAAK,IAAI,KAAK,KAAK,QAAQ,CAAC,EAAE;AAAA,IACtK,CAAC;AACD,QAAI,KAAK,MAAM;AACb,aAAO,KAAK;AACZ,aAAO,KAAK;AAAA,IACd;AACA,WAAO;AAAA,EACT;AAEA,MAAM,aAAa,CAAC,MAAqB,UAA8B,aAAiC,YAAY,KAAK,WAAW,aAAa,MAAM,QAAQ,IAAI,QAAQ,MAAM,QAAQ;AAOlL,WAAS,mBAAmB,WAAsB,UAAmC,CAAC,GAAqB;AAChH,UAAM,EAAE,SAAS,MAAM,aAAa,MAAM,eAAe,KAAK,IAAI;AAClE,UAAM,OAAO,UAAU,MAAM,OAAO,CAAC,SAAS,CAAC,QAAQ,UAAU,QAAQ,OAAO,IAAI,CAAC;AACrF,UAAM,UAAU,QAAQ,YAAY,QAAQ,eAAe,YAAY,UAAU;AACjF,UAAM,QAAQ,UAAU,KAAK,IAAI,CAAC,SAAyB,KAAK,SAAS,SAAS,EAAE,GAAG,MAAM,MAAM,YAAY,IAAI,IAAK,IAAI;AAC5H,UAAM,MAAM,IAAI,IAAI,MAAM,IAAI,CAAC,SAAS,KAAK,EAAE,CAAC;AAChD,UAAM,WAAW,UAAU,SAAS,OAAO,CAAC,YAAY,CAAC,QAAQ,UAAW,IAAI,IAAI,QAAQ,IAAI,MAAM,QAAQ,OAAO,UAAU,IAAI,IAAI,QAAQ,EAAE,EAAG;AACpJ,UAAM,SAAS,QAAQ,cAAc;AACrC,UAAM,SAAS,YAAY,EAAE,OAAO,OAAO,UAAU,SAAS,GAAG,WAAW,MAAM;AAClF,UAAM,SAAS,EAAE,QAAQ,YAAY,aAAa;AAClD,UAAM,QAAQ,EAAE,GAAG,QAAQ,YAAY,QAAQ,UAAU,QAAQ,oBAAI,IAAoB,IAAI,eAAe,OAAO,OAAO,OAAO,UAAU,MAAM,EAAE;AACnJ,UAAM,EAAE,OAAO,UAAU,WAAW,IAAI,WAAW,UAAU,WAAW,OAAO,SAAS,IAAI;AAC5F,UAAM,QAAQ,MAAM,IAAI,CAAC,SAAS,WAAW,MAAM,WAAW,IAAI,KAAK,EAAE,GAAG,WAAW,QAAQ,CAAC;AAChG,UAAM,SAAS,QAAQ,iBAAiB;AACxC,UAAM,KAAK,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC;AACxD,UAAM,KAAK,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC;AACxD,UAAM,KAAK,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC;AACxD,UAAM,KAAK,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC;AACxD,QAAI,MAAM,OAAQ,OAAM,KAAK,EAAE,IAAI,QAAQ,UAAU,YAAY,OAAO,EAAE,MAAM,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,mBAAmB,KAAK,KAAK,MAAM,EAAE,GAAG,UAAU,EAAE,KAAK,MAAM,GAAG,CAAC,oBAAoB,IAAI,KAAK,MAAM,CAAC,GAAG,IAAI,MAAM,WAAW,EAAE,MAAM,aAAa,GAAG,UAAU,MAAM,MAAM,CAAC,SAAS,EAAE,CAAC;AAC1S,UAAM,UAAU,oBAAI,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,SAAS,KAAK,EAAE,GAAG,MAAM,CAAC;AACjE,UAAM,SAAsB,SAAS,OAAO,CAAC,MAAM,QAAQ,IAAI,EAAE,IAAI,KAAK,QAAQ,IAAI,EAAE,EAAE,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,GAAG,EAAE,MAAM,GAAG,EAAE,IAAI,MAAM,EAAE,OAAO,OAAO,EAAE,UAAU,QAAQ,QAAQ,SAAS,EAAE;AACrN,WAAO,EAAE,MAAM,QAAQ,QAAQ,SAAS,OAAO,OAAO,QAAQ,MAAM,CAAC,aAAa,OAAO,EAAE;AAAA,EAC7F;;;AClEA,MAAM,qBAA6C,EAAE,UAAU,OAAO,iBAAiB,cAAc,mBAAmB,aAAa;AACrI,MAAMC,cAAa;AACnB,MAAM,eAAe;AAErB,WAAS,UAAU,MAAyB,QAAyB;AACnE,WAAO,SAAS,SACZ,EAAE,IAAI,QAAQ,MAAM,MAAM,iBAAiB,MAAM,CAACA,cAAa,GAAG,IAAIA,cAAa,GAAG,IAAI,GAAG,IAAI,SAAS,IAAI,IAC9G,EAAE,IAAI,UAAU,MAAM,MAAM,iBAAiB,MAAM,CAAC,eAAe,GAAG,IAAI,eAAe,GAAG,IAAI,SAAS,MAAM,IAAI,SAAS,IAAI;AAAA,EACtI;AAOO,WAAS,kBAAkB,SAAgD;AAChF,UAAM,EAAE,UAAU,GAAG,GAAG,SAAAC,WAAU,MAAM,SAAS,SAAS,IAAI;AAC9D,UAAM,MAAM,YAAY,QAAQ;AAChC,QAAI,CAAC,IAAK,OAAM,IAAI,MAAM,qBAAqB,QAAQ,GAAG;AAC1D,UAAM,SAAS,mBAAmB,QAAQ,KAAK;AAC/C,UAAM,QAAQ,cAAc,GAAG;AAC/B,UAAM,OAAO,aAAa,UAAU,EAAE,IAAI,iBAAiB,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC,EAAE,QAAQ;AACnH,UAAM,eAAe,qBAAqB,QAAQ,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,GAAG,GAAG,GAAG,MAAM,CAAoB;AACxJ,UAAM,QAAQ,qBAAqB,IAAI,MAAM,EAAG,OAAO;AACvD,UAAM,YAAY;AAAA,MAChB,OAAO,CAAC,EAAE,IAAI,iBAAiB,MAAM,QAAiB,UAAU,IAAI,KAAK,UAAU,MAAM,CAAC,CAAC,IAAI,GAAG,CAAC,QAAQ,GAAG,IAAI,GAAG,QAAQ,CAAC,GAAuC,IAAI,GAAG,IAAI,GAAG,OAAO,GAAG,MAAM,SAAS,CAAC;AAAA,MAC7M,UAAU,CAAC,EAAE,MAAM,iBAAiB,IAAI,QAAQ,MAAM,CAAC;AAAA,MACvD,UAAUA,WAAU,CAAC,UAAUA,UAAS,CAAC,CAAC,IAAI,CAAC;AAAA,MAC/C,QAAQ,CAAC,CAAC;AAAA,MAAG,WAAW;AAAA,MAAG;AAAA,MAAc,QAAQ;AAAA,MACjD,MAAM,EAAE,OAAO,QAAiB,UAAU,IAAI,UAAU,IAAI,OAAO,GAAG,cAAc,GAAG,OAAO,CAAC,GAAG,SAAS,EAAE;AAAA,IAC/G;AACA,WAAO,mBAAmB,WAAW,EAAE,YAAY,QAAQ,OAAO,OAAO,eAAe,KAAK,MAAM,QAAQ,QAAQ,GAAG,CAAC;AAAA,EACzH;;;AnEpDO,MAAM,UAAU;","names":["at","at","item","flight","part","entry","entry","round2","round2","round2","round2","round2","absolute","round2","round2","DOOR_HEIGHT","round2","clamp","densityOf","opening","at","LINTEL_DEPTH","LINTEL_BEARING","roleOf","opening","DOOR_WIDTH","opening"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/registry.ts","../src/geometry.ts","../src/presets.ts","../src/construction.ts","../src/locales/en.json","../src/locales/pt-BR.json","../src/types.ts","../src/density.ts","../src/structure/builder.ts","../src/structure/legacy-key.ts","../src/structure/context.ts","../src/structure/balconies.ts","../src/structure/canvas.ts","../src/structure/extras.ts","../src/structure/floor-deck.ts","../src/structure/foundation.ts","../src/structure/plates.ts","../src/structure/porch.ts","../src/structure/porch-roof.ts","../src/structure/roof.ts","../src/structure/stairs.ts","../src/structure/openings.ts","../src/structure/steps.ts","../src/structure/tank-parts.ts","../src/structure/upper-floor.ts","../src/structure/walls.ts","../src/structure/index.ts","../src/utilities/content-tables.ts","../src/utilities/content.ts","../src/utilities/shared.ts","../src/utilities/wall-points.ts","../src/utilities/electrical-outlets.ts","../src/utilities/electrical-entrance.ts","../src/utilities/electrical-circuits.ts","../src/utilities/electrical.ts","../src/utilities/gas.ts","../src/utilities/plumbing.ts","../src/utilities/solar.ts","../src/utilities/index.ts","../src/utilities/outbuildings.ts","../src/water-tank.ts","../src/viewer-layer.ts","../src/register.ts","../../game-contracts/src/blast-shove.ts","../../game-contracts/src/impact.ts","../../game-contracts/src/body.ts","../../game-contracts/src/spec.ts","../../game-contracts/src/weapons.ts","../../game-contracts/src/ignition.ts","../../game-contracts/src/animation.ts","../../game-contracts/src/tool-animation.ts","../../game-contracts/src/registry.ts","../../game-contracts/src/bench.ts","../../game-contracts/src/environment.ts","../../game-contracts/src/categories.ts","../../game-destruction/src/chain.ts","../../game-destruction/src/math.ts","../../game-destruction/src/fracture.ts","../../game-destruction/src/breach.ts","../../game-destruction/src/layers.ts","../../game-destruction/src/rebar.ts","../../game-destruction/src/flexure.ts","../../game-destruction/src/data/soils.json","../../game-destruction/src/soil.ts","../../game-destruction/src/data/wind-terrain.json","../../game-destruction/src/wind.ts","../../game-destruction/src/data/materials.json","../../game-destruction/src/data/material-hints.json","../../game-destruction/src/materials.ts","../../game-destruction/src/world.ts","../../game-destruction/src/data/assemblies.json","../../game-destruction/src/assemblies.ts","../../game-destruction/src/frame.ts","../../game-destruction/src/size.ts","../../game-destruction/src/locale.ts","../../game-destruction/src/contracts.ts","../src/loads.ts","../src/slab-panels/layout.ts","../src/slab-panels/apply.ts","../src/slab-panels/options.ts","../src/wall-detail/apply.ts","../src/wall-detail/courses.ts","../src/wall-detail/panels.ts","../src/wall-detail/index.ts","../src/to-destructible-spec.ts","../src/wall-specimen.ts","../src/tower.ts","../src/skyscraper.ts","../src/skyscraper-plan.ts"],"sourcesContent":["export const version = '0.1.0'\n\nexport { register } from './register'\nexport type { StructurePackOptions } from './register'\nexport { buildStructure } from './structure'\nexport { PILE_AREA, RAFT_THICKNESS, REBAR_RATIOS, toDestructibleSpec } from './to-destructible-spec'\nexport type { DestructibleSpecOptions } from './to-destructible-spec'\nexport { SLAB_PANEL_DEFAULTS, applySlabPanels, beamDepthFor, beamSpan, resolveSlabPanels, slabPanelView, slabPanelsOf } from './slab-panels'\nexport type { SlabPanelOptions } from './slab-panels'\nexport { buildWallSpecimen } from './wall-specimen'\nexport type { WallSpecimenOptions } from './wall-specimen'\nexport { planWaterTank } from './water-tank'\nexport type { TankPlanOptions } from './water-tank'\nexport {\n CONSTRUCTION_SYSTEMS, CONSTRUCTIONS, ROOF_COVERINGS, registerConstruction, registerConstructionSystem, registerRoofCovering,\n} from './registry'\nexport type { ConstructionBuild, ConstructionBuilder, ConstructionSystemDef, RoofCoveringDef } from './registry'\nexport { campConstruction, chaletConstruction, constructionOfSystem, logCabinConstruction, masonryConstruction, shackConstruction, woodFrameConstruction } from './presets'\nexport type { ChaletOptions, ShackOptions, WoodFrameOptions } from './presets'\nexport { structureLayer } from './viewer-layer'\nexport { DENSITY } from './density'\nexport { GROUND } from './types'\nexport type * from './types'\nexport {\n CORE_DEFAULTS, CURTAIN_DEFAULTS, DAMPER_DEFAULTS, FLAT_ROOF_DEFAULTS, MECHANICAL_DEFAULTS, TOWER_DEFAULTS, addCore, addCurtainWall, addFlatRoof, addMechanicalFloor,\n addTunedMassDamper, buildTower, coreSize, damperMass, towerWater, windExposureOf,\n PUNCHED_DEFAULTS, addPunchedFacade, mechanicalStoreys,\n} from './tower'\nexport type { CoreOptions, CurtainWallOptions, DamperOptions, FlatRoofOptions, MechanicalFloorOptions, PunchedFacadeOptions, TowerGeometry, TowerMechanicalOptions, TowerOptions } from './tower'\nexport { PILE_DEFAULTS, SKYSCRAPER_DEFAULTS, SKYSCRAPER_MAX_STOREYS, buildSkyscraper, pilesFor, skyscraperLayout } from './skyscraper'\nexport type { PileDesign, SkyscraperLayout, SkyscraperOptions, SkyscraperPreset } from './skyscraper'\nexport { PLATE_DEFAULTS, exteriorWindows, planToSpace, splitStrip, storeyKinds, stripDoor, towerFloors, towerLocales, towerPlate } from './skyscraper-plan'\nexport type { PlateOptions, PlateRect, PlateStrip, StoreyContext, StoreyKind, StripFill, StripFiller, StripId, TowerPlanOptions, TowerPlate } from './skyscraper-plan'\n","import type { JointKind } from '@adatechnology/game-contracts'\n\nimport type { Construction, ConstructionSystem, PlanContext, StructureExtras } from './types'\n\n/** What a wall system is made of and how its parts are tied. Timber systems sit on joists, carry the roof on timber plates and have wooden porch posts. */\nexport interface ConstructionSystemDef {\n /** Wall assembly of `game-destruction` (`registerAssembly`) the detailed wall is built from. Empty: no walls (a tent). */\n walls: string\n joints: Record<'wall' | 'slab' | 'beam' | 'column' | 'truss', JointKind>\n /** Thickness of the structural floor under each storey (m). */\n slabThickness: number\n /** Height of the top plate or bond beam (m). */\n plateThickness: number\n timber: boolean\n /** `rules`: bearing when external, under another wall or beside a porch; `bearing`: every wall (logs); `partition`: none (posts carry the roof). */\n wallRole: 'rules' | 'bearing' | 'partition'\n /** Solid fraction of a bearing wall in the structure weight (studs and air). */\n wallFill: number\n studs?: { spacing: number; section: string }\n}\n\nconst uniform = (joint: JointKind): ConstructionSystemDef['joints'] => ({ wall: joint, slab: joint, beam: joint, column: joint, truss: joint })\n\nexport const CONSTRUCTION_SYSTEMS = new Map<string, ConstructionSystemDef>([\n ['masonry', { walls: 'brick_wall_plastered', joints: { wall: 'mortar', slab: 'rebar', beam: 'mortar', column: 'rebar', truss: 'bolt' }, slabThickness: 0.12, plateThickness: 0.2, timber: false, wallRole: 'rules', wallFill: 1 }],\n ['wood_frame', { walls: 'wood_frame_wall', joints: uniform('nail'), slabThickness: 0.28, plateThickness: 0.1, timber: true, wallRole: 'rules', wallFill: 0.35, studs: { spacing: 0.4, section: '38x89' } }],\n ['log', { walls: 'log_wall', joints: { wall: 'bolt', slab: 'nail', beam: 'bolt', column: 'bolt', truss: 'bolt' }, slabThickness: 0.2, plateThickness: 0.1, timber: true, wallRole: 'bearing', wallFill: 1 }],\n ['improvised', { walls: 'sheet_metal_shack', joints: uniform('nail'), slabThickness: 0.2, plateThickness: 0.1, timber: true, wallRole: 'partition', wallFill: 1 }],\n ['canvas', { walls: '', joints: uniform('tie'), slabThickness: 0, plateThickness: 0, timber: false, wallRole: 'partition', wallFill: 1 }],\n])\n\n/** Adds or replaces a construction system (`id` is a `ConstructionSystem` or any name a construction refers to). */\nexport function registerConstructionSystem(id: ConstructionSystem | string, def: ConstructionSystemDef): void {\n CONSTRUCTION_SYSTEMS.set(id, def)\n}\n\nexport interface RoofCoveringDef {\n material: string\n /** How the covering is fixed to the trusses. */\n joint: JointKind\n}\n\nexport const ROOF_COVERINGS = new Map<string, RoofCoveringDef>([\n ['colonial', { material: 'ceramic', joint: 'resting' }],\n ['fiber_cement', { material: 'concrete', joint: 'bolt' }],\n ['slab', { material: 'concrete', joint: 'rebar' }],\n ['asphalt', { material: 'plastic', joint: 'nail' }],\n ['zinc', { material: 'steel', joint: 'nail' }],\n ['wood', { material: 'wood_soft', joint: 'nail' }],\n ['canvas', { material: 'fabric', joint: 'tie' }],\n ['thatch', { material: 'foliage', joint: 'tie' }],\n])\n\nexport function registerRoofCovering(id: string, def: RoofCoveringDef): void {\n ROOF_COVERINGS.set(id, def)\n}\n\nexport interface ConstructionBuild {\n construction: Construction\n extras?: StructureExtras\n}\nexport type ConstructionBuilder = (context: PlanContext) => ConstructionBuild\n\nexport const CONSTRUCTIONS = new Map<string, ConstructionBuilder>()\n\n/** Registers how a template's building is made: `TemplateDef.construction` names it. A template without one gets the masonry default. */\nexport function registerConstruction(id: string, builder: ConstructionBuilder): void {\n CONSTRUCTIONS.set(id, builder)\n}\n","import type { Rect, SourceWall } from './types'\n\nexport const WALL_THICKNESS = 0.15\n\nexport const round2 = (value: number): number => Math.round(value * 100) / 100\n\nexport function touches(a: Rect, b: Rect, tolerance: number): boolean {\n return a[0] < b[2] + tolerance && a[2] > b[0] - tolerance && a[1] < b[3] + tolerance && a[3] > b[1] - tolerance\n}\n\nexport function distanceBetween(a: Rect, b: Rect): number {\n return Math.hypot(Math.max(a[0] - b[2], b[0] - a[2], 0), Math.max(a[1] - b[3], b[1] - a[3], 0))\n}\n\nexport function unionOf(rects: readonly Rect[]): Rect {\n const out: Rect = [1e9, 1e9, -1e9, -1e9]\n for (const rect of rects) {\n out[0] = Math.min(out[0], rect[0])\n out[1] = Math.min(out[1], rect[1])\n out[2] = Math.max(out[2], rect[2])\n out[3] = Math.max(out[3], rect[3])\n }\n return out\n}\n\n/** The wall's centre line thickened to its box in the plan. */\nexport function wallBox(wall: Pick<SourceWall, 'u0' | 'v0' | 'u1' | 'v1' | 'thickness'>): Rect {\n const half = (wall.thickness ?? WALL_THICKNESS) / 2\n return [Math.min(wall.u0, wall.u1) - half, Math.min(wall.v0, wall.v1) - half, Math.max(wall.u0, wall.u1) + half, Math.max(wall.v0, wall.v1) + half]\n}\n\nexport const centreOf = (rect: Rect): [number, number] => [(rect[0] + rect[2]) / 2, (rect[1] + rect[3]) / 2]\n\n/** The nearest `count` of `candidates` to `target`, nearest first. */\nexport function nearestTo<T extends { aabb: Rect }>(target: Rect, candidates: readonly T[], count: number): T[] {\n return candidates.slice().sort((a, b) => distanceBetween(target, a.aabb) - distanceBetween(target, b.aabb)).slice(0, count)\n}\n","import type { Construction, FoundationType, StructureSource } from './types'\nimport { WALL_THICKNESS } from './geometry'\nimport { ROOF_COVERINGS } from './registry'\n\nconst SLAB_COVERING = 'slab'\nconst PLASTERED_FINISHES = ['plaster', 'partial_plaster']\n\n/** Masonry house of the engine's own templates: brick with plaster, concrete frame, tiles by facade; a unit in a building gets a flat slab roof. */\nexport function masonryConstruction(source: StructureSource): Construction {\n const unit = source.floorNumber !== undefined\n const covering = unit ? SLAB_COVERING : (source.facade.roof ?? 'colonial')\n const finish = source.facade.finish ?? 'roughcast'\n const budget = source.style === 'budget'\n const flat = unit || covering === SLAB_COVERING\n return {\n system: 'masonry',\n walls: { material: 'brick', cladding: PLASTERED_FINISHES.includes(finish) ? 'plaster' : null, finish, thickness: WALL_THICKNESS, ...(finish === 'exposed_block' ? { assembly: 'concrete_block_wall' } : {}) },\n floor: { material: budget ? 'concrete' : 'ceramic', finish: budget ? 'burnt_cement' : 'ceramic_tile' },\n roof: { material: ROOF_COVERINGS.get(covering)?.material ?? 'ceramic', covering, shape: flat ? 'slab' : 'gable', pitch: flat ? 0 : covering === 'colonial' ? 30 : 15, timber: 'wood_soft' },\n frame: { material: 'concrete', pillars: 'concrete', beams: 'concrete', slabs: 'concrete', timber: 'wood_soft', rebar: 'steel' },\n foundation: { type: unit ? 'building' : 'strip_footing', material: 'concrete', elevation: 0 },\n }\n}\n\nexport interface WoodFrameOptions {\n foundation?: 'basement' | 'crawl_space' | 'raft'\n covering?: string\n finish?: string\n /** Cladding of the outer face (default soft wood). */\n cladding?: string\n}\n\nconst FOUNDATIONS: Record<NonNullable<WoodFrameOptions['foundation']>, Construction['foundation']> = {\n basement: { type: 'basement', material: 'concrete', elevation: 0.5, depth: 2.4 },\n crawl_space: { type: 'crawl_space', material: 'concrete', elevation: 0.6 },\n raft: { type: 'raft', material: 'concrete', elevation: 0.2 },\n}\n\nconst TIMBER_FRAME: Construction['frame'] = { material: 'wood_soft', pillars: 'wood_soft', beams: 'wood_soft', slabs: 'plywood', timber: 'wood_soft', rebar: null }\n\n/** American wood frame house: 38x89 studs every 40 cm, plaster inside, wood outside, asphalt shingles. */\nexport function woodFrameConstruction(options: WoodFrameOptions = {}): Construction {\n const covering = options.covering ?? 'asphalt'\n return {\n system: 'wood_frame',\n walls: { material: 'wood_soft', interior: 'plaster', cladding: options.cladding ?? 'wood_soft', finish: options.finish ?? 'wood_siding', thickness: WALL_THICKNESS, studs: '38x89 every 40 cm', insulation: 'foam' },\n floor: { material: 'wood_hard', finish: 'wood_boards' },\n roof: { material: ROOF_COVERINGS.get(covering)?.material ?? 'plastic', covering, shape: 'gable', pitch: 28, timber: 'wood_soft', eave: 0.5 },\n frame: { ...TIMBER_FRAME },\n foundation: { ...FOUNDATIONS[options.foundation ?? 'raft'] },\n }\n}\n\nexport interface ChaletOptions {\n covering?: string\n finish?: string\n piles?: boolean\n}\n\n/** Mountain chalet: A-frame roof at 52 degrees with gables front and back, 38x140 studs. */\nexport function chaletConstruction(options: ChaletOptions = {}): Construction {\n const covering = options.covering ?? 'colonial'\n return {\n system: 'wood_frame',\n walls: { material: 'wood_soft', interior: 'wood_soft', cladding: 'wood_hard', finish: options.finish ?? 'vertical_boards', thickness: WALL_THICKNESS, studs: '38x140 every 40 cm' },\n floor: { material: 'wood_hard', finish: 'wood_boards' },\n roof: { material: ROOF_COVERINGS.get(covering)?.material ?? 'wood_soft', covering, shape: 'gable', pitch: 52, timber: 'wood_soft', eave: 0.8, axis: 'v', profile: 'a_frame', gables: ['front', 'back'] },\n frame: { ...TIMBER_FRAME },\n foundation: options.piles ? { type: 'piles', material: 'stone', elevation: 0.9 } : { type: 'raft', material: 'concrete', elevation: 0.2 },\n }\n}\n\n/** Log cabin: every wall is a stack of 26 cm logs, notched at the corners, on stone piles. */\nexport function logCabinConstruction(options: { covering?: string } = {}): Construction {\n const covering = options.covering ?? 'wood'\n return {\n system: 'log',\n walls: { material: 'wood_hard', interior: 'wood_hard', cladding: null, finish: 'log', thickness: WALL_THICKNESS, logDiameter: 0.26, joint: 'notched_corners' },\n floor: { material: 'wood_hard', finish: 'wood_boards' },\n roof: { material: ROOF_COVERINGS.get(covering)?.material ?? 'wood_soft', covering, shape: 'gable', pitch: 32, timber: 'wood_hard', eave: 0.6 },\n frame: { material: 'wood_hard', pillars: 'wood_hard', beams: 'wood_hard', slabs: 'wood_hard', timber: 'wood_hard', rebar: null },\n foundation: { type: 'piles', material: 'stone', elevation: 0.5 },\n }\n}\n\nexport interface ShackOptions {\n material?: 'wood' | 'zinc' | 'mixed'\n floor?: 'soil' | 'concrete'\n}\n\nconst MIXED_SCRAP = ['wood_soft', 'steel', 'plywood', 'steel', 'wood_soft']\n\n/** Shack of scrap boards and zinc sheets: timber posts carry the roof, the walls only close. */\nexport function shackConstruction(options: ShackOptions = {}): Construction {\n const material = options.material === 'zinc' ? 'steel' : 'wood_soft'\n const onSoil = options.floor === 'soil'\n return {\n system: 'improvised',\n walls: { material, interior: options.material === 'zinc' ? 'plywood' : material, cladding: null, finish: 'scrap', thickness: WALL_THICKNESS, ...(options.material === 'mixed' ? { mixed: MIXED_SCRAP } : {}) },\n floor: onSoil ? { material: 'soil', finish: 'packed_earth' } : { material: 'concrete', finish: 'burnt_cement' },\n roof: { material: 'steel', covering: 'zinc', shape: 'gable', pitch: 12, timber: 'wood_soft', eave: 0.3, fastening: 'nails_and_stones' },\n frame: { material: 'wood_soft', pillars: 'wood_soft', beams: 'wood_soft', slabs: 'concrete', timber: 'wood_soft', rebar: null },\n foundation: onSoil ? { type: 'ground', material: 'soil', elevation: 0 } : { type: 'raft', material: 'concrete', elevation: 0.08 },\n }\n}\n\n/** Camping: canvas over aluminium poles on the ground; there are no walls. */\nexport function campConstruction(): Construction {\n return {\n system: 'canvas',\n walls: { material: 'fabric', interior: 'fabric', cladding: null, finish: 'nylon', thickness: 0.002 },\n floor: { material: 'plastic', finish: 'waterproof_mat' },\n roof: { material: 'fabric', covering: 'canvas', shape: 'tent', pitch: 0, timber: 'aluminium', eave: 0 },\n frame: { material: 'aluminium', pillars: 'aluminium', beams: 'aluminium', slabs: 'plastic', timber: 'aluminium', rebar: null },\n foundation: { type: 'ground', material: 'soil', elevation: 0 },\n }\n}\n\n/** The construction a system gets on any plan when the options force it (`options.construction`). */\nexport function constructionOfSystem(system: string, source: StructureSource): Construction | undefined {\n const covering = source.facade.roof\n const keep = covering && covering !== SLAB_COVERING ? { covering } : {}\n switch (system) {\n case 'masonry':\n return masonryConstruction(source)\n case 'wood_frame':\n return woodFrameConstruction(keep)\n case 'log':\n return logCabinConstruction(keep)\n case 'improvised':\n return shackConstruction()\n case 'canvas':\n return campConstruction()\n default:\n return undefined\n }\n}\n\nexport type { FoundationType }\n","import { CONSTRUCTIONS } from './registry'\nimport type { ConstructionBuild } from './registry'\nimport { constructionOfSystem, masonryConstruction } from './presets'\nimport type { PlanContext, StructureSource, Tent } from './types'\n\n/** The construction of a plan: the one it already carries, else the masonry default of the engine's templates. */\nexport function resolveConstruction(source: StructureSource): ConstructionBuild {\n const extras = source.structureExtras ?? {}\n return { construction: source.construction ?? masonryConstruction(source), extras }\n}\n\nconst TENT_LABEL = /^tent_(dome|tunnel)(?:_|$)/\n\n/**\n * Tents of a plan whose template names the `canvas` construction and registers none of its own: one per room of type `tent`, standing on the room's footprint\n * (a label `tent_<kind>_<people>` names the kind, any other is a long tunnel) as high as the room's ceiling.\n */\nexport function tentsOf(source: StructureSource): Tent[] {\n const tents: Tent[] = []\n for (const room of source.rooms) {\n if (room.type !== 'tent' || room.floor !== 0 || !room.parts[0]) continue\n const { label } = room as { label?: unknown }\n tents.push({ id: room.id, kind: TENT_LABEL.exec(typeof label === 'string' ? label : '')?.[1] ?? 'tunnel', height: room.ceiling ?? source.floors[0]?.ceiling ?? 2.4, aabb: room.parts[0] })\n }\n return tents\n}\n\n/**\n * Picks the construction for a plan being generated: `options.construction` (a registered construction or a system name) wins over the template's\n * own (`TemplateDef.construction`), which wins over the masonry default.\n */\nexport function constructionFor(context: PlanContext): ConstructionBuild {\n const forced = context.options?.construction\n const named = typeof forced === 'string' ? forced : (context.template?.construction as string | undefined)\n if (named === undefined) return { construction: masonryConstruction(context.result) }\n const registered = CONSTRUCTIONS.get(named)\n if (registered) return registered(context)\n const preset = constructionOfSystem(named, context.result)\n if (preset) return { construction: preset, ...(named === 'canvas' ? { extras: { tents: tentsOf(context.result) } } : {}) }\n throw new Error(`Unknown construction \"${named}\": register it with registerConstruction`)\n}\n","{\n \"ui\": {\n \"structure_layer\": \"Structure\",\n \"structure_column_concrete\": \"Concrete pillar\",\n \"structure_column_steel\": \"Steel post\",\n \"structure_column_masonry\": \"Masonry pillar\",\n \"structure_column_wood\": \"Wood post\",\n \"structure_beam_concrete\": \"Bond beam / beam (concrete)\",\n \"structure_beam_wood\": \"Plate / beam (wood)\",\n \"structure_roof_frame\": \"Trusses, rafters and ridge (roof view)\"\n },\n \"labels\": {\n \"elevator_lobby\": \"Elevator lobby\",\n \"service_shaft\": \"Service shaft\",\n \"plant_room\": \"Plant room\",\n \"mechanical_floor\": \"Mechanical floor\",\n \"typical_floor\": \"Typical floor\"\n }\n}\n","{\n \"ui\": {\n \"structure_layer\": \"Estrutura\",\n \"structure_column_concrete\": \"Pilar de concreto\",\n \"structure_column_steel\": \"Poste de aço\",\n \"structure_column_masonry\": \"Pilar de alvenaria\",\n \"structure_column_wood\": \"Pilar de madeira\",\n \"structure_beam_concrete\": \"Cinta / viga (concreto)\",\n \"structure_beam_wood\": \"Prato / viga (madeira)\",\n \"structure_roof_frame\": \"Tesouras, caibros e cumeeira (vista do telhado)\"\n },\n \"labels\": {\n \"elevator_lobby\": \"Antessala dos elevadores\",\n \"service_shaft\": \"Shaft de serviço\",\n \"plant_room\": \"Casa de máquinas\",\n \"mechanical_floor\": \"Andar técnico\",\n \"typical_floor\": \"Andar tipo\"\n }\n}\n","import type { JointKind, MaterialId, StructureRole } from '@adatechnology/game-contracts'\n\n/** Axis-aligned rectangle `[u0, v0, u1, v1]` in the plan (metres). */\nexport type Rect = [number, number, number, number]\n\nexport type ConstructionSystem = 'masonry' | 'wood_frame' | 'log' | 'improvised' | 'canvas'\nexport type WallDetail = 'coarse' | 'panels' | 'units'\n/** What a structural part is called in a plan: a column is a pillar, `wall` is a bearing wall, `partition` a wall that only closes. */\nexport type PartRole = Exclude<StructureRole, 'foundation'>\n\nexport const GROUND = 'ground'\n\n/** A piece of the structure with its box in the plan, its height range and the mass it weighs. `y` is absolute: the ground floor sits at `foundation.elevation`. */\nexport interface StructurePart {\n id: string\n role: PartRole\n material: MaterialId\n aabb: Rect\n y0: number\n y1: number\n floor: number\n mass: number\n /** Part this one is cut out of (a pier of a wall in `panels` detail). */\n host?: string\n /** Wall assembly of `game-destruction` the part is built from in the destructible spec (layers, units, rebar, breach). */\n assembly?: string\n /** A brick, block or log: the unit of a wall (`units` detail, log courses), not a piece of it. */\n unit?: true\n /** Distance between repeated members (joists, ceiling joists). */\n spacing?: number\n /** `plate` (timber top plate) or `bond_beam` (masonry bond beam). */\n beamKind?: 'plate' | 'bond_beam'\n steps?: number\n door?: string\n /** Slab that is the roof (flat roof). */\n cover?: boolean\n /** Litres a tank holds. */\n liters?: number\n studs?: { spacing: number; section: string }\n pitch?: number\n tent?: string\n form?: string\n /** Rooms a concrete slab covers (the rectangles of the storey it carries); the slab itself is their bounding box. `toDestructibleSpec` cuts the slab into panels over it. */\n footprint?: Rect[]\n /** Slab the panel, beam or column was made for (`toDestructibleSpec` with `slabPanels`; a `StructurePart` of `buildStructure` never has it). */\n slab?: string\n}\n\n/** `part` rests on `on` (`GROUND` or another part) through `joint`. `bears: false` ties the two without carrying load. */\nexport interface Support {\n part: string\n on: string\n joint: JointKind\n bears?: false\n}\n\nexport interface RoofPane {\n id: string\n aabb: Rect\n y0: number\n y1: number\n flat?: true\n}\n\nexport type RoofShape = 'gable' | 'slab' | 'tent'\n\nexport interface Roof {\n shape: RoofShape\n covering: string\n material: MaterialId\n pitch: number\n /** Floor the roof rests on. */\n bearingFloor: number\n panes: (RoofPane | string)[]\n trusses: number\n axis?: 'u' | 'v'\n ridge?: number\n eave?: number\n y0?: number\n aabb?: Rect\n}\n\n/** A window in a wall (the doors are gaps between walls: a lintel part bridges them). Heights are absolute. */\nexport interface Opening {\n id: string\n kind: 'window' | 'door'\n wall: string\n /** Along the wall (u for a wall along u, v for one along v). */\n from: number\n to: number\n y0: number\n y1: number\n}\n\nexport interface Structure {\n parts: StructurePart[]\n supports: Support[]\n openings: Opening[]\n /** Absolute height of the floor level of each storey. */\n levels: number[]\n elevation: number\n roof: Roof\n construction: Construction\n /** A reinforced concrete frame carries the building (apartments, commercial buildings, three storeys or more); the walls are infill. */\n framed: boolean\n}\n\nexport interface WallMaterials {\n material: MaterialId\n interior?: MaterialId\n cladding?: MaterialId | null\n finish?: string\n /** Wall assembly of `game-destruction` (default by system, and by finish in masonry). */\n assembly?: string\n thickness: number\n studs?: string\n /** Materials drawn per wall by a hash of its legacy key (the improvised shack). */\n mixed?: MaterialId[]\n [extra: string]: unknown\n}\n\nexport interface Construction {\n system: ConstructionSystem\n walls: WallMaterials\n floor: { material: MaterialId; finish: string }\n roof: {\n material: MaterialId\n covering: string\n shape: RoofShape\n pitch: number\n timber: MaterialId\n eave?: number\n axis?: 'u' | 'v'\n bearingFloor?: number\n profile?: string\n gables?: string[]\n fastening?: string\n }\n frame: { material: MaterialId; pillars: MaterialId; beams: MaterialId; slabs: MaterialId; timber: MaterialId; rebar: MaterialId | null }\n foundation: { type: FoundationType; material: MaterialId; elevation: number; depth?: number }\n guard?: MaterialId\n stairs?: MaterialId\n}\n\nexport type FoundationType = 'strip_footing' | 'building' | 'raft' | 'crawl_space' | 'piles' | 'basement' | 'ground'\n\nexport interface Chimney {\n kind: 'fireplace' | 'flue'\n material: MaterialId\n aabb: Rect\n flue?: boolean\n top?: number\n height?: number\n}\n\nexport interface Tent {\n id: string\n kind: string\n height: number\n aabb: Rect\n}\n\n/** What a construction needs besides walls and roof, from the template: a chimney, a well, an attic floor, tents. */\nexport interface StructureExtras {\n chimney?: Chimney\n well?: { aabb: Rect; height?: number }\n attic?: boolean\n tents?: Tent[]\n [extra: string]: unknown\n}\n\nexport interface TankPlatform {\n aabb: Rect\n baseY: number\n height: number\n thickness: number\n topY: number\n pillars: { u: number; v: number; side: number }[]\n ladder: boolean\n}\n\nexport interface WaterTank {\n id: 'water_tank'\n kind: 'water_tank'\n itemType: string\n place: 'slab' | 'attic' | 'raised_slab' | 'trestle' | string\n floor: number\n room: string\n u: number\n v: number\n y: number\n w: number\n d: number\n h: number\n capacity: number\n material?: MaterialId\n aabb: Rect\n platform?: TankPlatform\n /** Trestle tank (a stand of its own: rural water). */\n stand?: { pillars: { u: number; v: number; side: number }[]; material: MaterialId; height: number; baseJoint?: JointKind; joint?: JointKind; tie?: JointKind; braces?: boolean }\n}\n\n/** The fields of a generated plan the structure reads. */\nexport interface StructureSource {\n floors: { y0: number; ceiling: number }[]\n rooms: { id: string; type: string; floor: number; parts: Rect[]; ceiling?: number | null }[]\n walls: SourceWall[]\n doors: SourceDoor[]\n windows?: SourceWindow[]\n items: { id?: string; type: string; category?: string; floor: number; aabb?: Rect; link?: { from: number; to: number } | null }[]\n facade: { roof?: string; finish?: string; [extra: string]: unknown }\n style?: string\n template?: string\n lot?: unknown\n w: number\n d: number\n floorNumber?: number\n waterTank?: WaterTank | null\n construction?: Construction\n structureExtras?: StructureExtras\n [extra: string]: unknown\n}\n\nexport interface SourceWall {\n floor: number\n axis: 'u' | 'v'\n u0: number\n v0: number\n u1: number\n v1: number\n thickness?: number\n sides: string[]\n exterior: boolean\n type: string\n h?: number\n /** Gable wall: the plate does not sit on top of it. */\n gable?: boolean\n structureHeight?: number\n}\n\nexport interface SourceWindow {\n id: string\n floor: number\n axis: 'u' | 'v'\n /** Coordinate of the wall line across its axis. */\n pos: number\n /** Centre along the wall. */\n at: number\n width: number\n y0: number\n y1: number\n}\n\nexport interface SourceDoor {\n id: string\n floor: number\n a: string\n b: string\n exterior?: boolean\n model?: string\n type?: string\n u: number\n v: number\n width: number\n side?: string\n axis: 'u' | 'v'\n steps?: number\n}\n\nexport interface StructureOptions {\n construction?: Construction\n extras?: StructureExtras\n tank?: WaterTank | null\n /** The porch roof is carried by its posts alone (the tie to the house wall carries nothing). Default: when the detail is not `coarse`. */\n porchRoofOnPostsOnly?: boolean\n /** Gable roofs as rafters of each side and a ridge beam (a side falls with the wall it rests on) instead of whole trusses. Default: when the detail is not `coarse`. */\n rafterRoof?: boolean\n wallDetail?: WallDetail\n}\n\n/** What a construction builder and the tank get to see: the generated plan, its seed and the template. */\nexport interface PlanContext {\n result: StructureSource\n seed: number | string\n /** The template definition (`TemplateDef`) when known: it may carry `tank` and `tankLocation` hooks. */\n template?: Record<string, unknown>\n options?: { floors?: number; [extra: string]: unknown }\n}\n","import type { MaterialId } from '@adatechnology/game-contracts'\n\n/** kg/m3 the plan structure weighs its parts with (the table of the Visor de casas 3D; a material outside it weighs like soft wood). */\nexport const DENSITY: Readonly<Record<string, number>> = {\n steel: 7850, cast_iron: 7200, aluminium: 2700, copper: 8900, wood_soft: 500, wood_hard: 800, plywood: 600, mdf: 750, glass: 2500,\n tempered_glass: 2500, ceramic: 2000, concrete: 2400, brick: 1800, plaster: 1000, stone: 2600, plastic: 950, rubber: 1100, fabric: 400,\n foam: 30, leather: 900, paper: 800, foliage: 100, green_wood: 900, cactus: 700, flesh_fruit: 900, wax: 900, soil: 1600,\n}\nexport const DEFAULT_DENSITY = 500\n\nexport const densityOf = (material: MaterialId): number => DENSITY[material] ?? DEFAULT_DENSITY\n","import type { JointKind, MaterialId } from '@adatechnology/game-contracts'\n\nimport { densityOf } from '../density'\nimport { round2 } from '../geometry'\nimport { GROUND } from '../types'\nimport type { PartRole, Rect, StructurePart, Support } from '../types'\n\nexport type PartExtras = Partial<Pick<StructurePart, 'host' | 'spacing' | 'beamKind' | 'steps' | 'door' | 'cover' | 'studs' | 'pitch' | 'tent' | 'form' | 'liters' | 'assembly' | 'footprint'>>\nexport interface PartOptions extends PartExtras {\n floor?: number\n /** Solid fraction of the box (studs, trusses, tile roofs). */\n fill?: number\n}\n\nexport interface PartDraft {\n id: string\n role: PartRole\n material: MaterialId\n aabb: Rect\n y0: number\n y1: number\n}\n\n/** Collects the parts and what each rests on. A part id is unique: a second one is a bug of the builder. */\nexport class StructureBuilder {\n readonly parts: StructurePart[] = []\n readonly supports: Support[] = []\n private readonly ids = new Set<string>()\n\n add(draft: PartDraft, options: PartOptions = {}): StructurePart {\n const { id, role, material, aabb, y0, y1 } = draft\n if (this.ids.has(id)) throw new Error(`Part repeated in the structure: ${id}`)\n this.ids.add(id)\n const { floor, fill, ...extras } = options\n const volume = Math.max(0, (aabb[2] - aabb[0]) * (aabb[3] - aabb[1]) * (y1 - y0)) * (fill ?? 1)\n const part: StructurePart = {\n id, role, material, aabb: aabb.map(round2) as Rect, y0: round2(y0), y1: round2(y1), floor: floor ?? 0,\n mass: Math.max(1, Math.round(volume * densityOf(material))),\n }\n for (const [key, value] of Object.entries(extras)) if (value !== undefined) (part as unknown as Record<string, unknown>)[key] = value\n this.parts.push(part)\n return part\n }\n\n rest(part: StructurePart | string, on: StructurePart | string, joint: JointKind): void {\n const id = typeof part === 'string' ? part : part.id\n const base = typeof on === 'string' ? on : on.id\n this.supports.push({ part: id, on: base === GROUND ? GROUND : base, joint })\n }\n\n has(id: string): boolean {\n return this.ids.has(id)\n }\n\n find(id: string): StructurePart | undefined {\n return this.parts.find((part) => part.id === id)\n }\n}\n","/** The string hash of the floor plan engine (`engine.hashString`), copied so that this package never imports the engine at run time. */\nexport function hashLegacyKey(key: string): number {\n let hash = 1779033703 ^ key.length\n for (let i = 0; i < key.length; i++) {\n hash = Math.imul(hash ^ key.charCodeAt(i), 3432918353)\n hash = (hash << 13) | (hash >>> 19)\n }\n hash = Math.imul(hash ^ (hash >>> 16), 2246822507)\n hash = Math.imul(hash ^ (hash >>> 13), 3266489909)\n return (hash ^ (hash >>> 16)) >>> 0\n}\n","import type { MaterialId } from '@adatechnology/game-contracts'\n\nimport { unionOf, wallBox, round2 } from '../geometry'\nimport { CONSTRUCTION_SYSTEMS } from '../registry'\nimport type { ConstructionSystemDef } from '../registry'\nimport { GROUND } from '../types'\nimport type { Construction, PartRole, Rect, Roof, StructureExtras, StructurePart, StructureSource, WaterTank, SourceWall } from '../types'\nimport { StructureBuilder } from './builder'\nimport { hashLegacyKey } from './legacy-key'\n\nexport const OPEN_ROOM_TYPES: readonly string[] = ['balcony', 'terrace', 'porch']\nconst GUARD_HEIGHT = 1.1\n\nexport interface BuildWall extends SourceWall {\n id: string\n /** The id the Visor de casas 3D gave the wall (`w<floor>_<index>`); seeded choices hash it so old seeds keep their draws. */\n legacyKey: string\n role: PartRole\n material: MaterialId\n box: Rect\n}\n\nexport interface PorchPosts {\n posts: StructurePart[]\n ceilingY: number\n}\n\ntype Base = StructurePart | typeof GROUND | undefined\n\n/** Everything the steps that build the structure share: the plan, the construction, the parts so far and what each storey rests on. */\nexport interface BuildContext {\n source: StructureSource\n construction: Construction\n system: ConstructionSystemDef\n extras: StructureExtras\n tank: WaterTank | null\n builder: StructureBuilder\n porchRoofOnPostsOnly: boolean\n /** Gable roofs are built as rafters of each side plus a ridge beam, so a side falls with the wall it rests on. */\n rafterRoof: boolean\n floorCount: number\n isUnit: boolean\n elevation: number\n isTimber: boolean\n walls: BuildWall[]\n wallParts: Map<string, StructurePart>\n carriers: Map<number, StructurePart[]>\n plates: Map<number, StructurePart[]>\n pillars: Map<number, StructurePart[]>\n porches: Map<string, PorchPosts>\n base0: Base\n houseBox: Rect\n topBox: Rect\n hasBasement: boolean\n topSlab?: StructurePart\n ceilingJoists?: StructurePart[]\n roof: Roof\n level(floor: number): number\n ceilingOf(floor: number): number\n topOf(floor: number): number\n rectsOf(floor: number, exclude?: readonly string[]): Rect[]\n baseOf(floor: number): Base\n}\n\nexport interface ContextOptions {\n porchRoofOnPostsOnly: boolean\n rafterRoof: boolean\n}\n\nexport function createContext(source: StructureSource, construction: Construction, extras: StructureExtras, tank: WaterTank | null, options: ContextOptions): BuildContext {\n const system = CONSTRUCTION_SYSTEMS.get(construction.system)\n if (!system) throw new Error(`Unknown construction system \"${construction.system}\"`)\n const floorCount = source.floors.length\n const isUnit = source.floorNumber !== undefined\n const elevation = construction.foundation.elevation || 0\n const level = (floor: number): number => round2(elevation + (source.floors[floor]?.y0 ?? 0))\n const ceilingOf = (floor: number): number => source.floors[floor]?.ceiling ?? 0\n const topOf = (floor: number): number => (floor < floorCount - 1 && !isUnit ? level(floor + 1) - system.slabThickness : level(floor) + ceilingOf(floor))\n const rectsOf = (floor: number, exclude: readonly string[] = []): Rect[] =>\n source.rooms.filter((room) => room.floor === floor && !exclude.includes(room.type)).flatMap((room) => room.parts)\n const builder = new StructureBuilder()\n const context: BuildContext = {\n source, construction, system, extras, tank, builder, porchRoofOnPostsOnly: options.porchRoofOnPostsOnly, rafterRoof: options.rafterRoof, floorCount, isUnit, elevation, isTimber: system.timber,\n walls: [], wallParts: new Map(), carriers: new Map(), plates: new Map(), pillars: new Map(), porches: new Map(), base0: GROUND,\n houseBox: [0, 0, 0, 0], topBox: [0, 0, 0, 0], hasBasement: false,\n roof: { shape: 'slab', covering: '', material: '', pitch: 0, bearingFloor: 0, panes: [], trusses: 0 },\n level, ceilingOf, topOf, rectsOf,\n baseOf: (floor) => (floor === 0 ? context.base0 : builder.find(`slab_${floor}`)),\n }\n const closed = rectsOf(0, ['balcony', 'porch'])\n context.houseBox = unionOf(closed.length ? closed : rectsOf(0))\n context.walls = classifyWalls(context)\n return context\n}\n\nconst isBearingOnTop = (wall: BuildWall, walls: readonly BuildWall[]): boolean => {\n const along = (w: SourceWall, pick: (a: number, b: number) => number): number => (w.axis === 'u' ? pick(w.u0, w.u1) : pick(w.v0, w.v1))\n const across = (w: SourceWall): number => (w.axis === 'u' ? w.v0 : w.u0)\n return walls.some(\n (other) =>\n other.floor === wall.floor + 1 && other.type === 'wall' && other.axis === wall.axis && Math.abs(across(other) - across(wall)) < 0.2 &&\n Math.min(along(wall, Math.max), along(other, Math.max)) - Math.max(along(wall, Math.min), along(other, Math.min)) > 0.3,\n )\n}\n\nfunction roleOf(context: BuildContext, wall: BuildWall, walls: readonly BuildWall[], porchIds: ReadonlySet<string>): PartRole {\n if (wall.type === 'railing') return 'partition'\n const { wallRole } = context.system\n if (wallRole === 'bearing') return 'wall'\n if (wallRole === 'partition') return 'partition'\n const bearingFloor = context.construction.roof.bearingFloor ?? context.floorCount - 1\n if (wall.floor > bearingFloor) return 'partition'\n if (wall.exterior || wall.sides.some((id) => porchIds.has(id))) return 'wall'\n return wall.floor < context.floorCount - 1 && isBearingOnTop(wall, walls) ? 'wall' : 'partition'\n}\n\nfunction materialOf(context: BuildContext, wall: BuildWall): MaterialId {\n const { walls, guard } = context.construction\n if (wall.type === 'railing') return guard ?? (context.isTimber ? 'wood_soft' : 'steel')\n if (walls.mixed?.length) return walls.mixed[hashLegacyKey(wall.legacyKey) % walls.mixed.length] as MaterialId\n return wall.exterior ? walls.material : (walls.interior ?? walls.material)\n}\n\nfunction classifyWalls(context: BuildContext): BuildWall[] {\n const countByFloor = new Map<number, number>()\n const all: BuildWall[] = context.source.walls.map((wall) => {\n const index = countByFloor.get(wall.floor) ?? 0\n countByFloor.set(wall.floor, index + 1)\n return { ...wall, id: `wall_${wall.floor}_${index}`, legacyKey: `w${wall.floor}_${index}`, role: 'wall', material: '', box: wallBox(wall) }\n })\n const built = all.filter((wall) => wall.type === 'wall' || wall.type === 'railing')\n const porchIds = new Set(context.source.rooms.filter((room) => room.type === 'porch').map((room) => room.id))\n for (const wall of built) {\n wall.role = roleOf(context, wall, built, porchIds)\n wall.material = materialOf(context, wall)\n }\n return built\n}\n\nexport const guardHeightOf = (wall: BuildWall): number => wall.h || GUARD_HEIGHT\n","import { GROUND } from '../types'\nimport { unionOf } from '../geometry'\nimport type { BuildContext } from './context'\n\n/** Cantilevered balconies: a slab tied to the floor of its storey, or on a pillar of its own when it is at ground level. */\nexport function addBalconies(context: BuildContext): void {\n const { builder, construction, system } = context\n for (const room of context.source.rooms.filter((r) => r.type === 'balcony' && r.floor >= 0)) {\n const floor = room.floor\n const box = unionOf(room.parts)\n const base = floor === 0 ? undefined : context.baseOf(floor)\n const deck = builder.add({ id: `slab_${floor}_${room.id}`, role: 'slab', material: construction.frame.slabs, aabb: box, y0: context.level(floor) - system.slabThickness, y1: context.level(floor) }, { floor })\n if (base) {\n builder.rest(deck, base, system.joints.slab)\n continue\n }\n const pillar = builder.add({ id: `balcony_column_${room.id}`, role: 'column', material: construction.frame.pillars, aabb: [box[0] - 0.08, box[1] - 0.08, box[0] + 0.08, box[1] + 0.08], y0: 0, y1: context.level(floor) - system.slabThickness }, { floor: 0 })\n builder.rest(pillar, GROUND, 'rebar')\n builder.rest(deck, pillar, 'rebar')\n }\n}\n","import { GROUND } from '../types'\nimport type { Construction, Rect, Roof, Structure, StructureExtras } from '../types'\nimport { StructureBuilder } from './builder'\n\nconst GROUNDSHEET = 0.02\n\n/** Camping tents: canvas over aluminium poles, a plastic groundsheet and pegs with guy ropes; no walls. */\nexport function buildCanvasStructure(construction: Construction, extras: StructureExtras): Structure {\n const builder = new StructureBuilder()\n const panes: string[] = []\n for (const tent of extras.tents ?? []) {\n const [u0, v0, u1, v1] = tent.aabb\n const centreU = (u0 + u1) / 2\n const centreV = (v0 + v1) / 2\n const sheet = builder.add({ id: `groundsheet_${tent.id}`, role: 'slab', material: 'plastic', aabb: tent.aabb, y0: 0, y1: GROUNDSHEET }, { floor: 0, tent: tent.id })\n builder.rest(sheet, GROUND, 'resting')\n const canvas = builder.add({ id: `canvas_${tent.id}`, role: 'roof', material: 'fabric', aabb: tent.aabb, y0: GROUNDSHEET, y1: tent.height }, { floor: 0, fill: 0.04, tent: tent.id, form: tent.kind })\n panes.push(canvas.id)\n const poles: [Rect, number][] =\n tent.kind === 'tunnel'\n ? [0.25, 0.75].map((fraction, k): [Rect, number] => [[u0 + (u1 - u0) * fraction - 0.015, v0 + 0.05, u0 + (u1 - u0) * fraction + 0.015, v1 - 0.05], k])\n : [[[u0 + 0.05, centreV - 0.015, u1 - 0.05, centreV + 0.015], 0], [[centreU - 0.015, v0 + 0.05, centreU + 0.015, v1 - 0.05], 1]]\n for (const [aabb, k] of poles) {\n const pole = builder.add({ id: `pole_${tent.id}_${k}`, role: 'column', material: construction.frame.pillars, aabb, y0: GROUNDSHEET, y1: tent.height - GROUNDSHEET }, { floor: 0, fill: 0.05, tent: tent.id })\n builder.rest(pole, GROUND, 'resting')\n builder.rest(canvas, pole, 'tie')\n }\n const corners: [number, number][] = [[u0 - 0.2, v0 - 0.2], [u1 + 0.2, v0 - 0.2], [u0 - 0.2, v1 + 0.2], [u1 + 0.2, v1 + 0.2]]\n corners.forEach(([u, v], k) => {\n const peg = builder.add({ id: `peg_${tent.id}_${k}`, role: 'column', material: 'wood_soft', aabb: [u - 0.02, v - 0.02, u + 0.02, v + 0.02], y0: 0, y1: 0.2 }, { floor: 0 })\n builder.rest(peg, GROUND, 'nail')\n builder.rest(canvas, peg, 'tie')\n })\n }\n const roof: Roof = { shape: 'tent', covering: 'canvas', material: 'fabric', pitch: 0, bearingFloor: 0, panes, trusses: 0 }\n return { parts: builder.parts, supports: builder.supports, levels: [0], elevation: 0, roof, construction, framed: false, openings: [] }\n}\n","import { GROUND } from '../types'\nimport { round2, touches } from '../geometry'\nimport type { BuildContext } from './context'\n\nconst CHIMNEY_CLEARANCE_ABOVE_RIDGE = 0.6\n\n/** A masonry chimney or a stove flue next to the house, tied to the wall it touches, rising above the ridge. */\nexport function addChimney(context: BuildContext): void {\n const chimney = context.extras.chimney\n if (!chimney) return\n const { builder } = context\n const top = context.floorCount - 1\n const ridge = context.roof.ridge || context.level(top) + context.ceilingOf(top)\n const height = Math.max(ridge, chimney.top || 0) + CHIMNEY_CLEARANCE_ABOVE_RIDGE\n const part = builder.add({ id: 'chimney', role: 'column', material: chimney.material || 'brick', aabb: chimney.aabb, y0: chimney.flue ? context.level(0) : 0, y1: height }, { floor: 0, fill: chimney.flue ? 0.15 : 0.7 })\n if (chimney.flue) builder.rest(part, context.base0 ?? GROUND, 'resting')\n else builder.rest(part, GROUND, 'mortar')\n const walls = builder.parts.filter((wall) => wall.role === 'wall' && wall.floor === 0 && !wall.id.startsWith('basement') && touches(wall.aabb, part.aabb, 0.1))\n for (const wall of walls) builder.rest(part, wall, 'bolt')\n chimney.height = round2(height)\n}\n\n/** The stone mouth of a well. */\nexport function addWell(context: BuildContext): void {\n const well = context.extras.well\n if (!well) return\n const part = context.builder.add({ id: 'well', role: 'column', material: 'stone', aabb: well.aabb, y0: -0.5, y1: well.height || 0.9 }, { floor: 0, fill: 0.5 })\n context.builder.rest(part, GROUND, 'mortar')\n}\n","import type { JointKind, MaterialId } from '@adatechnology/game-contracts'\n\nimport { distanceBetween, touches } from '../geometry'\nimport type { Rect, StructurePart } from '../types'\nimport type { BuildContext } from './context'\n\nexport interface JoistOptions {\n floor: number\n box: Rect\n thickness: number\n carriers: readonly StructurePart[]\n material: MaterialId\n joint: JointKind\n suffix?: string\n}\n\nconst JOIST_PITCH = 0.6\n\n/** Joists every 0.6 m under the floor of `floor`, each resting on what touches it from below (or the nearest carrier). */\nexport function addJoists(context: BuildContext, options: JoistOptions): StructurePart[] {\n const { floor, box, thickness, carriers, material, joint, suffix = '' } = options\n const length = box[2] - box[0]\n const depth = box[3] - box[1]\n const alongU = length >= depth\n const span = alongU ? length : depth\n const count = Math.max(2, Math.round(span / JOIST_PITCH) + 1)\n const top = context.level(floor) - thickness * 0.15\n const out: StructurePart[] = []\n for (let k = 0; k < count; k++) {\n const centre = (alongU ? box[0] : box[1]) + 0.05 + (k * (span - 0.1)) / (count - 1)\n const aabb: Rect = alongU ? [centre - 0.025, box[1], centre + 0.025, box[3]] : [box[0], centre - 0.025, box[2], centre + 0.025]\n const joist = context.builder.add({ id: `joist_${floor}${suffix}_${k}`, role: 'beam', material, aabb, y0: context.level(floor) - thickness, y1: top }, { floor, fill: 1, spacing: JOIST_PITCH })\n out.push(joist)\n const below = carriers.filter((carrier) => carrier.y0 <= top + 0.05)\n const touching = below.filter((carrier) => touches(aabb, carrier.aabb, 0.2))\n const pool = below.length ? below : carriers\n const chosen = touching.length ? touching : pool.slice().sort((a, b) => distanceBetween(aabb, a.aabb) - distanceBetween(aabb, b.aabb)).slice(0, 1)\n for (const carrier of chosen) context.builder.rest(joist, carrier, joint)\n }\n return out\n}\n\n/** The deck (floor boards, slab) of `floor` on its joists. */\nexport function addDeck(context: BuildContext, id: string, material: MaterialId, options: Pick<JoistOptions, 'floor' | 'box' | 'thickness' | 'joint'>, joists: readonly StructurePart[]): StructurePart {\n const { floor, box, thickness, joint } = options\n const deck = context.builder.add({ id, role: 'slab', material, aabb: box, y0: context.level(floor) - thickness * 0.15, y1: context.level(floor) }, { floor })\n for (const joist of joists) context.builder.rest(deck, joist, joint)\n return deck\n}\n","import type { StructurePart, Rect } from '../types'\nimport { GROUND } from '../types'\nimport type { BuildContext } from './context'\nimport { addDeck, addJoists } from './floor-deck'\n\nconst raft = (context: BuildContext, thickness: number, material: string): StructurePart => {\n const [u0, v0, u1, v1] = context.houseBox\n const part = context.builder.add({ id: 'foundation_raft', role: 'slab', material, aabb: [u0 - 0.1, v0 - 0.1, u1 + 0.1, v1 + 0.1], y0: 0, y1: thickness }, { floor: 0 })\n context.builder.rest(part, GROUND, 'resting')\n return part\n}\n\n/** A unit in a building: the building's pillars go down to the ground and carry a slab under the unit. */\nfunction addBuildingBase(context: BuildContext): void {\n const { builder, construction, houseBox: box } = context\n const corners: [number, number][] = [[box[0], box[1]], [box[2], box[1]], [box[0], box[3]], [box[2], box[3]]]\n const top = context.level(0) - context.system.slabThickness\n const pillars = corners.map(([u, v], k) => {\n const pillar = builder.add({ id: `building_column_${k}`, role: 'column', material: construction.frame.pillars, aabb: [u - 0.15, v - 0.15, u + 0.15, v + 0.15], y0: 0, y1: top }, { floor: 0 })\n builder.rest(pillar, GROUND, 'rebar')\n return pillar\n })\n const slab = builder.add({ id: 'slab_base', role: 'slab', material: construction.frame.slabs, aabb: box, y0: top, y1: context.level(0) }, { floor: 0, footprint: [box] })\n for (const pillar of pillars) builder.rest(slab, pillar, 'rebar')\n context.base0 = slab\n}\n\nfunction addBasement(context: BuildContext): StructurePart[] {\n const { builder, houseBox: box, elevation } = context\n const depth = context.construction.foundation.depth || 2.4\n const floor = builder.add({ id: 'basement_slab', role: 'slab', material: 'concrete', aabb: box, y0: -depth - 0.15, y1: -depth }, { floor: -1 })\n builder.rest(floor, GROUND, 'resting')\n const sides: [string, Rect][] = [\n ['front', [box[0], box[1] - 0.1, box[2], box[1] + 0.1]], ['back', [box[0], box[3] - 0.1, box[2], box[3] + 0.1]],\n ['left', [box[0] - 0.1, box[1], box[0] + 0.1, box[3]]], ['right', [box[2] - 0.1, box[1], box[2] + 0.1, box[3]]],\n ]\n const carried: StructurePart[] = []\n for (const [name, aabb] of sides) {\n const wall = builder.add({ id: `basement_wall_${name}`, role: 'wall', material: 'concrete', aabb, y0: -depth, y1: elevation }, { floor: -1 })\n builder.rest(wall, GROUND, 'rebar')\n builder.rest(wall, floor, 'rebar')\n carried.push(wall)\n }\n const count = Math.max(1, Math.floor((box[2] - box[0]) / 3.0))\n for (let k = 0; k < count; k++) {\n const u = box[0] + ((k + 0.5) * (box[2] - box[0])) / count\n const v = (box[1] + box[3]) / 2\n const column = builder.add({ id: `basement_column_${k}`, role: 'column', material: 'concrete', aabb: [u - 0.15, v - 0.15, u + 0.15, v + 0.15], y0: -depth, y1: elevation - 0.3 }, { floor: -1 })\n builder.rest(column, floor, 'rebar')\n builder.rest(column, GROUND, 'rebar')\n carried.push(column)\n }\n context.hasBasement = true\n return carried\n}\n\n/** Pier footings every ~2 m with a base beam through each line of them (crawl space, piles). */\nfunction addPiers(context: BuildContext): StructurePart[] {\n const { builder, houseBox: box, elevation, construction } = context\n const columns = Math.max(2, Math.ceil((box[2] - box[0]) / 2.0) + 1)\n const rows = Math.max(2, Math.ceil((box[3] - box[1]) / 2.0) + 1)\n const height = Math.max(0.1, elevation - context.system.slabThickness - 0.15)\n const piers: StructurePart[] = []\n for (let j = 0; j < rows; j++) {\n for (let i = 0; i < columns; i++) {\n const u = box[0] + (i * (box[2] - box[0])) / (columns - 1)\n const v = box[1] + (j * (box[3] - box[1])) / (rows - 1)\n const pier = builder.add({ id: `footing_pier_${j}_${i}`, role: 'column', material: construction.foundation.material || 'concrete', aabb: [u - 0.12, v - 0.12, u + 0.12, v + 0.12], y0: 0, y1: height }, { floor: 0 })\n builder.rest(pier, GROUND, 'resting')\n piers.push(pier)\n }\n }\n const alongU = box[2] - box[0] >= box[3] - box[1]\n const beams: StructurePart[] = []\n const lines = alongU ? rows : columns\n for (let line = 0; line < lines; line++) {\n const at = alongU ? box[1] + (line * (box[3] - box[1])) / (rows - 1) : box[0] + (line * (box[2] - box[0])) / (columns - 1)\n const aabb: Rect = alongU ? [box[0], at - 0.07, box[2], at + 0.07] : [at - 0.07, box[1], at + 0.07, box[3]]\n const beam = builder.add({ id: `base_beam_${line}`, role: 'beam', material: construction.frame.timber, aabb, y0: height, y1: elevation - context.system.slabThickness }, { floor: 0 })\n const centre = (q: StructurePart): number => (alongU ? (q.aabb[1] + q.aabb[3]) / 2 : (q.aabb[0] + q.aabb[2]) / 2)\n for (const pier of piers.filter((q) => Math.abs(centre(q) - at) < 0.05)) builder.rest(beam, pier, 'bolt')\n beams.push(beam)\n }\n return beams\n}\n\nfunction addRaisedFloor(context: BuildContext): void {\n const { construction, system, houseBox: box } = context\n const carriers = construction.foundation.type === 'basement' ? addBasement(context) : addPiers(context)\n const thickness = system.slabThickness\n const joists = addJoists(context, { floor: 0, box, thickness, carriers, material: construction.frame.timber, joint: construction.foundation.type === 'basement' ? 'bolt' : 'nail' })\n const deckMaterial = context.isTimber ? (construction.floor.material === 'wood_hard' ? 'wood_hard' : 'plywood') : construction.frame.slabs\n context.base0 = addDeck(context, 'slab_0', deckMaterial, { floor: 0, box, thickness, joint: 'nail' }, joists)\n}\n\n/** Foundation and floor of the ground storey: raft, crawl space, piles, basement, a unit's building base or nothing (strip footing). */\nexport function addFoundation(context: BuildContext): void {\n const { type, material } = context.construction.foundation\n if (context.isUnit) return addBuildingBase(context)\n if (type === 'raft') context.base0 = raft(context, Math.max(0.1, context.elevation), material || 'concrete')\n else if (type === 'crawl_space' || type === 'piles' || type === 'basement') addRaisedFloor(context)\n else if (context.isTimber && type !== 'ground') context.base0 = raft(context, Math.max(0.12, context.elevation), 'concrete')\n}\n","import { GROUND } from '../types'\nimport type { Rect, StructurePart } from '../types'\nimport { round2, touches } from '../geometry'\nimport type { BuildContext, BuildWall } from './context'\n\nconst MAX_GAP_WITHIN_RUN = 3.2\nconst POST_SPACING = 2.4\nconst POST_SIDE = 0.05\n\ninterface Run {\n from: number\n to: number\n walls: BuildWall[]\n}\n\nconst alongOf = (wall: BuildWall, pick: (a: number, b: number) => number): number => (wall.axis === 'u' ? pick(wall.u0, wall.u1) : pick(wall.v0, wall.v1))\nconst acrossOf = (wall: BuildWall): number => (wall.axis === 'u' ? wall.v0 : wall.u0)\n\n/** Continuous runs of exterior wall on one line and height: a plate or bond beam runs along each. */\nfunction runsOf(context: BuildContext, walls: readonly BuildWall[], floor: number): Run[][] {\n const lines = new Map<string, BuildWall[]>()\n for (const wall of walls) {\n if (!wall.exterior || wall.type !== 'wall') continue\n const top = round2(context.wallParts.get(wall.id)!.y1)\n const key = `${floor}|${wall.axis}|${acrossOf(wall).toFixed(2)}|${top.toFixed(2)}`\n lines.set(key, [...(lines.get(key) ?? []), wall])\n }\n return [...lines.values()].map((line) => {\n const sorted = line.slice().sort((a, b) => alongOf(a, Math.min) - alongOf(b, Math.min))\n const runs: Run[] = []\n for (const wall of sorted) {\n const from = alongOf(wall, Math.min)\n const to = alongOf(wall, Math.max)\n const last = runs[runs.length - 1]\n if (last && from - last.to <= MAX_GAP_WITHIN_RUN) {\n last.to = Math.max(last.to, to)\n last.walls.push(wall)\n } else runs.push({ from, to, walls: [wall] })\n }\n return runs\n })\n}\n\n/** Timber posts of a shack: the corner and every ~2.4 m carry the plate; the sheet walls only close. */\nfunction addShackPosts(context: BuildContext, run: Run, plate: StructurePart, floor: number, index: number): StructurePart[] {\n const first = run.walls[0]!\n const across = acrossOf(first)\n const top = context.wallParts.get(first.id)!.y1\n const count = Math.max(1, Math.ceil((run.to - run.from) / POST_SPACING))\n const posts: StructurePart[] = []\n for (let k = 0; k <= count; k++) {\n const along = run.from + ((run.to - run.from) * k) / count\n const [u, v] = first.axis === 'u' ? [along, across] : [across, along]\n const half = 0.05 + POST_SIDE / 2\n const post = context.builder.add({ id: `post_${floor}_${index}_${k}`, role: 'column', material: 'wood_soft', aabb: [u - half, v - half, u + half, v + half], y0: context.level(floor), y1: top }, { floor })\n const base = context.baseOf(floor)\n if (base === GROUND || !base) context.builder.rest(post, GROUND, 'tie')\n else context.builder.rest(post, base, 'nail')\n context.builder.rest(plate, post, 'nail')\n posts.push(post)\n }\n return posts\n}\n\nexport interface PlatesResult {\n plates: StructurePart[]\n pillars: StructurePart[]\n}\n\nfunction addPlates(context: BuildContext, walls: readonly BuildWall[], floor: number): PlatesResult {\n const { builder, system, construction } = context\n const plates: StructurePart[] = []\n const pillars: StructurePart[] = []\n let counter = 0\n for (const runs of runsOf(context, walls, floor)) {\n for (const run of runs) {\n const first = run.walls[0]!\n const half = (first.thickness ?? 0.15) / 2\n const across = acrossOf(first)\n const top = context.wallParts.get(first.id)!.y1\n const aabb: Rect = first.axis === 'u' ? [run.from - half, across - half, run.to + half, across + half] : [across - half, run.from - half, across + half, run.to + half]\n const material = context.isTimber ? construction.frame.timber : construction.frame.beams\n const plate = builder.add({ id: `plate_${floor}_${counter++}`, role: 'beam', material, aabb, y0: top, y1: top + system.plateThickness }, { floor, beamKind: context.isTimber ? 'plate' : 'bond_beam' })\n if (construction.system === 'improvised') pillars.push(...addShackPosts(context, run, plate, floor, counter))\n else for (const wall of run.walls) builder.rest(plate, context.wallParts.get(wall.id)!, system.joints.beam)\n plates.push(plate)\n }\n }\n return { plates, pillars }\n}\n\nfunction cornerPoints(walls: readonly BuildWall[]): [number, number][] {\n const ends = walls\n .filter((wall) => wall.exterior && wall.type === 'wall')\n .flatMap((wall): [number, number, string][] =>\n wall.axis === 'u'\n ? [[Math.min(wall.u0, wall.u1), wall.v0, 'u'], [Math.max(wall.u0, wall.u1), wall.v0, 'u']]\n : [[wall.u0, Math.min(wall.v0, wall.v1), 'v'], [wall.u0, Math.max(wall.v0, wall.v1), 'v']],\n )\n const points: [number, number][] = []\n for (const a of ends) {\n const joinsOtherAxis = ends.some((b) => b[2] !== a[2] && Math.hypot(a[0] - b[0], a[1] - b[1]) < 0.12)\n if (joinsOtherAxis && !points.some((q) => Math.hypot(q[0] - a[0], q[1] - a[1]) < 0.12)) points.push([a[0], a[1]])\n }\n return points\n}\n\n/** Concrete corner pillars of a masonry storey where two exterior walls of different axes meet; they run up to the highest plate they touch. */\nfunction addCornerPillars(context: BuildContext, walls: readonly BuildWall[], floor: number, plates: readonly StructurePart[]): StructurePart[] {\n const { builder } = context\n const topOfFloor = context.topOf(floor)\n return cornerPoints(walls).map(([u, v], k) => {\n const box: Rect = [u - 0.1, v - 0.1, u + 0.1, v + 0.1]\n const top = Math.max(topOfFloor, ...plates.filter((plate) => touches(plate.aabb, box, 0.05)).map((plate) => plate.y0))\n const pillar = builder.add({ id: `column_${floor}_${k}`, role: 'column', material: context.construction.frame.pillars, aabb: box, y0: context.level(floor), y1: top }, { floor })\n const base = context.baseOf(floor)\n builder.rest(pillar, base === GROUND || !base ? GROUND : base, 'rebar')\n for (const plate of plates.filter((p) => touches(p.aabb, pillar.aabb, 0.05))) builder.rest(plate, pillar, 'rebar')\n return pillar\n })\n}\n\n/** Plates (bond beams) over the exterior walls of a storey and, in masonry, the corner pillars; records what carries the storey above. */\nexport function addPlatesAndPillars(context: BuildContext, floor: number): void {\n const walls = context.walls.filter((wall) => wall.floor === floor)\n const { plates, pillars } = addPlates(context, walls, floor)\n if (context.construction.system === 'masonry') pillars.push(...addCornerPillars(context, walls, floor, plates))\n context.pillars.set(floor, pillars)\n context.plates.set(floor, plates)\n const innerBearing = walls.filter((wall) => wall.role === 'wall' && !wall.exterior).map((wall) => context.wallParts.get(wall.id)!)\n context.carriers.set(floor, [...plates, ...pillars, ...innerBearing])\n}\n","import { GROUND } from '../types'\nimport type { Rect, StructurePart } from '../types'\nimport { touches } from '../geometry'\nimport type { BuildContext } from './context'\n\nconst POST_HALF = 0.08\nconst FOOTING_HALF = 0.12\nconst BEAM_DEPTH = 0.2\nconst BEAM_WIDTH = 0.16\n\n/** Footings and posts under the porch roof: two at the front corners and one more in the middle of a wide porch. */\nfunction addPosts(context: BuildContext, porchId: string, rect: Rect, deck: StructurePart, floor: number): StructurePart[] {\n const { builder, construction } = context\n const hasUpperFloor = floor < context.floorCount - 1\n const ceilingY = hasUpperFloor ? context.level(floor + 1) - context.system.slabThickness : context.level(floor) + context.ceilingOf(floor)\n const deckDepth = Math.min(0.2, Math.max(0.06, context.elevation * 0.5))\n const spots: [number, number][] = [[rect[0] + 0.1, rect[1] + 0.1], [rect[2] - 0.1, rect[1] + 0.1]]\n if (rect[2] - rect[0] > 4.5) spots.push([(rect[0] + rect[2]) / 2, rect[1] + 0.1])\n const posts = spots.map(([u, v], k) => {\n const footing = builder.add({ id: `porch_footing_${porchId}_${k}`, role: 'column', material: 'concrete', aabb: [u - FOOTING_HALF, v - FOOTING_HALF, u + FOOTING_HALF, v + FOOTING_HALF], y0: 0, y1: context.level(floor) - deckDepth }, { floor: 0 })\n builder.rest(footing, GROUND, 'resting')\n builder.rest(deck, footing, 'resting')\n const material = context.isTimber ? construction.frame.timber : construction.frame.pillars\n const post = builder.add({ id: `porch_post_${porchId}_${k}`, role: 'column', material, aabb: [u - POST_HALF, v - POST_HALF, u + POST_HALF, v + POST_HALF], y0: context.level(floor), y1: hasUpperFloor ? ceilingY - BEAM_DEPTH : ceilingY }, { floor })\n builder.rest(post, deck, context.isTimber ? 'nail' : 'rebar')\n return post\n })\n context.porches.set(porchId, { posts, ceilingY })\n return posts\n}\n\n/** With a storey above the porch, a head beam over the posts and two side beams carry the floor of that storey. */\nfunction addUpperBeams(context: BuildContext, porchId: string, rect: Rect, posts: StructurePart[], floor: number): void {\n const { builder, construction } = context\n const material = context.isTimber ? construction.frame.timber : construction.frame.beams\n const joint = context.isTimber ? 'nail' : 'rebar'\n const ceilingY = context.porches.get(porchId)!.ceilingY\n const y0 = ceilingY - BEAM_DEPTH\n const carriers = context.carriers.get(floor)!\n const head = builder.add({ id: `porch_beam_${porchId}`, role: 'beam', material, aabb: [rect[0], rect[1], rect[2], rect[1] + BEAM_WIDTH], y0, y1: ceilingY }, { floor })\n for (const post of posts) builder.rest(head, post, joint)\n carriers.push(head)\n const sides: [string, Rect, StructurePart][] = [['e', [rect[0], rect[1], rect[0] + BEAM_WIDTH, rect[3]], posts[0]!], ['d', [rect[2] - BEAM_WIDTH, rect[1], rect[2], rect[3]], posts[1]!]]\n for (const [name, aabb, post] of sides) {\n const side = builder.add({ id: `porch_beam_${porchId}_${name}`, role: 'beam', material, aabb, y0, y1: ceilingY }, { floor })\n builder.rest(side, post, joint)\n builder.rest(side, head, joint)\n for (const wall of context.walls.filter((w) => w.floor === floor && w.role === 'wall' && touches(w.box, side.aabb, 0.3))) builder.rest(side, context.wallParts.get(wall.id)!, joint)\n carriers.push(side)\n }\n}\n\n/** Deck, footings, posts (concrete in masonry, wood in timber houses) and, with a storey above, the beams of every porch of the storey. */\nexport function addPorches(context: BuildContext, floor: number): void {\n const { builder, construction } = context\n for (const room of context.source.rooms.filter((r) => r.type === 'porch' && r.floor === floor)) {\n const rect = room.parts[0]!\n const base = context.baseOf(floor)\n const deckDepth = Math.min(0.2, Math.max(0.06, context.elevation * 0.5))\n const deck = builder.add({ id: `porch_floor_${room.id}`, role: 'slab', material: context.isTimber ? 'wood_soft' : construction.frame.slabs, aabb: rect, y0: context.level(floor) - deckDepth, y1: context.level(floor) }, { floor })\n if (base && base !== GROUND) builder.rest(deck, base, context.isTimber ? 'nail' : context.system.joints.slab)\n const posts = addPosts(context, room.id, rect, deck, floor)\n if (floor < context.floorCount - 1) addUpperBeams(context, room.id, rect, posts, floor)\n }\n}\n","import { ROOF_COVERINGS } from '../registry'\nimport type { BuildContext } from './context'\n\nconst ROOF_RISE = 0.6\n\n/** A porch under the top storey has a roof of its own, resting on its posts and on the wall of the house. */\nexport function addPorchRoofs(context: BuildContext): void {\n const { builder, construction } = context\n for (const room of context.source.rooms.filter((r) => r.type === 'porch')) {\n const floor = room.floor\n const rect = room.parts[0]!\n const posts = context.porches.get(room.id)\n if (floor !== context.floorCount - 1 || !posts) continue\n const material = ROOF_COVERINGS.get(construction.roof.covering)?.material ?? 'ceramic'\n const roof = builder.add({ id: `porch_roof_${room.id}`, role: 'roof', material, aabb: [rect[0] - 0.3, rect[1] - 0.5, rect[2] + 0.3, rect[3]], y0: posts.ceilingY, y1: posts.ceilingY + ROOF_RISE }, { floor })\n for (const post of posts.posts) builder.rest(roof, post, context.isTimber ? 'nail' : 'bolt')\n const housewalls = context.walls.filter((w) => w.floor === floor && !w.exterior && w.sides.includes(room.id) && w.type === 'wall')\n for (const wall of housewalls) {\n if (context.porchRoofOnPostsOnly) builder.supports.push({ part: roof.id, on: wall.id, joint: 'nail', bears: false })\n else builder.rest(roof, context.wallParts.get(wall.id)!, 'nail')\n }\n }\n}\n","import type { JointKind } from '@adatechnology/game-contracts'\n\nimport { distanceBetween, round2, touches, unionOf } from '../geometry'\nimport { ROOF_COVERINGS } from '../registry'\nimport type { Rect, RoofPane, StructurePart } from '../types'\nimport type { BuildContext } from './context'\nimport { OPEN_ROOM_TYPES } from './context'\n\nconst TRUSS_PITCH = 1.2\nconst DEFAULT_PITCH = 20\nconst DEFAULT_EAVE = 0.4\nconst CLOSED_ONLY: readonly string[] = [...OPEN_ROOM_TYPES, 'void']\n\ninterface RoofUnit {\n suffix: string\n box: Rect\n floor: number\n annex: boolean\n}\n\n/** The main roof, plus an own roof for every room of a lower storey that the storey above does not cover (a ground floor wider than the upper one). */\nfunction roofUnits(context: BuildContext, bearing: number): RoofUnit[] {\n const units: RoofUnit[] = [{ suffix: '', box: context.topBox, floor: bearing, annex: false }]\n if (context.floorCount <= 1 || context.isUnit || bearing !== context.floorCount - 1) return units\n for (let floor = 0; floor < context.floorCount - 1; floor++) {\n const above = context.source.rooms.filter((room) => room.floor === floor + 1).flatMap((room) => room.parts)\n const rooms = context.source.rooms.filter((room) => room.floor === floor && !OPEN_ROOM_TYPES.includes(room.type) && room.type !== 'void' && room.type !== 'elevator')\n for (const room of rooms) {\n const area = room.parts.reduce((total, part) => total + (part[2] - part[0]) * (part[3] - part[1]), 0)\n const covered = room.parts.reduce((total, part) => total + above.reduce((sum, other) => sum + Math.max(0, Math.min(part[2], other[2]) - Math.max(part[0], other[0])) * Math.max(0, Math.min(part[3], other[3]) - Math.max(part[1], other[1])), 0), 0)\n if (covered < area * 0.7) units.push({ suffix: `_${room.id}`, box: unionOf(room.parts), floor, annex: true })\n }\n }\n return units\n}\n\n/** Everything that carries the roof of one unit: the plates at its height, the pillars and the inner bearing walls under it. */\nfunction roofCarriers(context: BuildContext, unit: RoofUnit): StructurePart[] {\n const platesHere = context.plates.get(unit.floor) ?? []\n const allPlates = [...context.plates.values()].flat()\n const eaveHeight = platesHere.length ? Math.max(...platesHere.map((plate) => plate.y1)) : 0\n const plates = allPlates.filter((plate) => Math.abs(plate.y1 - eaveHeight) < 0.4 && touches(plate.aabb, unit.box, 0.3))\n const pillars = (context.pillars.get(unit.floor) ?? []).filter((pillar) => touches(pillar.aabb, unit.box, 0.3))\n const walls = context.walls.filter((wall) => wall.floor === unit.floor && wall.role === 'wall' && !wall.exterior && touches(wall.box, unit.box, 0.2)).map((wall) => context.wallParts.get(wall.id)!)\n return [...plates, ...pillars, ...walls]\n}\n\nfunction addFlatRoof(context: BuildContext, unit: RoofUnit, carriers: StructurePart[]): RoofPane {\n const { builder, construction, system } = context\n const top = context.level(unit.floor) + context.ceilingOf(unit.floor)\n const [u0, v0, u1, v1] = unit.box\n const slab = builder.add({ id: `slab_top${unit.suffix}`, role: 'slab', material: construction.frame.slabs, aabb: [u0 - 0.15, v0 - 0.15, u1 + 0.15, v1 + 0.15], y0: top, y1: top + 0.12 }, { floor: unit.floor, cover: true, footprint: [unit.box] })\n for (const carrier of carriers.length ? carriers : (context.plates.get(unit.floor) ?? [])) builder.rest(slab, carrier, system.joints.slab)\n if (unit.suffix === '') context.topSlab = slab\n return { id: slab.id, aabb: slab.aabb, y0: slab.y0, y1: slab.y1, flat: true }\n}\n\nfunction addTrusses(context: BuildContext, unit: RoofUnit, carriers: StructurePart[], geometry: GableGeometry): StructurePart[] {\n const { builder, construction, system } = context\n const { box } = unit\n const { axis, length, eave, rise, eaveY } = geometry\n const count = Math.max(2, Math.ceil(length / TRUSS_PITCH) + 1)\n const trusses: StructurePart[] = []\n for (let k = 0; k < count; k++) {\n const at = (axis === 'u' ? box[0] : box[1]) + (k * length) / (count - 1)\n const aabb: Rect = axis === 'u' ? [at - 0.04, box[1] - eave * 0.5, at + 0.04, box[3] + eave * 0.5] : [box[0] - eave * 0.5, at - 0.04, box[2] + eave * 0.5, at + 0.04]\n const truss = builder.add({ id: `truss${unit.suffix}_${k}`, role: 'beam', material: construction.frame.timber, aabb, y0: eaveY, y1: eaveY + rise }, { floor: unit.floor, fill: 0.25 })\n const touching = carriers.filter((carrier) => touches(aabb, carrier.aabb, 0.2) && carrier.role !== 'slab')\n const chosen = touching.length ? touching : carriers.slice().sort((a, b) => distanceBetween(aabb, a.aabb) - distanceBetween(aabb, b.aabb)).slice(0, 2)\n for (const carrier of chosen) builder.rest(truss, carrier, system.joints.truss)\n trusses.push(truss)\n }\n return trusses\n}\n\ninterface GableGeometry {\n axis: 'u' | 'v'\n length: number\n eave: number\n rise: number\n eaveY: number\n}\n\nfunction geometryOf(context: BuildContext, unit: RoofUnit): GableGeometry {\n const { box } = unit\n const roof = context.construction.roof\n const platesHere = context.plates.get(unit.floor) ?? []\n const width = box[2] - box[0]\n const depth = box[3] - box[1]\n const axis = roof.axis ?? (width >= depth ? 'u' : 'v')\n const span = axis === 'u' ? depth : width\n const pitch = unit.annex ? Math.min(roof.pitch || DEFAULT_PITCH, 20) : roof.pitch || DEFAULT_PITCH\n const eaveY = platesHere.length ? Math.max(...platesHere.map((plate) => plate.y1)) : context.level(unit.floor) + context.ceilingOf(unit.floor)\n return { axis, length: axis === 'u' ? width : depth, eave: roof.eave ?? DEFAULT_EAVE, rise: round2((span / 2) * Math.tan((pitch * Math.PI) / 180)), eaveY }\n}\n\ninterface Frames {\n all: StructurePart[]\n sideA: StructurePart[]\n sideB: StructurePart[]\n}\n\n/** Rafters of each side at the truss positions, each resting only on what is under its own side, and a ridge beam that rests on all of them. */\nfunction addRafters(context: BuildContext, unit: RoofUnit, carriers: StructurePart[], geometry: GableGeometry): Frames {\n const { builder, construction, system } = context\n const { box } = unit\n const { axis, length, eave, rise, eaveY } = geometry\n const count = Math.max(2, Math.ceil(length / TRUSS_PITCH) + 1)\n const middle = axis === 'u' ? (box[1] + box[3]) / 2 : (box[0] + box[2]) / 2\n const frames: Frames = { all: [], sideA: [], sideB: [] }\n for (let k = 0; k < count; k++) {\n const at = (axis === 'u' ? box[0] : box[1]) + (k * length) / (count - 1)\n const halves: [string, Rect][] =\n axis === 'u'\n ? [['a', [at - 0.04, box[1] - eave * 0.5, at + 0.04, middle]], ['b', [at - 0.04, middle, at + 0.04, box[3] + eave * 0.5]]]\n : [['a', [box[0] - eave * 0.5, at - 0.04, middle, at + 0.04]], ['b', [middle, at - 0.04, box[2] + eave * 0.5, at + 0.04]]]\n for (const [side, aabb] of halves) {\n const rafter = builder.add({ id: `rafter${unit.suffix}_${side}_${k}`, role: 'beam', material: construction.frame.timber, aabb, y0: eaveY, y1: eaveY + rise }, { floor: unit.floor, fill: 0.25 })\n const touching = carriers.filter((carrier) => touches(aabb, carrier.aabb, 0.2) && carrier.role !== 'slab')\n const chosen = touching.length ? touching : carriers.slice().sort((x, y) => distanceBetween(aabb, x.aabb) - distanceBetween(aabb, y.aabb)).slice(0, 2)\n for (const carrier of chosen) builder.rest(rafter, carrier, system.joints.truss)\n frames.all.push(rafter)\n if (side === 'a') frames.sideA.push(rafter)\n else frames.sideB.push(rafter)\n }\n }\n if (!unit.annex) {\n const ridgeBox: Rect = axis === 'u' ? [box[0] - eave, middle - 0.05, box[2] + eave, middle + 0.05] : [middle - 0.05, box[1] - eave, middle + 0.05, box[3] + eave]\n const ridge = builder.add({ id: `ridge${unit.suffix}`, role: 'beam', material: construction.frame.timber, aabb: ridgeBox, y0: eaveY + rise - 0.12, y1: eaveY + rise }, { floor: unit.floor })\n for (const rafter of frames.all) builder.rest(ridge, rafter, system.joints.truss)\n }\n context.roof.trusses += count\n return frames\n}\n\nfunction panesOf(unit: RoofUnit, geometry: GableGeometry): Rect[] {\n const [u0, v0, u1, v1] = unit.box\n const { eave, axis } = geometry\n if (unit.annex) return [[u0 - eave, v0 - eave, u1 + eave, v1 + eave]]\n const midV = (v0 + v1) / 2\n const midU = (u0 + u1) / 2\n return axis === 'u'\n ? [[u0 - eave, v0 - eave, u1 + eave, midV], [u0 - eave, midV, u1 + eave, v1 + eave]]\n : [[u0 - eave, v0 - eave, midU, v1 + eave], [midU, v0 - eave, u1 + eave, v1 + eave]]\n}\n\nfunction coarseFrames(context: BuildContext, unit: RoofUnit, carriers: StructurePart[], geometry: GableGeometry): Frames {\n const trusses = addTrusses(context, unit, carriers, geometry)\n context.roof.trusses += trusses.length\n return { all: trusses, sideA: trusses, sideB: trusses }\n}\n\nfunction addGableRoof(context: BuildContext, unit: RoofUnit, carriers: StructurePart[], covering: JointKind): RoofPane[] {\n const { builder, construction } = context\n const geometry = geometryOf(context, unit)\n const frames: Frames = context.rafterRoof ? addRafters(context, unit, carriers, geometry) : coarseFrames(context, unit, carriers, geometry)\n const panes: RoofPane[] = []\n panesOf(unit, geometry).forEach((aabb, k) => {\n const name = unit.annex ? 'annex' : k === 0 ? 'a' : 'b'\n const options = { floor: unit.floor, fill: construction.roof.covering === 'colonial' ? 0.12 : 0.05, ...(construction.roof.pitch === undefined ? {} : { pitch: construction.roof.pitch }) }\n const pane = builder.add({ id: `roof${unit.suffix}_${name}`, role: 'roof', material: construction.roof.material, aabb, y0: geometry.eaveY, y1: geometry.eaveY + geometry.rise + 0.05 }, options)\n const carried = unit.annex || !context.rafterRoof ? frames.all : k === 0 ? frames.sideA : frames.sideB\n for (const frame of carried) builder.rest(pane, frame, covering)\n panes.push({ id: pane.id, aabb: pane.aabb, y0: pane.y0, y1: pane.y1 })\n })\n if (!unit.annex) {\n const roof = context.roof\n roof.axis = geometry.axis\n roof.ridge = round2(geometry.eaveY + geometry.rise)\n roof.eave = geometry.eave\n roof.y0 = round2(geometry.eaveY)\n roof.aabb = [unit.box[0] - geometry.eave, unit.box[1] - geometry.eave, unit.box[2] + geometry.eave, unit.box[3] + geometry.eave].map(round2) as Rect\n }\n return panes\n}\n\n/** Roof of a timber house: ceiling joists every 0.6 m tie the trusses and carry the attic floor. */\nfunction addCeilingJoists(context: BuildContext): void {\n const { builder, construction } = context\n const bearing = context.roof.bearingFloor\n const rects = context.rectsOf(bearing, CLOSED_ONLY)\n const box = unionOf(rects.length ? rects : [context.topBox])\n const carriers = [...(context.plates.get(bearing) ?? []), ...context.walls.filter((w) => w.floor === bearing && w.role === 'wall' && !w.exterior).map((w) => context.wallParts.get(w.id)!)]\n const length = box[2] - box[0]\n const depth = box[3] - box[1]\n const alongU = length >= depth\n const span = alongU ? length : depth\n const count = Math.max(2, Math.round(span / 0.6) + 1)\n const beamTops = carriers.filter((carrier) => carrier.role === 'beam').map((carrier) => carrier.y0)\n const y0 = carriers.length ? Math.max(...beamTops, context.level(bearing) + 1) : context.topOf(bearing)\n const joists: StructurePart[] = []\n for (let k = 0; k < count; k++) {\n const at = (alongU ? box[0] : box[1]) + 0.05 + (k * (span - 0.1)) / (count - 1)\n const aabb: Rect = alongU ? [at - 0.025, box[1], at + 0.025, box[3]] : [box[0], at - 0.025, box[2], at + 0.025]\n const joist = builder.add({ id: `ceiling_joist_${k}`, role: 'beam', material: construction.frame.timber, aabb, y0: y0 - 0.02, y1: y0 + context.system.plateThickness - 0.02 }, { floor: bearing, spacing: 0.6 })\n const beams = carriers.filter((carrier) => carrier.role === 'beam' && touches(aabb, carrier.aabb, 0.2))\n for (const carrier of beams.length ? beams : carriers.slice(0, 2)) builder.rest(joist, carrier, 'nail')\n joists.push(joist)\n }\n context.ceilingJoists = joists\n}\n\n/** The roof over the top storey: a flat slab or trusses and two panes, and the ceiling joists of a timber house. */\nexport function addRoof(context: BuildContext): void {\n const { construction } = context\n const covering = ROOF_COVERINGS.get(construction.roof.covering)\n const bearing = construction.roof.bearingFloor ?? context.floorCount - 1\n const open = context.rectsOf(context.floorCount - 1, OPEN_ROOM_TYPES)\n const topRects = context.rectsOf(context.floorCount - 1, CLOSED_ONLY)\n const body = unionOf(open.length ? open : topRects)\n context.topBox = context.floorCount - 1 === bearing ? body : unionOf(context.rectsOf(bearing, OPEN_ROOM_TYPES))\n context.roof = { shape: construction.roof.shape, covering: construction.roof.covering, material: construction.roof.material, pitch: construction.roof.pitch || 0, bearingFloor: bearing, panes: [], trusses: 0 }\n for (const unit of roofUnits(context, bearing)) {\n const carriers = roofCarriers(context, unit)\n if (construction.roof.shape === 'slab') context.roof.panes.push(addFlatRoof(context, unit, carriers))\n else context.roof.panes.push(...addGableRoof(context, unit, carriers, covering?.joint ?? 'nail'))\n }\n if (context.isTimber && construction.roof.shape !== 'slab') addCeilingJoists(context)\n}\n","import { GROUND } from '../types'\nimport type { StructureSource } from '../types'\nimport type { BuildContext } from './context'\n\ntype StairItem = StructureSource['items'][number]\n\n/** One flight per pair of linked storeys, taken from the item of the lower storey when both are present. */\nfunction flightsOf(items: readonly StairItem[]): Map<string, StairItem> {\n const flights = new Map<string, StairItem>()\n for (const item of items.filter((it) => it.category === 'stairs' && it.link)) {\n const key = `${item.link!.from}_${item.link!.to}`\n if (!flights.has(key) || item.floor === item.link!.from) flights.set(key, item)\n }\n return flights\n}\n\n/** Interior stairs between storeys, resting on the floor below and tied to the one above, plus the basement stairs. */\nexport function addStairs(context: BuildContext): void {\n const { builder, construction } = context\n const material = context.isTimber ? construction.frame.timber : (construction.stairs ?? 'concrete')\n for (const [key, item] of flightsOf(context.source.items)) {\n const { from, to } = item.link!\n const flight = builder.add({ id: `stairs_${key}`, role: 'stair', material, aabb: item.aabb!, y0: context.level(from), y1: context.level(to) }, { floor: from, steps: Math.round((context.level(to) - context.level(from)) / 0.18) })\n const base = context.baseOf(from)\n builder.rest(flight, !base || base === GROUND ? GROUND : base, !base || base === GROUND ? 'resting' : context.isTimber ? 'nail' : 'mortar')\n const upper = context.baseOf(to)\n if (upper && upper !== GROUND) builder.rest(flight, upper, context.isTimber ? 'nail' : 'bolt')\n }\n if (!context.hasBasement) return\n const item = context.source.items.find((it) => it.type === 'basement_stairs')\n if (!item?.aabb) return\n const depth = construction.foundation.depth || 2.4\n const flight = builder.add({ id: 'basement_stairs', role: 'stair', material: 'wood_soft', aabb: item.aabb, y0: -depth, y1: context.level(0) }, { floor: -1, steps: Math.round((context.level(0) + depth) / 0.18) })\n builder.rest(flight, builder.find('basement_slab')!, 'resting')\n if (context.base0 && context.base0 !== GROUND) builder.rest(flight, context.base0, 'nail')\n}\n","import type { Opening, Rect, StructurePart } from '../types'\nimport type { BuildContext, BuildWall } from './context'\n\nconst TOLERANCE = 0.02\n/** Height of a door leaf, which the plan does not store (m). */\nexport const DOOR_HEIGHT = 2.1\nconst LINTEL_DEPTH = 0.2\nconst LINTEL_BEARING = 0.2\n\nconst crossOf = (wall: BuildWall): number => (wall.axis === 'u' ? wall.v0 : wall.u0)\nconst alongRange = (wall: BuildWall): [number, number] => (wall.axis === 'u' ? [Math.min(wall.u0, wall.u1), Math.max(wall.u0, wall.u1)] : [Math.min(wall.v0, wall.v1), Math.max(wall.v0, wall.v1)])\n\n/** The windows of the plan, each in the wall it sits in. */\nexport function findOpenings(context: BuildContext): Opening[] {\n const openings: Opening[] = []\n for (const window of context.source.windows ?? []) {\n const from = window.at - window.width / 2\n const to = window.at + window.width / 2\n const wall = context.walls.find((w) => {\n if (w.floor !== window.floor || w.axis !== window.axis || w.type !== 'wall' || Math.abs(crossOf(w) - window.pos) > TOLERANCE) return false\n const [low, high] = alongRange(w)\n return from >= low - TOLERANCE && to <= high + TOLERANCE\n })\n if (!wall) continue\n const base = context.level(window.floor)\n openings.push({ id: window.id, kind: 'window', wall: wall.id, from, to, y0: base + window.y0, y1: base + window.y1 })\n }\n return openings\n}\n\n/**\n * A lintel over every door gap, 0.2 m deep, bearing 0.2 m on the wall at each side (a concrete beam in masonry, a header in timber houses). The bond beam or\n * plate over the door rests on it as well as on the walls beside it.\n */\nexport function addDoorLintels(context: BuildContext): void {\n const { builder, construction, system } = context\n for (const door of context.source.doors.filter((d) => d.a !== undefined && d.type !== 'zipper')) {\n const along = door.axis === 'u' ? door.u : door.v\n const cross = door.axis === 'u' ? door.v : door.u\n const from = along - door.width / 2\n const to = along + door.width / 2\n const beside = context.walls.filter((w) => w.floor === door.floor && w.axis === door.axis && w.type === 'wall' && Math.abs(crossOf(w) - cross) <= TOLERANCE && (Math.abs(alongRange(w)[1] - from) <= 0.05 || Math.abs(alongRange(w)[0] - to) <= 0.05))\n if (!beside.length) continue\n const half = (beside[0]!.thickness ?? 0.15) / 2\n const lo = from - LINTEL_BEARING\n const hi = to + LINTEL_BEARING\n const box: Rect = door.axis === 'u' ? [lo, cross - half, hi, cross + half] : [cross - half, lo, cross + half, hi]\n const y0 = context.level(door.floor) + DOOR_HEIGHT\n const lintel = builder.add({ id: `lintel_${door.id}`, role: 'beam', material: system.timber ? construction.frame.timber : 'concrete', aabb: box, y0, y1: y0 + LINTEL_DEPTH }, { floor: door.floor, ...(system.timber ? {} : { assembly: 'reinforced_concrete' }) })\n for (const wall of beside) builder.rest(lintel, context.wallParts.get(wall.id) as StructurePart, system.joints.beam)\n for (const plate of context.plates.get(door.floor) ?? []) if (overlapsInPlan(plate.aabb, box)) builder.rest(plate, lintel, system.joints.beam)\n }\n}\n\nconst overlapsInPlan = (a: Rect, b: Rect): boolean => a[0] < b[2] && a[2] > b[0] && a[1] < b[3] && a[3] > b[1]\n","import { GROUND } from '../types'\nimport type { Rect } from '../types'\nimport type { BuildContext } from './context'\n\nconst RISER = 0.18\nconst TREAD = 0.28\n\nconst stepCount = (elevation: number): number => Math.max(1, Math.ceil(elevation / RISER))\n\n/** Steps from each porch door down to the ground: concrete in masonry, wood otherwise, resting on the porch floor. */\nfunction addPorchSteps(context: BuildContext): void {\n const { builder } = context\n for (const room of context.source.rooms.filter((r) => r.type === 'porch')) {\n const deck = builder.find(`porch_floor_${room.id}`)\n for (const door of context.source.doors.filter((d) => d.floor === room.floor && d.b === 'outside' && d.a === room.id)) {\n const count = stepCount(context.elevation)\n const depth = count * TREAD\n const aabb: Rect = [door.u - door.width / 2, door.v - depth, door.u + door.width / 2, door.v]\n const flight = builder.add({ id: `steps_${door.id}`, role: 'stair', material: context.isTimber ? 'wood_soft' : 'concrete', aabb, y0: 0, y1: context.level(room.floor) }, { floor: 0, steps: count, door: door.id })\n builder.rest(flight, GROUND, 'resting')\n if (deck) builder.rest(flight, deck, context.isTimber ? 'nail' : 'mortar')\n }\n }\n}\n\nfunction boxOfSteps(door: { u: number; v: number; width: number; axis: string; side?: string }, depth: number): Rect {\n const direction = door.axis === 'u' ? (door.side === 'front' ? -1 : 1) : door.side === 'left' ? -1 : 1\n if (door.axis === 'u') return [door.u - door.width / 2, Math.min(door.v, door.v + direction * depth), door.u + door.width / 2, Math.max(door.v, door.v + direction * depth)]\n return [Math.min(door.u, door.u + direction * depth), door.v - door.width / 2, Math.max(door.u, door.u + direction * depth), door.v + door.width / 2]\n}\n\n/** Steps at the other outside doors of the ground storey when the floor sits above the ground. */\nfunction addDoorSteps(context: BuildContext): void {\n if (context.elevation <= 0.1) return\n const { builder } = context\n const doors = context.source.doors.filter((d) => d.floor === 0 && d.exterior && d.model !== 'steel' && d.type !== 'steps' && d.type !== 'zipper')\n for (const door of doors) {\n const count = stepCount(context.elevation)\n const depth = Math.min(TREAD * count, 0.9)\n const flight = builder.add({ id: `steps_${door.id}`, role: 'stair', material: context.isTimber ? 'wood_soft' : 'concrete', aabb: boxOfSteps(door, depth), y0: 0, y1: context.level(0) }, { floor: 0, steps: count, door: door.id })\n builder.rest(flight, GROUND, 'resting')\n const base = context.base0\n if (base && base !== GROUND) builder.rest(flight, base, context.isTimber ? 'nail' : 'mortar')\n }\n}\n\nexport function addExteriorSteps(context: BuildContext): void {\n addPorchSteps(context)\n addDoorSteps(context)\n}\n","import { GROUND } from '../types'\nimport type { Rect, StructurePart, WaterTank } from '../types'\nimport { touches } from '../geometry'\nimport type { BuildContext } from './context'\n\nconst TANK_FILL = 0.08\n\nconst squareAround = (u: number, v: number, side: number): Rect => [u - side / 2, v - side / 2, u + side / 2, v + side / 2]\n\nfunction addTank(context: BuildContext, tank: WaterTank, floor: number, y0: number): StructurePart {\n return context.builder.add({ id: 'water_tank', role: 'none', material: tank.material ?? 'plastic', aabb: tank.aabb, y0, y1: y0 + tank.h }, { floor, fill: TANK_FILL, liters: tank.capacity })\n}\n\n/** The slab under the roof that carries a tank in the attic or on a raised platform: a ceiling slab on the top plates, pillars and bearing walls. */\nfunction ensureCeilingSlab(context: BuildContext, y: number): StructurePart {\n const { builder, construction, system } = context\n const existing = builder.find('slab_ceiling')\n if (existing) return existing\n const top = context.floorCount - 1\n const box = context.topBox\n const carriers = builder.parts.filter(\n (part) =>\n ((part.role === 'beam' && part.id.startsWith(`plate_${top}_`)) || (part.role === 'column' && part.floor === top) || (part.role === 'wall' && part.floor === top && !part.id.startsWith('basement'))) &&\n touches(box, part.aabb, 0.1),\n )\n const slab = builder.add({ id: 'slab_ceiling', role: 'slab', material: construction.frame.slabs, aabb: box, y0: y - 0.12, y1: y }, { floor: top, footprint: [box] })\n for (const carrier of carriers) builder.rest(slab, carrier, system.joints.slab)\n return slab\n}\n\nfunction addRaisedPlatform(context: BuildContext, tank: WaterTank): void {\n const { builder, construction } = context\n const platform = tank.platform!\n const top = context.floorCount - 1\n const ceiling = ensureCeilingSlab(context, platform.baseY)\n const pillars = platform.pillars.map((q, k) => {\n const pillar = builder.add({ id: `tank_column_${k}`, role: 'column', material: construction.frame.pillars, aabb: squareAround(q.u, q.v, q.side), y0: platform.baseY, y1: platform.topY - platform.thickness }, { floor: top })\n builder.rest(pillar, ceiling, 'rebar')\n return pillar\n })\n const slab = builder.add({ id: 'tank_slab', role: 'slab', material: construction.frame.slabs, aabb: platform.aabb, y0: platform.topY - platform.thickness, y1: platform.topY }, { floor: top })\n for (const pillar of pillars) builder.rest(slab, pillar, 'rebar')\n builder.rest(addTank(context, tank, top, tank.y), slab, 'resting')\n}\n\nfunction addAtticTank(context: BuildContext, tank: WaterTank): void {\n const { builder } = context\n const top = context.floorCount - 1\n if (!context.isTimber) {\n const ceiling = ensureCeilingSlab(context, tank.y)\n builder.rest(addTank(context, tank, top, tank.y), ceiling, 'resting')\n return\n }\n const supports = context.topSlab ? [context.topSlab] : (context.ceilingJoists ?? builder.parts.filter((part) => part.role === 'beam' && part.id.startsWith(`plate_${top}_`)))\n const y0 = supports[0] ? supports[0].y1 : tank.y - 0.03\n const floor = builder.add({ id: 'attic_floor', role: 'slab', material: 'plywood', aabb: context.topBox, y0, y1: y0 + 0.03 }, { floor: top })\n for (const support of supports) if (touches(floor.aabb, support.aabb, 0.1)) builder.rest(floor, support, 'nail')\n builder.rest(addTank(context, tank, top, tank.y), floor, 'resting')\n}\n\nfunction addSlabTank(context: BuildContext, tank: WaterTank): void {\n const { builder } = context\n const supports = builder.parts.filter((part) => part.role === 'slab' && Math.abs(part.y1 - tank.y) < 0.3 && touches(part.aabb, tank.aabb, 0.1))\n const carrier = supports.sort((a, b) => Math.abs(a.y1 - tank.y) - Math.abs(b.y1 - tank.y))[0] ?? context.topSlab\n const part = addTank(context, tank, tank.floor, tank.y)\n builder.rest(part, carrier ?? GROUND, 'resting')\n}\n\nfunction addTrestleTank(context: BuildContext, tank: WaterTank): void {\n const { builder } = context\n const stand = tank.stand!\n const columns = stand.pillars.map((q, k) => {\n const column = builder.add({ id: `trestle_column_${k}`, role: 'column', material: stand.material, aabb: squareAround(q.u, q.v, q.side), y0: 0, y1: stand.height }, { floor: 0 })\n builder.rest(column, GROUND, stand.baseJoint ?? 'resting')\n return column\n })\n const [u0, v0, u1, v1] = tank.aabb\n const beams = ([[u0 - 0.1, v0 - 0.1, u1 + 0.1, v0 + 0.05], [u0 - 0.1, v1 - 0.05, u1 + 0.1, v1 + 0.1]] as Rect[]).map((aabb, k) => {\n const beam = builder.add({ id: `trestle_beam_${k}`, role: 'beam', material: stand.material, aabb, y0: stand.height - 0.12, y1: stand.height }, { floor: 0 })\n for (const column of columns.filter((c) => touches(beam.aabb, c.aabb, 0.15))) builder.rest(beam, column, stand.joint ?? 'nail')\n return beam\n })\n const part = addTank(context, tank, 0, stand.height)\n for (const beam of beams) builder.rest(part, beam, stand.tie ?? 'resting')\n}\n\n/** The water tank as a part (role `none`: it weighs on what holds it and carries nothing) with whatever holds it up. */\nexport function addWaterTank(context: BuildContext): void {\n const tank = context.tank\n if (!tank) return\n switch (tank.place) {\n case 'slab':\n return addSlabTank(context, tank)\n case 'raised_slab':\n return addRaisedPlatform(context, tank)\n case 'attic':\n return addAtticTank(context, tank)\n case 'trestle':\n return addTrestleTank(context, tank)\n }\n}\n","import { touches, unionOf } from '../geometry'\nimport type { BuildContext } from './context'\nimport { addDeck, addJoists } from './floor-deck'\n\n/** The floor of the storey above `floor`: a concrete slab, or joists and boards in timber, resting on what carries `floor`. */\nexport function addUpperFloor(context: BuildContext, floor: number): void {\n if (floor >= context.floorCount - 1 || context.isUnit) return\n const next = floor + 1\n const rects = context.rectsOf(next, ['balcony', 'porch', 'void'])\n const box = rects.length ? unionOf(rects) : context.houseBox\n const carriers = context.carriers.get(floor)!\n const { system, construction, builder } = context\n const thickness = system.slabThickness\n if (context.isTimber) {\n const joists = addJoists(context, { floor: next, box, thickness, carriers, material: construction.frame.timber, joint: system.joints.beam })\n addDeck(context, `slab_${next}`, construction.frame.slabs, { floor: next, box, thickness, joint: system.joints.slab }, joists)\n return\n }\n const slab = builder.add({ id: `slab_${next}`, role: 'slab', material: construction.frame.slabs, aabb: box, y0: context.level(next) - thickness, y1: context.level(next) }, { floor: next, footprint: rects.length ? rects : [context.houseBox] })\n const below = carriers.filter((carrier) => carrier.y0 <= slab.y0 + 0.05)\n const touching = below.filter((carrier) => touches(slab.aabb, carrier.aabb, 0.2))\n for (const carrier of touching.length ? touching : below) builder.rest(slab, carrier, system.joints.slab)\n}\n","import { GROUND } from '../types'\nimport type { StructurePart } from '../types'\nimport type { BuildContext, BuildWall } from './context'\nimport { guardHeightOf, OPEN_ROOM_TYPES } from './context'\n\n/** Highest ceiling among the rooms the wall touches (a double-height room lifts its outer wall to the eave). */\nexport function wallCeiling(context: BuildContext, wall: BuildWall): number {\n const rooms = wall.sides.map((id) => context.source.rooms.find((room) => room.id === id && room.floor === wall.floor)).filter((room) => room !== undefined)\n return Math.max(context.ceilingOf(wall.floor), ...rooms.map((room) => room.ceiling || 0))\n}\n\nfunction wallTop(context: BuildContext, wall: BuildWall, floor: number): number {\n const y0 = context.level(floor)\n if (wall.type === 'railing') return y0 + guardHeightOf(wall)\n const ceiling = wallCeiling(context, wall)\n const height = wall.structureHeight || wall.h || context.ceilingOf(floor)\n if (wall.exterior && floor < context.floorCount - 1 && !context.isUnit && ceiling > context.ceilingOf(floor) + 0.01) return y0 + ceiling\n if (floor === context.floorCount - 1 || context.isUnit) return y0 + Math.max(height, ceiling)\n const top = context.topOf(floor)\n return Math.max(y0 + height, y0 + ceiling > top ? top : y0 + ceiling)\n}\n\n/** What a railing rests on: the slab of its own balcony or the floor of its porch. */\nfunction railingBase(context: BuildContext, wall: BuildWall, floor: number): StructurePart | string | undefined {\n const open = wall.sides\n .map((id) => context.source.rooms.find((room) => room.id === id && room.floor === floor))\n .find((room) => room && (room.type === 'balcony' || room.type === 'porch'))\n if (!open) return context.baseOf(floor)\n return open.type === 'porch' ? `porch_floor_${open.id}` : `slab_${floor}_${open.id}`\n}\n\nconst assemblyOf = (context: BuildContext): string | undefined => context.construction.walls.assembly ?? (context.system.walls || undefined)\n\nfunction addWallPart(context: BuildContext, wall: BuildWall, floor: number): void {\n const { system, builder } = context\n const isRailing = wall.type === 'railing'\n const y0 = context.level(floor)\n const top = wallTop(context, wall, floor)\n const y1 = isRailing ? top : wall.exterior && !wall.gable ? top - system.plateThickness : top\n const framed = system.studs !== undefined && !isRailing\n const part = builder.add(\n { id: wall.id, role: wall.role, material: wall.material, aabb: wall.box, y0, y1: Math.max(y1, y0 + 0.2) },\n { floor, fill: context.isTimber && wall.role === 'wall' ? system.wallFill : 1, ...(framed ? { studs: system.studs } : {}), ...(isRailing ? {} : { assembly: assemblyOf(context) }) },\n )\n context.wallParts.set(wall.id, part)\n const base = isRailing ? railingBase(context, wall, floor) : context.baseOf(floor)\n const joint = isRailing ? 'nail' : system.joints.wall\n if (base === GROUND || (floor === 0 && !base)) builder.rest(part, GROUND, joint)\n else if (base) builder.rest(part, base, joint)\n}\n\n/** One part per wall of the storey, resting on the floor below it (or the ground). */\nexport function addWalls(context: BuildContext, floor: number): void {\n for (const wall of context.walls.filter((w) => w.floor === floor)) addWallPart(context, wall, floor)\n}\n\nexport const isOpenRoomType = (type: string): boolean => OPEN_ROOM_TYPES.includes(type)\n","import { createContext } from './context'\nimport type { BuildContext } from './context'\nimport { addBalconies } from './balconies'\nimport { buildCanvasStructure } from './canvas'\nimport { addChimney, addWell } from './extras'\nimport { addFoundation } from './foundation'\nimport { addPlatesAndPillars } from './plates'\nimport { addPorches } from './porch'\nimport { addPorchRoofs } from './porch-roof'\nimport { addRoof } from './roof'\nimport { addStairs } from './stairs'\nimport { addDoorLintels, findOpenings } from './openings'\nimport { addExteriorSteps } from './steps'\nimport { addWaterTank } from './tank-parts'\nimport { addUpperFloor } from './upper-floor'\nimport { addWalls } from './walls'\nimport { resolveConstruction } from '../construction'\nimport type { Structure, StructureOptions, StructureSource } from '../types'\n\nfunction buildFloors(context: BuildContext): void {\n for (let floor = 0; floor < context.floorCount; floor++) {\n addWalls(context, floor)\n addPlatesAndPillars(context, floor)\n addPorches(context, floor)\n addUpperFloor(context, floor)\n }\n}\n\n/**\n * The structure of a generated plan: every part that carries load (foundation, floors, walls, plates and bond beams, pillars, porch posts, trusses,\n * roof, stairs, tank) with what each rests on. The plan itself is not modified.\n */\nexport function buildStructure(source: StructureSource, options: StructureOptions = {}): Structure {\n const refined = options.wallDetail !== 'coarse'\n const built = options.construction ? { construction: options.construction, extras: options.extras ?? {} } : resolveConstruction(source)\n const construction = built.construction\n const extras = options.extras ?? built.extras ?? {}\n if (construction.system === 'canvas') return buildCanvasStructure(construction, extras)\n const tank = options.tank !== undefined ? options.tank : (source.waterTank ?? null)\n const context = createContext(source, construction, extras, tank, { porchRoofOnPostsOnly: options.porchRoofOnPostsOnly ?? refined, rafterRoof: options.rafterRoof ?? refined })\n addFoundation(context)\n buildFloors(context)\n addBalconies(context)\n addPorchRoofs(context)\n addExteriorSteps(context)\n addStairs(context)\n addRoof(context)\n if (refined) addDoorLintels(context)\n addWaterTank(context)\n addChimney(context)\n addWell(context)\n const levels = source.floors.map((_, floor) => context.level(floor))\n const framed = construction.system === 'masonry' && (context.isUnit || source.style === 'commercial' || context.floorCount >= 3)\n return { parts: context.builder.parts, supports: context.builder.supports, levels, elevation: context.elevation, roof: context.roof, construction, framed, openings: findOpenings(context) }\n}\n","export type ContentGroup = 'food' | 'water' | 'medicine' | 'tool' | 'cleaning' | 'improvised_weapon' | 'clothes' | 'document' | 'utensil' | 'trash'\n\nexport interface ContentEntry {\n itemId: string\n min: number\n max: number\n group: ContentGroup\n pickable: boolean\n weight: number\n}\n\nconst entry = (itemId: string, min: number, max: number, group: ContentGroup, pickable: boolean, weight: number): ContentEntry => ({ itemId, min, max, group, pickable, weight })\n\nconst FRIDGE = [\n entry('water_bottle', 1, 3, 'water', true, 3), entry('milk_carton', 1, 2, 'food', true, 2), entry('eggs', 1, 1, 'food', true, 2), entry('packed_meat', 1, 2, 'food', true, 1.5), entry('fruit', 1, 4, 'food', true, 2),\n entry('yogurt', 1, 3, 'food', true, 1), entry('soda', 1, 2, 'water', true, 1), entry('cheese', 1, 1, 'food', true, 1), entry('insulin', 1, 1, 'medicine', true, 0.4), entry('leftovers', 1, 2, 'food', true, 1),\n]\nconst BEDSIDE = [entry('medicine', 1, 2, 'medicine', true, 2), entry('book', 1, 2, 'document', true, 1.5), entry('charger', 1, 1, 'tool', true, 1), entry('flashlight', 1, 1, 'tool', true, 0.7), entry('glasses', 1, 1, 'tool', true, 0.7)]\nconst WARDROBE = [\n entry('shirt', 2, 6, 'clothes', true, 3), entry('trousers', 1, 4, 'clothes', true, 3), entry('coat', 1, 2, 'clothes', true, 1.5), entry('sneakers', 1, 2, 'clothes', true, 1.5),\n entry('shoes', 1, 2, 'clothes', true, 1), entry('blanket', 1, 2, 'clothes', true, 1.5), entry('backpack', 1, 1, 'tool', true, 0.8),\n]\nconst DRESSER = [entry('underwear', 2, 6, 'clothes', true, 3), entry('socks', 2, 6, 'clothes', true, 2), entry('t_shirt', 1, 4, 'clothes', true, 2), entry('documents', 1, 2, 'document', true, 1), entry('flashlight', 1, 1, 'tool', true, 0.7), entry('batteries', 1, 2, 'tool', true, 0.7)]\nconst FILING = [entry('documents', 1, 4, 'document', true, 3), entry('pen', 1, 3, 'tool', true, 1.5), entry('keys', 1, 2, 'tool', true, 1), entry('stapler', 1, 1, 'improvised_weapon', true, 0.5)]\nconst TRASH = [entry('full_trash_bag', 1, 1, 'trash', false, 2), entry('packaging', 1, 4, 'trash', true, 3), entry('empty_can', 1, 3, 'trash', true, 2), entry('crumpled_paper', 1, 3, 'trash', true, 1)]\n\n/** What each kind of container may hold, by category (or by type when a type differs from its category). */\nexport const CONTENT_TABLES: Record<string, ContentEntry[]> = {\n fridge: FRIDGE,\n display_fridge: [entry('soda', 2, 6, 'water', true, 3), entry('water_bottle', 2, 6, 'water', true, 3), entry('yogurt', 2, 5, 'food', true, 2)],\n freezer: [entry('frozen_meat', 2, 5, 'food', true, 3), entry('ice_cream', 1, 2, 'food', true, 1)],\n kitchen_cabinet: [\n entry('pot', 1, 2, 'tool', true, 1.5), entry('kitchen_knife', 1, 2, 'improvised_weapon', true, 1.5), entry('dish_soap', 1, 2, 'cleaning', true, 2), entry('sponge', 1, 2, 'cleaning', true, 1), entry('rice', 1, 2, 'food', true, 1.5),\n entry('beans', 1, 2, 'food', true, 1.5), entry('pasta', 1, 2, 'food', true, 1), entry('cooking_oil', 1, 1, 'food', true, 1), entry('canned_tuna', 1, 3, 'food', true, 1.5), entry('disinfectant', 1, 1, 'cleaning', true, 1), entry('trash_bag', 1, 2, 'trash', true, 0.7),\n ],\n overhead_cabinet: [entry('plates', 4, 8, 'utensil', false, 3), entry('glasses', 3, 6, 'utensil', false, 3), entry('mug', 1, 3, 'utensil', true, 1.5), entry('coffee', 1, 2, 'food', true, 1.5), entry('canned_corn', 1, 3, 'food', true, 1.5), entry('spices', 1, 3, 'food', true, 1)],\n washbasin: [\n entry('painkiller', 1, 2, 'medicine', true, 2), entry('bandages', 1, 2, 'medicine', true, 2), entry('soap', 1, 3, 'cleaning', true, 2), entry('toilet_paper', 1, 4, 'cleaning', true, 2), entry('shampoo', 1, 2, 'cleaning', true, 1),\n entry('toothbrush', 1, 2, 'cleaning', true, 1), entry('scissors', 1, 1, 'improvised_weapon', true, 0.5), entry('rubbing_alcohol', 1, 1, 'medicine', true, 1),\n ],\n wardrobe: WARDROBE,\n wardrobe_large: WARDROBE,\n dresser: DRESSER,\n console_table: DRESSER,\n nightstand: BEDSIDE,\n filing_cabinet: FILING,\n pantry: [\n entry('rice', 2, 4, 'food', true, 2), entry('beans', 2, 4, 'food', true, 2), entry('canned_tuna', 2, 5, 'food', true, 2), entry('water_jug', 1, 2, 'water', true, 2), entry('flour', 1, 2, 'food', true, 1),\n entry('sugar', 1, 2, 'food', true, 1), entry('cooking_oil', 1, 2, 'food', true, 1), entry('biscuits', 1, 4, 'food', true, 1.5),\n ],\n tv_unit: [entry('remote_control', 1, 1, 'tool', true, 2), entry('dvds', 1, 4, 'document', true, 1), entry('cables', 1, 3, 'tool', true, 1.5), entry('batteries', 1, 2, 'tool', true, 1)],\n laundry_cabinet: [entry('washing_powder', 1, 2, 'cleaning', true, 3), entry('bleach', 1, 2, 'cleaning', true, 2), entry('disinfectant', 1, 2, 'cleaning', true, 2), entry('bucket', 1, 1, 'tool', true, 1), entry('broom', 1, 1, 'improvised_weapon', true, 1), entry('rubber_gloves', 1, 2, 'cleaning', true, 1)],\n laundry_shelf: [entry('washing_powder', 1, 1, 'cleaning', true, 2), entry('softener', 1, 2, 'cleaning', true, 2), entry('clothespins', 1, 1, 'tool', true, 1)],\n workbench: [entry('hammer', 1, 1, 'improvised_weapon', true, 2), entry('screwdriver', 1, 2, 'tool', true, 2), entry('pliers', 1, 1, 'tool', true, 1.5), entry('insulating_tape', 1, 2, 'tool', true, 1), entry('screws', 1, 2, 'tool', true, 1)],\n tool_shelf: [entry('hammer', 1, 1, 'improvised_weapon', true, 1.5), entry('hand_saw', 1, 1, 'improvised_weapon', true, 1), entry('paint_can', 1, 3, 'trash', true, 1.5), entry('rope', 1, 1, 'tool', true, 1), entry('nails', 1, 2, 'tool', true, 1.5)],\n mailbox: [entry('letter', 1, 4, 'document', true, 3), entry('bill', 1, 2, 'document', true, 2), entry('flyer', 1, 4, 'trash', true, 2)],\n trash_bin: TRASH,\n outdoor_bin: TRASH,\n china_cabinet: [entry('china_plates', 3, 6, 'utensil', false, 3), entry('wine_glasses', 2, 5, 'utensil', false, 2)],\n}\n\n/** Groups of things somebody who locked themselves in would have stocked up. */\nexport const SUPPLY_GROUPS: readonly ContentGroup[] = ['food', 'water', 'medicine', 'tool']\n","import type { FindStack } from '@adatechnology/game-floorplan'\n\nimport { CONTENT_TABLES, SUPPLY_GROUPS } from './content-tables'\nimport type { ContentEntry } from './content-tables'\nimport type { Rng } from './shared'\n\nexport interface ContentStack extends FindStack {\n group: string\n pickable: boolean\n}\n\nexport interface ContentQuery {\n /** Category or type of the container (`fridge`, `kitchen_cabinet`, `overhead_cabinet`...). */\n container: string\n state: string\n rng: Rng\n /** Footprint of the container in m2. */\n footprint: number\n}\n\n/** How a state changes what a container holds: how many kinds, how likely each is, how many of each, and what is left over. */\nexport interface ContentStateRule {\n kinds(base: number, available: number, rng: Rng): number\n weight(entry: ContentEntry): number\n extraQuantity(entry: ContentEntry): number\n leftovers?(found: ContentStack[], container: string, rng: Rng): void\n}\n\nconst FRIDGES = ['fridge', 'display_fridge', 'freezer']\nconst isSupply = (entry: ContentEntry): boolean => SUPPLY_GROUPS.includes(entry.group)\n\n/** The normal world is the base; `fortified` and `abandoned` are the genre's rules, kept here until the item catalogue and the genre pack own them. */\nexport const CONTENT_STATES: Record<string, ContentStateRule> = {\n normal: { kinds: (base) => base, weight: (entry) => entry.weight, extraQuantity: () => 0 },\n fortified: { kinds: (base, available) => Math.min(available, base + 2), weight: (entry) => (isSupply(entry) ? entry.weight * 2.5 : entry.weight), extraQuantity: (entry) => (isSupply(entry) ? 1 : 0) },\n abandoned: {\n kinds: (_base, _available, rng) => (rng() < 0.4 ? 0 : 1),\n weight: (entry) => entry.weight,\n extraQuantity: () => 0,\n leftovers(found, container, rng) {\n if (found.length === 0 && rng() < 0.5) found.push({ itemId: 'scraps_and_papers', count: 1, pickable: false, group: 'trash' })\n if (FRIDGES.includes(container)) found.push({ itemId: 'spoiled_food', count: 1, pickable: false, group: 'trash' })\n },\n },\n}\n\nexport function registerContentState(state: string, rule: ContentStateRule): void {\n CONTENT_STATES[state] = rule\n}\n\n/** Weighted draw without replacement. */\nfunction weightedOrder<T extends { weight: number }>(candidates: T[], rng: Rng): T[] {\n const pool = candidates.slice()\n const out: T[] = []\n while (pool.length) {\n let x = rng() * pool.reduce((sum, c) => sum + c.weight, 0)\n let i = 0\n for (; i < pool.length - 1; i++) {\n x -= pool[i]!.weight\n if (x < 0) break\n }\n out.push(pool.splice(i, 1)[0]!)\n }\n return out\n}\n\n/** What a container holds in a state: a few kinds of thing from the table of its category, more of the useful ones when fortified, almost nothing when abandoned. */\nexport function contentOf(query: ContentQuery): ContentStack[] {\n const pool = CONTENT_TABLES[query.container]\n if (!pool) return []\n const rule = CONTENT_STATES[query.state] ?? CONTENT_STATES.normal!\n const { rng } = query\n const base = Math.max(2, Math.min(5, Math.round(1.5 + query.footprint * 3 + rng() * 1.5)))\n const kinds = rule.kinds(base, pool.length, rng)\n const found: ContentStack[] = []\n for (const candidate of weightedOrder(pool.map((entry) => ({ entry, weight: rule.weight(entry) })), rng).slice(0, kinds)) {\n const { entry } = candidate\n const count = entry.min + Math.floor(rng() * (entry.max - entry.min + 1)) + rule.extraQuantity(entry)\n found.push({ itemId: entry.itemId, count, pickable: entry.pickable, group: entry.group })\n }\n rule.leftovers?.(found, query.container, rng)\n return found\n}\n\nexport const hasContent = (container: string): boolean => container in CONTENT_TABLES\n\n","import type { Rect } from '../types'\n\n/** Loosely typed plan data: the engine's own plan and its items (`result.items`), which the utilities read and some of them annotate. */\nexport type Json = any\nexport type Rng = () => number\n\nexport const HALF_WALL = 0.075\nexport const round2 = (value: number): number => Math.round(value * 100) / 100\nexport const clamp = (value: number, low: number, high: number): number => Math.max(low, Math.min(high, value))\n\nexport const overlaps = (a: Rect, b: Rect, epsilon = 1e-6): boolean => a[0] < b[2] - epsilon && a[2] > b[0] + epsilon && a[1] < b[3] - epsilon && a[3] > b[1] + epsilon\n\nexport const inner = (rect: Rect): Rect => [rect[0] + HALF_WALL, rect[1] + HALF_WALL, rect[2] - HALF_WALL, rect[3] - HALF_WALL]\n\n/** A solid item: not a rug, not resting on something, and not decoration unless it stands on the floor. */\nexport const isSolid = (item: Json): boolean => !item.flat && !item.on && (!item.decor || item.mount === 'floor')\n\nexport const distanceToRect = (u: number, v: number, rect: Rect): number => Math.hypot(Math.max(rect[0] - u, 0, u - rect[2]), Math.max(rect[1] - v, 0, v - rect[3]))\n\n/** Room types without sockets, switches or circuits. */\nexport const NO_SOCKET_ROOMS: readonly string[] = ['void', 'elevator', 'stairs', 'balcony', 'terrace', 'porch', 'tent']\n\n/** Unit vector pointing out of the house from a wall (`sides[0]` or `sides[1]` is `outside`). */\nexport const outwardOf = (wall: Json): [number, number] => {\n const sign = wall.sides[0] === 'outside' ? -1 : 1\n return wall.axis === 'u' ? [0, sign] : [sign, 0]\n}\n\nexport const sideNameOf = (vector: [number, number]): string => (Math.abs(vector[0]) > Math.abs(vector[1]) ? (vector[0] > 0 ? 'right' : 'left') : vector[1] > 0 ? 'back' : 'front')\n\nexport const alongRange = (wall: Json): [number, number] => (wall.axis === 'u' ? [Math.min(wall.u0, wall.u1), Math.max(wall.u0, wall.u1)] : [Math.min(wall.v0, wall.v1), Math.max(wall.v0, wall.v1)])\n\n/** Exterior ground-floor wall at least 1 m long, the front one first when there is one (a gas meter and an inverter go on them). */\nexport function groundExteriorWalls(plan: Json): Json[] {\n return plan.walls.filter((wall: Json) => wall.exterior && wall.floor === 0 && wall.type === 'wall' && Math.hypot(wall.u1 - wall.u0, wall.v1 - wall.v0) >= 1.0)\n}\n","import type { Json } from './shared'\nimport { HALF_WALL, isSolid, round2 } from './shared'\n\nexport interface WallPoint {\n u: number\n v: number\n /** Position along the wall. */\n c: number\n axis: 'u' | 'v'\n pos: number\n side: number\n nu: number\n nv: number\n a0: number\n a1: number\n exterior: boolean\n windows: Json[]\n /** A solid item within 12 cm of the point reaches higher than `height`. */\n blocked(height: number): boolean\n}\n\nconst STEP = 0.05\nconst SURFACE_OFFSET = 0.012\n\n/** Points on the inner face of the walls of a room, away from corners (`margin`), where sockets, switches and a panel may go. */\nexport function wallPointsOf(plan: Json, room: Json, items: Json[], margin = 0.3): WallPoint[] {\n const points: WallPoint[] = []\n const windows = plan.windows.filter((w: Json) => w.floor === room.floor)\n const solids = items.filter((m) => m.floor === room.floor && !m.outdoor && m.room === room.id && isSolid(m))\n for (const wall of plan.walls) {\n if (wall.floor !== room.floor || wall.type !== 'wall' || !wall.sides.includes(room.id)) continue\n const side = wall.sides[1] === room.id ? 1 : -1\n const a0 = wall.axis === 'u' ? Math.min(wall.u0, wall.u1) : Math.min(wall.v0, wall.v1)\n const a1 = wall.axis === 'u' ? Math.max(wall.u0, wall.u1) : Math.max(wall.v0, wall.v1)\n const pos = wall.axis === 'u' ? wall.v0 : wall.u0\n const nearby = windows.filter((w: Json) => w.axis === wall.axis && Math.abs(w.pos - pos) < 1e-3 && w.at + w.width / 2 > a0 && w.at - w.width / 2 < a1)\n for (let c = a0 + margin; c <= a1 - margin + 1e-9; c += STEP) {\n const u = wall.axis === 'u' ? c : pos + side * (HALF_WALL + SURFACE_OFFSET)\n const v = wall.axis === 'u' ? pos + side * (HALF_WALL + SURFACE_OFFSET) : c\n points.push({\n u: round2(u), v: round2(v), c: round2(c), axis: wall.axis, pos, side, nu: wall.axis === 'u' ? 0 : side, nv: wall.axis === 'u' ? side : 0, a0, a1, exterior: wall.exterior, windows: nearby,\n blocked: (height) => solids.some((m) => m.aabb && Math.hypot(Math.max(m.aabb[0] - u, 0, u - m.aabb[2]), Math.max(m.aabb[1] - v, 0, v - m.aabb[3])) < 0.12 && (m.y || 0) + m.h > height),\n })\n }\n }\n return points\n}\n\nexport const hasWindowAt = (point: WallPoint, y: number, clearance = 0.2): boolean =>\n point.windows.some((w) => y + 0.1 > w.y0 - 0.05 && y - 0.1 < w.y1 + 0.05 && Math.abs(point.c - w.at) < w.width / 2 + clearance)\n\nexport const atDoor = (plan: Json, room: Json, point: WallPoint, clearance: number): boolean =>\n plan.doors.some((d: Json) => d.floor === room.floor && d.axis === point.axis && Math.abs(d.pos - point.pos) < 1e-3 && Math.abs(d.at - point.c) < d.width / 2 + clearance)\n","import type { Layout } from './electrical'\nimport { keyOf } from './electrical'\nimport type { Json } from './shared'\nimport { distanceToRect } from './shared'\nimport { atDoor, hasWindowAt } from './wall-points'\nimport type { WallPoint } from './wall-points'\n\n/** Categories that need a socket of their own. */\nconst APPLIANCES = ['fridge', 'display_fridge', 'freezer', 'tv', 'appliance', 'washing_machine', 'air_conditioner', 'cash_register', 'table_light']\nconst COUNTERS = ['kitchen_cabinet', 'workbench', 'checkout_counter']\nconst LAMPS = ['table_light', 'lamp']\n\nconst needsSocket = (item: Json): boolean => APPLIANCES.includes(item.category) || item.category === 'shower'\n\ninterface Pick {\n point: WallPoint\n y: number\n score: number\n}\n\n/** Sockets: one for each appliance (the shower heater too), then enough for the size of each room, two at counter height in a kitchen with a counter. */\nexport function addOutlets(layout: Layout): void {\n const { plan, items, rooms, electrical, pointsOf } = layout\n let counter = 0\n const outletsOf = (room: Json): Json[] => electrical.outlets.filter((t) => t.room === room.id && t.floor === room.floor)\n const newOutlet = (room: Json, point: WallPoint, y: number): Json => {\n const outlet = { id: `outlet${++counter}`, room: room.id, floor: room.floor, u: point.u, v: point.v, y, c: point.c, axis: point.axis, pos: point.pos, frontU: point.nu, frontV: point.nv, type: '2P+T', voltage: 127 }\n electrical.outlets.push(outlet)\n return outlet\n }\n const counters = items.filter((m) => COUNTERS.includes(m.category) && !m.outdoor)\n const heightFor = (room: Json, point: WallPoint): number =>\n room.type === 'kitchen' && counters.some((m) => m.floor === room.floor && m.room === room.id && distanceToRect(point.u, point.v, m.aabb) < 0.45) ? 1.1 : 0.3\n const valid = (room: Json, point: WallPoint, y: number): boolean =>\n !hasWindowAt(point, y, 0.25) && !atDoor(plan, room, point, 0.45) && !outletsOf(room).some((t) => Math.hypot(t.u - point.u, t.v - point.v) < 0.5 && t.y === y)\n const pick = (room: Json, score: (point: WallPoint) => number, fixedY: number | null, ignoreBlocked?: boolean): Pick | null => {\n let best: Pick | null = null\n for (const point of pointsOf.get(keyOf(room)) ?? []) {\n const y = fixedY ?? heightFor(room, point)\n if (!valid(room, point, y)) continue\n const total = score(point) + (point.blocked(y) && !ignoreBlocked ? 5 : 0)\n if (!best || total < best.score) best = { point, y, score: total }\n }\n return best\n }\n const roomOf = (item: Json): Json | undefined => rooms.find((x) => x.id === item.room && x.floor === item.floor)\n const appliances = items.filter((m) => !m.outdoor && needsSocket(m) && rooms.some((c) => c.id === m.room && c.floor === m.floor) && m.category !== 'table_light')\n for (const item of appliances) connectAppliance(item)\n function connectAppliance(item: Json): void {\n const room = roomOf(item)!\n const target = item.aabb\n const nearest = outletsOf(room).map((t) => ({ t, d: distanceToRect(t.u, t.v, target) })).filter((o) => o.d <= 1.2 && o.t.y <= 1.1).sort((a, b) => a.d - b.d)[0]\n const isShower = item.category === 'shower'\n let outlet: Json | null = nearest && !isShower ? nearest.t : null\n if (!outlet) {\n const height = isShower ? 1.1 : item.y > 0.7 ? 1.1 : null\n const best = pick(room, (p) => { const d = distanceToRect(p.u, p.v, target); return isShower && d < 0.6 ? 50 + d : d }, height)\n let chosen = best\n if (!isShower && (!best || distanceToRect(best.point.u, best.point.v, target) > 1.4)) {\n const behind = pick(room, (p) => distanceToRect(p.u, p.v, target), item.y > 0.7 ? 1.1 : null, true)\n if (behind && (!best || distanceToRect(behind.point.u, behind.point.v, target) < distanceToRect(best.point.u, best.point.v, target))) chosen = behind\n }\n if (chosen) outlet = newOutlet(room, chosen.point, chosen.y)\n }\n if (!outlet) return\n item.outlet = outlet.id\n if (isShower) item.showerHeater = { electric: true, powerW: 5500, outlet: outlet.id }\n }\n for (const room of rooms) {\n const area = room.parts.reduce((sum: number, q: number[]) => sum + (q[2]! - q[0]!) * (q[3]! - q[1]!), 0)\n const wanted = Math.max(room.type === 'kitchen' ? 3 : 2, Math.min(6, Math.round(area / 7)))\n const farthest = (existing: Json[]) => (p: WallPoint) => -Math.min(9, ...existing.map((t) => Math.hypot(t.u - p.u, t.v - p.v)))\n for (let guard = 0; outletsOf(room).length < wanted && guard < 12; guard++) {\n const best = pick(room, farthest(outletsOf(room)), null)\n if (!best) break\n newOutlet(room, best.point, best.y)\n }\n if (room.type !== 'kitchen' || !counters.some((m) => m.room === room.id)) continue\n for (let guard = 0; outletsOf(room).filter((t) => t.y === 1.1).length < 2 && guard < 4; guard++) {\n const existing = outletsOf(room)\n const best = pick(room, (p) => (heightFor(room, p) === 1.1 ? 0 : 20) - Math.min(9, ...existing.map((t) => Math.hypot(t.u - p.u, t.v - p.v))), 1.1)\n if (!best) break\n newOutlet(room, best.point, 1.1)\n }\n }\n for (const item of appliances) {\n if (item.category === 'shower' || !item.outlet) continue\n const room = roomOf(item)!\n const current = outletsOf(room).find((t) => t.id === item.outlet)\n if (!current || distanceToRect(current.u, current.v, item.aabb) <= 1.2) continue\n const other = outletsOf(room).filter((t) => t.y <= 1.1).map((t) => ({ t, d: distanceToRect(t.u, t.v, item.aabb) })).sort((a, b) => a.d - b.d)[0]\n if (other && other.d < distanceToRect(current.u, current.v, item.aabb) && other.d <= 1.2) item.outlet = other.t.id\n }\n for (const item of items.filter((m) => LAMPS.includes(m.category) && !m.outdoor)) {\n const room = roomOf(item)\n if (!room) continue\n const nearest = outletsOf(room).map((t) => ({ t, d: distanceToRect(t.u, t.v, item.aabb) })).sort((a, b) => a.d - b.d)[0]\n if (nearest) item.outlet = nearest.t.id\n }\n}\n\n","import type { Layout } from './electrical'\nimport { heightOf, keyOf } from './electrical'\nimport type { Json } from './shared'\nimport { clamp, round2 } from './shared'\nimport { atDoor, hasWindowAt } from './wall-points'\n\nconst METER_SIZE = { w: 0.35, d: 0.2, h: 0.5 }\n\nexport const mainDoorOf = (plan: Json): Json | undefined => plan.doors.find((p: Json) => p.floor === 0 && p.exterior && p.side === 'front') || plan.doors.find((p: Json) => p.floor === 0 && p.exterior)\n\n/** Pole, drop, meter and descent: the meter on the gate pillar (or the facade without a gate); an apartment or shop has it on the facade. */\nexport function placeEntrance(layout: Layout): void {\n const { plan, electrical } = layout\n const gate = plan.gates.find((g: Json) => g.type === 'pedestrian')\n const door = mainDoorOf(plan)\n const lot = plan.lot\n if (lot && plan.style !== 'commercial') {\n const rect = lot.rect\n const poleU = clamp(gate ? gate.u + 3 : plan.w / 2, rect[0] + 0.5, rect[2] - 0.5)\n const poleV = rect[1] - 0.6\n let meter: Json\n if (gate) {\n const direction = gate.u - gate.width / 2 - 0.4 >= rect[0] + 0.3 ? -1 : 1\n meter = { place: 'gate_pillar', u: round2(gate.u + direction * (gate.width / 2 + 0.25)), v: round2(gate.v), y: 1.4, side: 'front', ...METER_SIZE }\n } else meter = { place: 'facade', u: round2(door ? door.at + 1.2 : plan.w / 2), v: -0.1, y: 1.4, side: 'front', ...METER_SIZE }\n meter.id = 'meter'\n electrical.serviceEntrance = { pole: { u: round2(poleU), v: round2(poleV), h: 7.5 }, drop: [[round2(poleU), round2(poleV), 6.5], [meter.u, meter.v, 2.6]], meter, descent: [[meter.u, meter.v, 2.6], [meter.u, meter.v, 1.65]], internalRun: null }\n } else if (lot === null || plan.style === 'commercial') {\n const front = door ? { u: round2(door.at + 1.0), v: -0.1 } : { u: round2(plan.w / 2), v: -0.1 }\n electrical.serviceEntrance = {\n pole: { u: round2(front.u + 2), v: -3, h: 7.5 }, drop: [[round2(front.u + 2), -3, 6.5], [front.u, front.v, 3.2]],\n meter: { id: 'meter', place: 'facade', u: front.u, v: front.v, y: 1.4, side: 'front', ...METER_SIZE }, descent: [[front.u, front.v, 3.2], [front.u, front.v, 1.65]], internalRun: null,\n }\n }\n}\n\n/** The distribution panel in the room of the main door, on the wall nearest the meter, clear of doors and windows and of tall furniture. */\nexport function placePanel(layout: Layout): void {\n const { plan, rooms, electrical, pointsOf } = layout\n const door = mainDoorOf(plan)\n const room = (door && rooms.find((c) => c.id === door.a && c.floor === 0)) || rooms.find((c) => c.floor === 0) || rooms[0]\n if (!room) return\n const meter = electrical.serviceEntrance?.meter\n const targetU = meter ? meter.u : plan.w / 2\n const targetV = meter ? Math.max(0, meter.v) : 0\n let best: { point: Json; score: number } | null = null\n for (const point of pointsOf.get(keyOf(room)) ?? []) {\n if (point.blocked(1.5) || hasWindowAt(point, 1.5, 0.3) || atDoor(plan, room, point, 0.8)) continue\n const score = Math.hypot(point.u - targetU, point.v - targetV) + (point.exterior ? 0 : 3)\n if (!best || score < best.score) best = { point, score }\n }\n if (!best) best = { point: (pointsOf.get(keyOf(room)) ?? [])[0] as Json, score: 0 }\n if (best.point) {\n const p = best.point\n electrical.panel = { id: 'panel', room: room.id, floor: room.floor, u: p.u, v: p.v, y: 1.5, c: p.c, axis: p.axis, pos: p.pos, frontU: p.nu, frontV: p.nv, w: 0.3, h: 0.4, breakers: 0 }\n }\n if (electrical.serviceEntrance && electrical.panel) {\n const entrance = electrical.serviceEntrance\n entrance.internalRun = [[entrance.meter.u, entrance.meter.v, 0.1], [electrical.panel.u, electrical.panel.v, heightOf(plan, electrical.panel.floor, electrical.panel.y)]]\n }\n}\n","import type { Layout } from './electrical'\nimport { heightOf, keyOf } from './electrical'\nimport { mainDoorOf } from './electrical-entrance'\nimport type { Json } from './shared'\nimport { round2 } from './shared'\nimport { atDoor, hasWindowAt, wallPointsOf } from './wall-points'\n\nconst LAMP_CATEGORIES = ['ceiling_light', 'lamp', 'table_light']\n\nconst lampsOf = (layout: Layout): Json[] => layout.items.filter((m) => !m.outdoor && LAMP_CATEGORIES.includes(m.category))\n\n/** A switch by the latch of the main door of each room that has a lamp (and of the room of the front door, for the outside lamp), at 1.10 m. */\nexport function addSwitches(layout: Layout): void {\n const { plan, items, rooms, electrical, pointsOf } = layout\n const lamps = lampsOf(layout)\n const door = mainDoorOf(plan)\n let counter = 0\n const positionFor = (room: Json): { point: Json; door: Json; latch: boolean } | null => {\n const doors = plan.doors\n .filter((p: Json) => p.floor === room.floor && (p.a === room.id || p.b === room.id))\n .sort((a: Json, b: Json) => (a.opensTo === room.id ? 0 : 1) - (b.opensTo === room.id ? 0 : 1) || (a.width < b.width ? 1 : -1))\n const points = wallPointsOf(plan, room, items, 0.12)\n for (const tolerance of [0.16, 0.3]) {\n for (const d of doors) {\n for (const direction of [1, -1]) {\n const target = d.at + direction * (d.width / 2 + 0.18)\n const point = points.filter((q) => q.axis === d.axis && Math.abs(q.pos - d.pos) < 1e-3 && !hasWindowAt(q, 1.1, 0.2)).sort((a, b) => Math.abs(a.c - target) - Math.abs(b.c - target))[0]\n if (point && Math.abs(point.c - target) <= tolerance && !atDoor(plan, room, point, 0.0) && Math.abs(point.c - d.at) >= d.width / 2 + 0.12) return { point, door: d, latch: direction === 1 }\n }\n }\n }\n return null\n }\n for (const room of rooms.concat(plan.rooms.filter((x: Json) => ['stairs'].includes(x.type)))) {\n const roomLamps = lamps.filter((m) => m.room === room.id && m.floor === room.floor)\n const extra = door && door.a === room.id && room.floor === 0 && plan.lot ? [`outdoor_${door.id}`] : []\n if (!roomLamps.length && !extra.length) continue\n if (!pointsOf.get(keyOf(room))) pointsOf.set(keyOf(room), wallPointsOf(plan, room, items))\n const found = positionFor(room)\n if (!found) continue\n const p = found.point\n electrical.switches.push({ id: `switch${++counter}`, room: room.id, floor: room.floor, u: p.u, v: p.v, y: 1.1, c: p.c, axis: p.axis, pos: p.pos, frontU: p.nu, frontV: p.nv, door: found.door.id, latchSide: found.latch, controls: roomLamps.map((m) => m.id).concat(extra) })\n }\n if (door && plan.lot) {\n const id = `outdoor_${door.id}`\n electrical.outdoorLamps.push({ id, u: round2(door.at + door.width / 2 + 0.32), v: round2(door.pos), y: 2.15, door: door.id, switch: electrical.switches.find((s) => s.controls.includes(id))?.id ?? null })\n }\n}\n\n/** One circuit per room with sockets or switches, and the conduits: from the panel up to the ceiling, along it to the room and down to each point. */\nexport function addConduits(layout: Layout): void {\n const { plan, rooms, electrical } = layout\n const panel = electrical.panel\n const lamps = lampsOf(layout)\n for (const room of rooms) {\n const outlets = electrical.outlets.filter((t) => t.room === room.id && t.floor === room.floor)\n const switches = electrical.switches.filter((i) => i.room === room.id && i.floor === room.floor)\n const roomLamps = lamps.filter((m) => m.room === room.id && m.floor === room.floor)\n if (!outlets.length && !switches.length) continue\n const ceiling = (room.ceiling || plan.floors[room.floor].ceiling) - 0.12\n const part = room.parts[0]\n const centreU = round2((part[0] + part[2]) / 2)\n const centreV = round2((part[1] + part[3]) / 2)\n const circuit = { id: `circuit_${room.id}_${room.floor}`, room: room.id, floor: room.floor, outlets: outlets.map((t) => t.id), switches: switches.map((i) => i.id), lamps: roomLamps.map((m) => m.id), exposed: electrical.exposed, gauge_mm2: outlets.length > 3 ? 2.5 : 1.5 }\n electrical.circuits.push(circuit)\n const base = heightOf(plan, room.floor, 0)\n const riser = panel ? [[panel.u, panel.v, heightOf(plan, panel.floor, panel.y)], [panel.u, panel.v, heightOf(plan, panel.floor, 0) + ceiling]] : []\n if (panel) electrical.conduits.push({ id: `conduit_${circuit.id}`, circuit: circuit.id, from: 'panel', to: room.id, exposed: electrical.exposed, diameter: 0.025, points: riser.concat([[centreU, centreV, base + ceiling]]) })\n for (const point of outlets.concat(switches)) {\n electrical.conduits.push({ id: `conduit_${point.id}`, circuit: circuit.id, from: circuit.id, to: point.id, exposed: electrical.exposed, diameter: 0.02, points: [[centreU, centreV, base + ceiling], [point.u, point.v, base + ceiling], [point.u, point.v, base + point.y]] })\n }\n }\n if (panel) panel.breakers = electrical.circuits.length + 1\n}\n","import type { Json, Rng } from './shared'\nimport { NO_SOCKET_ROOMS } from './shared'\nimport { addOutlets } from './electrical-outlets'\nimport { addConduits, addSwitches } from './electrical-circuits'\nimport { placeEntrance, placePanel } from './electrical-entrance'\nimport { wallPointsOf } from './wall-points'\nimport type { WallPoint } from './wall-points'\n\nexport type EnergyMode = 'grid' | 'tap' | 'offgrid'\n\n/** What a template says about its energy (a shack taps the grid without a meter, a cabin may run off-grid on solar). */\nexport interface EnergyConfig {\n mode: EnergyMode\n solar?: boolean\n}\n\nexport interface Electrical {\n mode: EnergyMode\n serviceEntrance: Json | null\n panel: Json | null\n outlets: Json[]\n switches: Json[]\n circuits: Json[]\n conduits: Json[]\n exposed: boolean\n outdoorLamps: Json[]\n source?: 'solar' | 'lamp'\n}\n\nexport interface ElectricalContext {\n plan: Json\n items: Json[]\n rng: Rng\n energy?: EnergyConfig\n}\n\n/** Shared state of the steps that lay the installation out. */\nexport interface Layout {\n plan: Json\n items: Json[]\n rooms: Json[]\n electrical: Electrical\n pointsOf: Map<string, WallPoint[]>\n}\n\nexport const keyOf = (room: Json): string => `${room.id}@${room.floor}`\n\nconst absolute = (plan: Json, floor: number, y: number): number => (plan.floors[floor] ? plan.floors[floor].y0 : 0) + y\nexport const heightOf = absolute\n\n/**\n * The electrical installation: sockets for the appliances and by room size, the service entrance (pole, drop, meter, descent; a tap without meter for a shack),\n * the panel near the entrance, switches by the door latch, circuits and conduits. Items that plug in are annotated (`outlet`, `showerHeater`).\n */\nexport function planElectrical(context: ElectricalContext): Electrical {\n const { plan, items, rng, energy } = context\n const mode: EnergyMode = energy?.mode ?? 'grid'\n const electrical: Electrical = { mode, serviceEntrance: null, panel: null, outlets: [], switches: [], circuits: [], conduits: [], exposed: false, outdoorLamps: [] }\n electrical.exposed = plan.style === 'budget' ? rng() < 0.65 : plan.style === 'mid' ? rng() < 0.12 : false\n if (mode !== 'grid') electrical.exposed = true\n if (mode === 'offgrid') {\n electrical.source = energy?.solar ? 'solar' : 'lamp'\n return electrical\n }\n const rooms = plan.rooms.filter((room: Json) => !NO_SOCKET_ROOMS.includes(room.type) && !room.outdoor)\n const pointsOf = new Map<string, WallPoint[]>()\n for (const room of rooms) pointsOf.set(keyOf(room), wallPointsOf(plan, room, items))\n const layout: Layout = { plan, items, rooms, electrical, pointsOf }\n addOutlets(layout)\n placeEntrance(layout)\n placePanel(layout)\n addSwitches(layout)\n addConduits(layout)\n if (mode === 'tap' && electrical.serviceEntrance?.meter) {\n const entrance = electrical.serviceEntrance\n const meter = entrance.meter\n entrance.tap = true\n entrance.connection = { u: meter.u, v: meter.v, y: 2.6 }\n entrance.meter = null\n }\n return electrical\n}\n","import type { Rect } from '../types'\nimport type { Json, Rng } from './shared'\nimport { HALF_WALL, clamp, groundExteriorWalls, inner, isSolid, outwardOf, overlaps, round2, sideNameOf } from './shared'\n\nexport const CYLINDER_TYPE = 'cooking_gas_cylinder'\nconst CYLINDER = { w: 0.36, d: 0.36, h: 0.48 }\nconst CYLINDER_KG = 13\n\nexport interface GasMeter {\n id: 'gas.meter'\n u: number\n v: number\n y: number\n side: string\n w: number\n d: number\n h: number\n}\n\nexport interface Gas {\n type: 'piped' | 'cylinder'\n meter: GasMeter | null\n}\n\ninterface Spot {\n mode: 'beside' | 'niche' | 'under'\n x: number\n z: number\n rect: Rect\n outdoor?: boolean\n cabinet?: string\n}\n\n/** Gas meter on the front wall of the ground floor, 1.2 m up. */\nfunction placeMeter(plan: Json): GasMeter | null {\n const segments = groundExteriorWalls(plan).sort((a, b) => (b.sides.includes('outside') ? 1 : 0) - (a.sides.includes('outside') ? 1 : 0) || (a.axis === 'u' && a.v0 === 0 ? -1 : 1))\n const wall = segments.find((w) => w.axis === 'u' && w.v0 === 0) || segments[0]\n if (!wall) return null\n const centre = wall.axis === 'u' ? (wall.u0 + wall.u1) / 2 : (wall.v0 + wall.v1) / 2\n const vector = outwardOf(wall)\n const offset = HALF_WALL + 0.1\n return {\n id: 'gas.meter', u: round2(wall.axis === 'u' ? centre : wall.u0 + vector[0] * offset), v: round2(wall.axis === 'u' ? wall.v0 + vector[1] * offset : centre), y: 1.2, side: sideNameOf(vector), w: 0.3, d: 0.15, h: 0.4,\n }\n}\n\ninterface Context {\n plan: Json\n items: Json[]\n stateItems: Json[]\n rng: Rng\n}\n\nfunction besideStove(context: Context, stove: Json, room: Json, solids: Rect[], doorZones: Rect[]): Spot | undefined {\n const t: [number, number] = [-stove.frontV, stove.frontU]\n const parts = room.parts.map(inner)\n for (const s of context.rng() < 0.5 ? [1, -1] : [-1, 1]) {\n const cx = stove.x + t[0] * s * (stove.w / 2 + CYLINDER.w / 2 + 0.03) - (stove.frontU * (stove.d - CYLINDER.d)) / 2\n const cz = stove.z + t[1] * s * (stove.w / 2 + CYLINDER.w / 2 + 0.03) - (stove.frontV * (stove.d - CYLINDER.d)) / 2\n const rect = [cx - CYLINDER.w / 2, cz - CYLINDER.d / 2, cx + CYLINDER.w / 2, cz + CYLINDER.d / 2].map(round2) as Rect\n const inside = parts.some((q: Rect) => rect[0] >= q[0] - 0.011 && rect[2] <= q[2] + 0.011 && rect[1] >= q[1] - 0.011 && rect[3] <= q[3] + 0.011)\n if (inside && !solids.some((o) => overlaps(rect, o, 0.011)) && !doorZones.some((z) => overlaps(rect, z, 0.011))) return { mode: 'beside', x: cx, z: cz, rect }\n }\n return undefined\n}\n\nfunction inNiche(context: Context, stove: Json, room: Json, doorZones: Rect[]): Spot | undefined {\n const { plan, items, stateItems } = context\n const wall = plan.walls.find(\n (p: Json) =>\n p.exterior && p.floor === stove.floor && p.type === 'wall' && p.sides.includes(room.id) &&\n (p.axis === 'u'\n ? Math.abs(stove.x - clamp(stove.x, p.u0, p.u1)) < 1.6 && Math.abs(stove.z - p.v0) < 1.6\n : Math.abs(stove.z - clamp(stove.z, p.v0, p.v1)) < 1.6 && Math.abs(stove.x - p.u0) < 1.6),\n )\n if (!wall || stove.floor !== 0) return undefined\n const vector = outwardOf(wall)\n const cx = wall.axis === 'u' ? clamp(stove.x, wall.u0 + 0.4, wall.u1 - 0.4) : wall.u0 + vector[0] * (HALF_WALL + CYLINDER.w / 2 + 0.05)\n const cz = wall.axis === 'u' ? wall.v0 + vector[1] * (HALF_WALL + CYLINDER.d / 2 + 0.05) : clamp(stove.z, wall.v0 + 0.4, wall.v1 - 0.4)\n const rect = [cx - CYLINDER.w / 2, cz - CYLINDER.d / 2, cx + CYLINDER.w / 2, cz + CYLINDER.d / 2].map(round2) as Rect\n const blockedByItem = items.some((o) => o.outdoor && isSolid(o) && overlaps(rect, o.aabb, 0.011))\n const blockedByState = stateItems.some((o) => o.outdoor && o.aabb && !o.flat && o.mount !== 'ground' && overlaps(rect, o.aabb, 0.011))\n const blockedByPath = plan.paths.some((c: Json) => c.rects.some((z: Rect) => overlaps(rect, z, 0.011)))\n const blockedByGate = plan.gates.some((g: Json) => g.zones.some((z: Rect) => overlaps(rect, z, 0.011)))\n const blockedByFence = !plan.lot || plan.lot.perimeter.some((q: Json) => overlaps(rect, [Math.min(q.u0, q.u1) - HALF_WALL, Math.min(q.v0, q.v1) - HALF_WALL, Math.max(q.u0, q.u1) + HALF_WALL, Math.max(q.v0, q.v1) + HALF_WALL], 0.011))\n if (blockedByItem || blockedByState || blockedByPath || doorZones.some((z) => overlaps(rect, z, 0.011)) || blockedByGate || blockedByFence) return undefined\n return { mode: 'niche', x: cx, z: cz, rect, outdoor: true }\n}\n\nfunction underCounter(context: Context, stove: Json): Spot | undefined {\n const distance = (m: Json): number => Math.hypot(m.x - stove.x, m.z - stove.z)\n const cabinets = context.items\n .filter(\n (m) => m.floor === stove.floor && m.room === stove.room && !m.outdoor && !m.on && !m.flat && ['kitchen_cabinet', 'workbench'].includes(m.category) && m.aabb && m.id !== stove.id &&\n Math.min(m.aabb[2] - m.aabb[0], m.aabb[3] - m.aabb[1]) >= CYLINDER.d - 0.011 && Math.max(m.aabb[2] - m.aabb[0], m.aabb[3] - m.aabb[1]) >= CYLINDER.w + 0.02,\n )\n .sort((a, b) => (a.category === 'kitchen_cabinet' ? 0 : 1) - (b.category === 'kitchen_cabinet' ? 0 : 1) || distance(a) - distance(b))\n for (const cabinet of cabinets) {\n if (distance(cabinet) > 3) continue\n const box = cabinet.aabb as Rect\n const hw = CYLINDER.w / 2\n const hd = CYLINDER.d / 2\n const cx = clamp(stove.x, box[0] + hw + 0.01, box[2] - hw - 0.01)\n const cz = clamp(stove.z, box[1] + hd + 0.01, box[3] - hd - 0.01)\n const rect = [cx - hw, cz - hd, cx + hw, cz + hd].map(round2) as Rect\n if (rect[0] < box[0] || rect[2] > box[2] || rect[1] < box[1] || rect[3] > box[3] || overlaps(rect, stove.aabb, 0.011)) continue\n return { mode: 'under', x: cx, z: cz, rect, cabinet: cabinet.id }\n }\n return undefined\n}\n\nconst PLACEMENT = { beside: 'beside', niche: 'external_niche', under: 'under_counter' } as const\n\nfunction cylinderItem(stove: Json, spot: Spot): Json {\n const item: Json = {\n id: `${stove.room}.${CYLINDER_TYPE}`, type: CYLINDER_TYPE, category: CYLINDER_TYPE, x: round2(spot.x), z: round2(spot.z), ry: 0, w: CYLINDER.w, d: CYLINDER.d, h: CYLINDER.h, y: 0,\n frontU: -stove.frontU, frontV: -stove.frontV, room: stove.room, floor: stove.floor, outdoor: !!spot.outdoor, slot: 'cylinder', on: null, mode: null, clearance: 0, flat: false, low: false,\n aabb: spot.rect, link: stove.id, placement: PLACEMENT[spot.mode], hose: [[round2(spot.x), round2(spot.z), 0.3], [stove.x, stove.z, 0.5]], capacityKg: CYLINDER_KG,\n }\n if (spot.cabinet) {\n item.on = spot.cabinet\n item.hidden = true\n }\n if (spot.outdoor) item.floor = -1\n item.color = stove.color\n return item\n}\n\n/**\n * Gas for the stoves of the house: a cylinder beside the stove, in an outside niche with a hose or under the counter, or (high-end houses, or when\n * nothing fits) piped gas with a meter on the facade. The cylinders are added to `items`; the stoves are annotated (`gas`, `cylinder`, `gasMeter`).\n */\nexport function planGas(context: Context): Gas | null {\n const { plan, items, stateItems, rng } = context\n const stoves = items.filter((m) => m.category === 'stove' && !m.outdoor)\n if (!stoves.length) return null\n const high = plan.style === 'high'\n const piped = plan.style !== 'commercial' && (high ? rng() < 0.8 : plan.style === 'mid' ? rng() < 0.1 : false)\n const out: Gas = { type: piped ? 'piped' : 'cylinder', meter: null }\n const ensureMeter = (): void => {\n if (!out.meter) out.meter = placeMeter(plan)\n }\n for (const stove of stoves) {\n const room = plan.rooms.find((c: Json) => c.id === stove.room && c.floor === stove.floor)\n if (!room) continue\n stove.gas = piped ? 'piped' : 'cylinder'\n if (piped) {\n ensureMeter()\n stove.gasMeter = 'gas.meter'\n continue\n }\n const solids = items.filter((m) => m.floor === stove.floor && m.room === stove.room && isSolid(m) && m.id !== stove.id).map((m) => m.aabb as Rect)\n .concat(stateItems.filter((m) => m.aabb && m.room === stove.room && m.floor === stove.floor && !m.flat && !m.on && m.mount !== 'window' && m.mount !== 'ground').map((m) => m.aabb as Rect))\n const doorZones = plan.doors.filter((p: Json) => p.floor === stove.floor).flatMap((p: Json) => p.zones as Rect[])\n const order: Spot['mode'][] = rng() < 0.7 ? ['beside', 'niche', 'under'] : ['niche', 'beside', 'under']\n let spot: Spot | undefined\n for (const mode of order) {\n if (spot) break\n spot = mode === 'beside' ? besideStove(context, stove, room, solids, doorZones) : mode === 'niche' ? inNiche(context, stove, room, doorZones) : underCounter(context, stove)\n }\n if (!spot) {\n stove.gas = 'piped'\n out.type = 'piped'\n ensureMeter()\n stove.gasMeter = 'gas.meter'\n continue\n }\n const cylinder = cylinderItem(stove, spot)\n items.push(cylinder)\n stove.cylinder = cylinder.id\n }\n return out\n}\n","import type { Json } from './shared'\nimport { round2 } from './shared'\nimport type { WaterTank } from '../types'\n\nconst FIXTURES: Record<string, string> = { kitchen_cabinet: 'tap', washbasin: 'tap', shower: 'shower', toilet: 'flush', laundry_tub: 'tub', washing_machine: 'machine' }\nconst FLOW_LPM: Record<string, number> = { tap: 6, shower: 9, flush: 6, tub: 8, machine: 12 }\nconst POINT_HEIGHT: Record<string, number> = { shower: 2.1, flush: 0.9, machine: 0.8 }\nconst DEFAULT_CAPACITY = { budget: 500, mid: 1000 }\n\nexport interface PlumbingContext {\n plan: Json\n items: Json[]\n tank: WaterTank | null\n}\n\nconst absolute = (plan: Json, floor: number, y: number): number => (plan.floors[floor] ? plan.floors[floor].y0 : 0) + y\n\n/**\n * Plumbing as logic: a point for every tap, shower, toilet, tub and machine, and the runs you can see: the outlet of the tank, under each sink and in the wall\n * from the tank to every wet room (hidden in the wall, it shows only where the wall breaks).\n */\nexport function planPlumbing(context: PlumbingContext): Json {\n const { plan, items, tank } = context\n const fixtures = items.filter((m) => FIXTURES[m.category] && !m.decor)\n const points: Json[] = []\n const runs: Json[] = []\n const capacity = tank?.capacity ?? (plan.style === 'budget' ? DEFAULT_CAPACITY.budget : plan.style === 'mid' ? DEFAULT_CAPACITY.mid : plan.tpl?.id === 'mansion' ? 3000 : 2000)\n const plumbing: Json = { tank: tank ? 'water_tank' : null, capacityL: tank || !plan.tpl.noWalls ? capacity : 0, points, visibleRuns: runs }\n const top = plan.floors.length - 1\n fixtures.forEach((item, index) => {\n const kind = FIXTURES[item.category]!\n points.push({ id: `pt${index + 1}`, kind, item: item.id, room: item.room, floor: item.outdoor ? -1 : item.floor, u: item.x, v: item.z, y: POINT_HEIGHT[kind] ?? 0.9, flowLpm: FLOW_LPM[kind], run: null })\n })\n if (!tank) return plumbing\n const slabY = absolute(plan, top, plan.floors[top].ceiling)\n const tankY = tank.place === 'raised_slab' ? tank.platform!.topY : tank.place === 'attic' ? slabY + 0.5 : tank.y\n runs.push({ id: 'run_outlet', from: 'water_tank', to: 'ceiling', points: [[tank.u, tank.v, round2(tankY + 0.15)], [tank.u, tank.v, round2(slabY - 0.15)]], diameter: 0.032, exposed: 'tank_outlet' })\n for (const point of points) {\n const item = fixtures.find((x) => x.id === point.item)!\n if (point.kind !== 'tap' || item.outdoor) continue\n const front = [item.frontU || 0, item.frontV || 1]\n const behind = [item.x - front[0]! * (item.d / 2 + 0.02), item.z - front[1]! * (item.d / 2 + 0.02)]\n runs.push({ id: `run_under_${point.id}`, from: 'valve', to: point.id, points: [[round2(behind[0]!), round2(behind[1]!), absolute(plan, item.floor, 0.5)], [item.x, item.z, absolute(plan, item.floor, 0.5)], [item.x, item.z, absolute(plan, item.floor, 0.75)]], diameter: 0.025, exposed: 'under_sink' })\n }\n const wet: { room: string; floor: number; points: Json[] }[] = []\n for (const point of points) {\n if (!wet.some((c) => c.room === point.room && c.floor === point.floor)) wet.push({ room: point.room, floor: point.floor, points: points.filter((q) => q.room === point.room && q.floor === point.floor) })\n }\n for (const room of wet) {\n const found = plan.rooms.find((c: Json) => c.id === room.room && c.floor === room.floor)\n const zone = plan.zones.find((z: Json) => z.id === room.room)\n const parts = (found || zone || { parts: [[tank.u, tank.v, tank.u, tank.v]] }).parts\n const centreU = (parts[0][0] + parts[0][2]) / 2\n const centreV = (parts[0][1] + parts[0][3]) / 2\n const ceiling = found ? found.ceiling || plan.floors[found.floor].ceiling : 2.8\n const y0 = found ? absolute(plan, found.floor, 0) : 0\n const id = `run_wall_${room.room}${room.floor === -1 ? '_outside' : `_${room.floor}`}`\n runs.push({ id, from: 'water_tank', to: room.room, points: [[tank.u, tank.v, round2(slabY - 0.15)], [round2(centreU), round2(centreV), round2(slabY - 0.15)], [round2(centreU), round2(centreV), round2(y0 + ceiling - 0.15)], [round2(centreU), round2(centreV), round2(y0 + 0.6)]], diameter: 0.025, exposed: 'wall' })\n for (const point of room.points) point.run = id\n }\n return plumbing\n}\n","import { outwardOf, groundExteriorWalls, HALF_WALL, round2, sideNameOf } from './shared'\nimport type { Json, Rng } from './shared'\nimport type { EnergyConfig } from './electrical'\n\nconst PANEL_WIDTH = 1.0\nconst PANEL_LENGTH = 1.65\nconst NO_PANELS_UNDER: readonly string[] = ['void', 'elevator', 'stairs', 'balcony', 'terrace', 'porch']\n\nexport interface SolarContext {\n plan: Json\n rng: Rng\n energy?: EnergyConfig\n}\n\n/** Inverter on a side wall of the ground floor, 1.5 m up. */\nfunction placeInverter(plan: Json): Json | null {\n const wall = groundExteriorWalls(plan).filter((q) => q.sides.includes('outside')).sort((a, b) => (a.axis === 'v' ? 0 : 1) - (b.axis === 'v' ? 0 : 1))[0]\n if (!wall) return null\n const vector = outwardOf(wall)\n const centre = wall.axis === 'u' ? (wall.u0 + wall.u1) / 2 : (wall.v0 + wall.v1) / 2\n const offset = HALF_WALL + 0.08\n return { id: 'inverter', u: round2(wall.axis === 'u' ? centre : wall.u0 + vector[0] * offset), v: round2(wall.axis === 'u' ? wall.v0 + vector[1] * offset : centre), y: 1.5, side: sideNameOf(vector), w: 0.4, d: 0.15, h: 0.5, outdoor: true, link: 'panel' }\n}\n\n/**\n * Solar panels: about 6% of budget houses, 25% of mid and 50% of the rest; on the roof slope that faces north or on tilted racks on a flat roof, with the\n * inverter on the wall. A template with its own energy decides (`energy.solar`).\n */\nexport function planSolar(context: SolarContext): Json | null {\n const { plan, rng, energy } = context\n if (!plan.lot || plan.style === 'commercial' || !plan.facade) return null\n const chance = plan.style === 'budget' ? 0.06 : plan.style === 'mid' ? 0.25 : 0.5\n const forced = energy ? (energy.solar ? 1 : 0) : null\n const draw = rng()\n if (forced !== null ? !forced : draw >= chance) return null\n const floor = plan.floors.length - 1\n const level = plan.floors[floor]\n const flat = plan.facade.roof === 'slab'\n const tops = plan.rooms.filter((c: Json) => c.floor === floor && !NO_PANELS_UNDER.includes(c.type))\n if (!tops.length) return null\n const parts: number[][] = tops.flatMap((c: Json) => c.parts)\n const box = [Math.min(...parts.map((q) => q[0]!)), Math.min(...parts.map((q) => q[1]!)), Math.max(...parts.map((q) => q[2]!)), Math.max(...parts.map((q) => q[3]!))] as [number, number, number, number]\n const north = rng() < 0.5 ? 'front' : 'back'\n const angle = flat ? 15 : 25\n const projection = round2(PANEL_LENGTH * Math.cos((angle * Math.PI) / 180))\n const margin = 0.6\n const uStart = box[0] + margin\n const uEnd = box[2] - margin\n const columns = Math.max(1, Math.floor((uEnd - uStart) / (PANEL_WIDTH + 0.05)))\n const vMiddle = (box[1] + box[3]) / 2\n const vArea = flat ? [box[1] + margin, box[3] - margin] : north === 'front' ? [box[1] + 0.4, vMiddle - 0.2] : [vMiddle + 0.2, box[3] - 0.4]\n const step = flat ? projection + 0.5 : projection + 0.05\n const rowsMax = Math.max(1, Math.floor((vArea[1]! - vArea[0]!) / step))\n const wanted = forced !== null ? 1 + Math.floor(rng() * 2) : 3 + Math.floor(rng() * (plan.style === 'high' ? 12 : 8))\n const rows = Math.max(1, Math.min(rowsMax, Math.ceil(wanted / columns)))\n const count = Math.min(wanted, rows * columns)\n const u0 = uStart + (uEnd - uStart - columns * (PANEL_WIDTH + 0.05)) / 2\n const vStart = north === 'front' ? vArea[0]! : vArea[1]! - rows * step\n const panels: Json[] = []\n for (let k = 0; k < count; k++) {\n const row = Math.floor(k / columns)\n const column = k % columns\n panels.push({ id: `pv${k + 1}`, u: round2(u0 + column * (PANEL_WIDTH + 0.05) + PANEL_WIDTH / 2), v: round2(vStart + row * step + (flat ? 0.25 : 0) + projection / 2), w: PANEL_WIDTH, d: projection, length: PANEL_LENGTH })\n }\n const area = [round2(u0), round2(vStart), round2(u0 + columns * (PANEL_WIDTH + 0.05)), round2(vStart + rows * step)]\n return { type: flat ? 'slab_rack' : 'roof', orientation: 'north', north, slopeSide: flat ? null : north, tilt: angle, area, areaM2: round2(count * PANEL_WIDTH * PANEL_LENGTH), count, floor, y: round2(level.y0 + level.ceiling), panels, inverter: placeInverter(plan) }\n}\n","import type { FindsQuery, FindStack } from '@adatechnology/game-floorplan'\n\nimport type { WaterTank } from '../types'\nimport { hasContent } from './content'\nimport type { EnergyConfig, Electrical } from './electrical'\nimport { planElectrical } from './electrical'\nimport { planGas } from './gas'\nimport type { Gas } from './gas'\nimport { planPlumbing } from './plumbing'\nimport type { Json, Rng } from './shared'\nimport { planSolar } from './solar'\n\nexport interface Utilities {\n gas: Gas | null\n electrical: Electrical\n solar: Json | null\n plumbing: Json\n}\n\nexport interface UtilitiesContext {\n plan: Json\n items: Json[]\n stateItems: Json[]\n tank: WaterTank | null\n energy?: EnergyConfig\n /** Seeded stream by name: `gas`, `electrical`, `solar`. */\n rngFor(key: string): Rng\n}\n\n/** Gas, electricity, solar panels and plumbing of a house, in the order that lets the later ones see the cylinders the first adds to `items`. */\nexport function planUtilities(context: UtilitiesContext): Utilities {\n const { plan, items, stateItems, tank, energy, rngFor } = context\n const gas = planGas({ plan, items, stateItems, rng: rngFor('gas') })\n const electrical = planElectrical({ plan, items, rng: rngFor('eletrica'), ...(energy ? { energy } : {}) })\n const solar = planSolar({ plan, rng: rngFor('solar'), ...(energy ? { energy } : {}) })\n const plumbing = planPlumbing({ plan, items, tank })\n return { gas, electrical, solar, plumbing }\n}\n\nconst OVERHEAD = 'overhead_cabinet'\nconst ALWAYS_HOLD: readonly string[] = ['trash_bin', 'outdoor_bin', 'mailbox']\n\nexport interface ContentsContext {\n items: Json[]\n state: string\n place: string\n /** Outbreak days and region of the world, passed to the finds provider. */\n day?: number\n region?: string\n rngFor(key: string): Rng\n findsFor(query: FindsQuery): readonly FindStack[]\n}\n\n/** What every container holds, asked of the registered finds provider: by item id, and `<id>#overhead` for the wall cabinet over a sink. */\nexport function planContents(context: ContentsContext): Record<string, readonly FindStack[]> {\n const out: Record<string, readonly FindStack[]> = {}\n const ask = (item: Json, container: string, key: string): readonly FindStack[] =>\n context.findsFor({ place: context.place, container, state: context.state, rng: context.rngFor(key), footprint: item.w * item.d, key: item.id, ...(context.day === undefined ? {} : { day: context.day }), ...(context.region === undefined ? {} : { region: context.region }) })\n for (const item of context.items) {\n if (item.decor && item.mount !== 'wall_top') continue\n const container = hasContent(item.type) ? item.type : item.category\n if (!hasContent(container)) continue\n if (!ALWAYS_HOLD.includes(container) && item.decor) continue\n out[item.id] = ask(item, container, `content:${item.id}`)\n if (container === 'kitchen_cabinet' && item.overhead !== false) out[`${item.id}#overhead`] = ask(item, OVERHEAD, `content:${item.id}:overhead`)\n }\n return out\n}\n","import type { Rect } from '../types'\nimport type { Json, Rng } from './shared'\nimport { isSolid, overlaps, round2 } from './shared'\n\nconst WALL = 0.15\nconst DOOR_WIDTH = 0.85\nconst DOOR_HEIGHT = 2.1\nconst USES: Record<string, string[]> = { guest_room: ['single_bed', 'nightstand'], office: ['desk', 'shelf_unit_small'], storage: ['tool_shelf', 'crate'], gourmet: ['dining_table_small', 'workbench'] }\nconst USE_WEIGHTS: Record<string, number> = { guest_room: 3, office: 2, storage: 2, gourmet: 2 }\nconst PATH_WIDTH = 1.0\n\nexport interface OutbuildingContext {\n plan: Json\n items: Json[]\n catalog: Record<string, Json>\n rngFor(key: string): Rng\n}\n\n/**\n * Name of the seeded stream of an outbuilding. It is the name the Visor de casas 3D gave it (`edif:<room>.<slot>` in Portuguese: `quintal.edicula`), kept verbatim so that an\n * old seed draws the same use and furniture; it never appears in the output.\n */\nconst LEGACY_ROOMS: Record<string, string> = { backyard: 'quintal' }\nconst LEGACY_SLOTS: Record<string, string> = { outbuilding: 'edicula' }\nexport const streamOf = (itemId: string): string => {\n const [room = '', ...slot] = itemId.split('.')\n return `edif:${LEGACY_ROOMS[room] ?? room}.${slot.map((part) => LEGACY_SLOTS[part] ?? part).join('.')}`\n}\n\nfunction pickWeighted(rng: Rng, weights: Record<string, number>): string {\n const keys = Object.keys(weights)\n let x = rng() * keys.reduce((sum, key) => sum + weights[key]!, 0)\n for (const key of keys) {\n x -= weights[key]!\n if (x < 0) return key\n }\n return keys[keys.length - 1]!\n}\n\nconst sideOf = (x: number, z: number): string => (Math.abs(x) > Math.abs(z) ? (x > 0 ? 'right' : 'left') : z > 0 ? 'back' : 'front')\n\ninterface Frame {\n n: [number, number]\n t: [number, number]\n cx: number\n cz: number\n depth: number\n width: number\n horizontal: boolean\n sideToMiddle: number\n}\n\nconst at = (frame: Frame, a: number, b: number): [number, number] => [frame.cx + frame.n[0] * a + frame.t[0] * b, frame.cz + frame.n[1] * a + frame.t[1] * b]\n\nfunction opening(frame: Frame, id: string, a: number, b: number, vector: [number, number], width: number, extra: Json): Json {\n const [u, v] = at(frame, a, b)\n const alongU = Math.abs(vector[0]) !== 1\n return { id, axis: alongU ? 'u' : 'v', pos: round2(alongU ? v : u), at: round2(alongU ? u : v), u: round2(u), v: round2(v), width: round2(width), side: sideOf(vector[0], vector[1]), ...extra }\n}\n\nfunction wallsOf(box: Rect, door: Json, height: number): Json[] {\n const walls: Json[] = []\n const sides = [\n { axis: 'u', pos: box[1], i0: box[0], i1: box[2], side: 'front' }, { axis: 'u', pos: box[3], i0: box[0], i1: box[2], side: 'back' },\n { axis: 'v', pos: box[0], i0: box[1], i1: box[3], side: 'left' }, { axis: 'v', pos: box[2], i0: box[1], i1: box[3], side: 'right' },\n ]\n for (const w of sides) {\n const cut = w.axis === door.axis && Math.abs(w.pos - door.pos) < 0.02 ? [door.at - door.width / 2, door.at + door.width / 2] : null\n const segments = cut ? [[w.i0, cut[0]!], [cut[1]!, w.i1]] : [[w.i0, w.i1]]\n for (const [x0, x1] of segments) {\n if (x1! - x0! <= 1e-3) continue\n walls.push(w.axis === 'u' ? { axis: 'u', u0: round2(x0!), v0: round2(w.pos), u1: round2(x1!), v1: round2(w.pos), thickness: WALL, h: height, side: w.side } : { axis: 'v', u0: round2(w.pos), v0: round2(x0!), u1: round2(w.pos), v1: round2(x1!), thickness: WALL, h: height, side: w.side })\n }\n }\n return walls\n}\n\nfunction furnish(context: OutbuildingContext, frame: Frame, use: string, interior: Rect, insideDoor: Rect): Json[] {\n const placed: Json[] = []\n USES[use]!.forEach((type, k) => {\n const def = context.catalog[type]!\n const facing: [number, number] = k === 0 ? frame.n : [frame.t[0] * frame.sideToMiddle, frame.t[1] * frame.sideToMiddle]\n const [a, b] = k === 0 ? [-frame.depth / 2 + WALL + def.d / 2, frame.sideToMiddle * -0.4] : [-0.1, -frame.sideToMiddle * (frame.width / 2 - WALL - def.d / 2)]\n const [u, v] = at(frame, a, b)\n const eu = Math.abs(facing[0]) === 1 ? def.d : def.w\n const ev = Math.abs(facing[0]) === 1 ? def.w : def.d\n const box = [u - eu / 2, v - ev / 2, u + eu / 2, v + ev / 2].map(round2) as Rect\n if (box[0] < interior[0] - 0.011 || box[2] > interior[2] + 0.011 || box[1] < interior[1] - 0.011 || box[3] > interior[3] + 0.011 || overlaps(box, insideDoor) || placed.some((o) => overlaps(box, o.aabb))) return\n placed.push({ type, category: def.category, u: round2(u), v: round2(v), w: def.w, d: def.d, h: def.h, ry: Math.atan2(facing[0], facing[1]), frontU: facing[0], frontV: facing[1], aabb: box })\n })\n return placed\n}\n\n/**\n * The outbuilding at the back of the yard is a small building of its own: walls with a gap for the door, a door of 0.85 m facing the yard, two windows and the\n * furniture of a drawn use (guest room, office, storage, gourmet space).\n */\nexport function planOutbuildings(context: OutbuildingContext): Json[] {\n const { plan, items } = context\n const lot = plan.lot\n if (!lot) return []\n const out: Json[] = []\n for (const item of items.filter((m) => m.category === 'outbuilding')) {\n const rng = context.rngFor(streamOf(item.id))\n const [a0, a1, a2, a3] = item.aabb as Rect\n const n: [number, number] = [item.frontU, item.frontV]\n const t: [number, number] = [-item.frontV, item.frontU]\n const horizontal = Math.abs(item.frontU) === 1\n const cx = (a0 + a2) / 2\n const cz = (a1 + a3) / 2\n const depth = horizontal ? a2 - a0 : a3 - a1\n const width = horizontal ? a3 - a1 : a2 - a0\n const sideToMiddle = ((lot.rect[0] + lot.rect[2]) / 2 - cx) * t[0] + ((lot.rect[1] + lot.rect[3]) / 2 - cz) * t[1] >= 0 ? 1 : -1\n const frame: Frame = { n, t, cx, cz, depth, width, horizontal, sideToMiddle }\n const doorOffset = sideToMiddle * (width / 2 - 0.95)\n const door = opening(frame, `${item.id}.d0`, depth / 2, doorOffset, n, DOOR_WIDTH, { height: DOOR_HEIGHT, exterior: true })\n const windowFront = opening(frame, `${item.id}.w0`, depth / 2, -sideToMiddle * (width / 2 - 0.9), n, Math.min(1.0, width / 2 - 0.6), { y0: 1.0, y1: 2.0 })\n const windowSide = opening(frame, `${item.id}.w1`, 0, (sideToMiddle * width) / 2, [t[0] * sideToMiddle, t[1] * sideToMiddle], Math.min(1.0, depth - 0.8), { y0: 1.0, y1: 2.0 })\n const [p, q] = [at(frame, depth / 2, doorOffset), at(frame, depth / 2 - 0.9, doorOffset)]\n door.zone = (horizontal ? [Math.min(p[0], q[0]), p[1] - door.width / 2, Math.max(p[0], q[0]), p[1] + door.width / 2] : [p[0] - door.width / 2, Math.min(p[1], q[1]), p[0] + door.width / 2, Math.max(p[1], q[1])]).map(round2)\n const interior: Rect = [a0 + WALL, a1 + WALL, a2 - WALL, a3 - WALL]\n const use = pickWeighted(rng, USE_WEIGHTS)\n out.push({ id: item.id, type: 'outbuilding', use, floor: 0, aabb: (item.aabb as Rect).slice(), interior: [interior.map(round2)], ceiling: item.h, thickness: WALL, front: n, walls: wallsOf(item.aabb, door, item.h), doors: [door], windows: [windowFront, windowSide], items: furnish(context, frame, use, interior, door.zone) })\n }\n return out\n}\n\n/** A pedestrian path from every door of an outbuilding: a 1 m stub out of the door and an L to the nearest existing path, away from furniture, the building and the fence. */\nexport function addOutbuildingPaths(lot: Json, outbuildings: Json[], items: Json[]): void {\n const half = PATH_WIDTH / 2\n const rect = lot.rect as Rect\n const solids = items.filter((m) => m.outdoor && m.aabb && isSolid(m)).map((m) => m.aabb as Rect)\n const fence = lot.perimeter.map((q: Json) => [Math.min(q.u0, q.u1) - 0.075, Math.min(q.v0, q.v1) - 0.075, Math.max(q.u0, q.u1) + 0.075, Math.max(q.v0, q.v1) + 0.075] as Rect)\n const strip = (p: number[], q: number[]): Rect => [Math.min(p[0]!, q[0]!) - half, Math.min(p[1]!, q[1]!) - half, Math.max(p[0]!, q[0]!) + half, Math.max(p[1]!, q[1]!) + half]\n for (const building of outbuildings) {\n for (const door of building.doors as Json[]) {\n if (lot.paths.some((c: Json) => c.to === door.id)) continue\n const z = door.zone as Rect\n const zc = door.axis === 'v' ? (z[0] + z[2]) / 2 : (z[1] + z[3]) / 2\n const outside = zc > door.pos ? -1 : 1\n const A = door.axis === 'v' ? [door.pos, door.at] : [door.at, door.pos]\n const S = door.axis === 'v' ? [door.pos + outside * PATH_WIDTH, door.at] : [door.at, door.pos + outside * PATH_WIDTH]\n const stub: Rect = door.axis === 'v' ? [Math.min(A[0]!, S[0]!), A[1]! - half, Math.max(A[0]!, S[0]!), A[1]! + half] : [A[0]! - half, Math.min(A[1]!, S[1]!), A[0]! + half, Math.max(A[1]!, S[1]!)]\n const cost = (rs: Rect[]): number => {\n let n = 0\n for (const r of rs) {\n const c: Rect = [r[0] + 0.02, r[1] + 0.02, r[2] - 0.02, r[3] - 0.02]\n for (const q of solids) if (overlaps(c, q, 0.011)) n += 2\n if (overlaps(c, building.aabb, 0.011)) n += 3\n for (const q of fence) if (overlaps(c, q, 0.011)) n += 3\n if (r[0] < rect[0] || r[1] < rect[1] || r[2] > rect[2] || r[3] > rect[3]) n += 3\n }\n return n\n }\n let best: { v: number; k: { rects: Rect[]; points: number[][] }; from: string | null } | null = null\n for (const c of lot.paths.filter((p: Json) => p.type === 'pedestrian' || p.id === 'cargo_path')) {\n for (const r of c.rects as Rect[]) {\n const T = [Math.min(Math.max(S[0]!, r[0] + half), r[2] - half), Math.min(Math.max(S[1]!, r[1] + half), r[3] - half)]\n const candidates: { rects: Rect[]; points: number[][] }[] = []\n if (Math.abs(T[0]! - S[0]!) < 1e-6 && Math.abs(T[1]! - S[1]!) < 1e-6) candidates.push({ rects: [stub], points: [A, S] })\n else for (const via of [[T[0]!, S[1]!], [S[0]!, T[1]!]]) candidates.push({ rects: [stub, strip(S, via), strip(via, T)].filter((q) => q[2] - q[0] > 1e-6), points: [A, S, via, T] })\n for (const k of candidates) {\n const distance = k.points.slice(1).reduce((sum, q, i) => sum + Math.abs(q[0]! - k.points[i]![0]!) + Math.abs(q[1]! - k.points[i]![1]!), 0)\n const value = cost(k.rects.slice(1)) * 100 + distance\n if (!best || value < best.v) best = { v: value, k, from: c.from }\n }\n }\n }\n const chosen = best ? best.k : { rects: [stub], points: [A, S] }\n lot.paths.push({ id: `path_${door.id}`, type: 'pedestrian', from: best ? best.from : null, to: door.id, width: PATH_WIDTH, rects: chosen.rects.map((q) => q.map(round2)), points: chosen.points.map((q) => q.map(round2)) })\n }\n }\n}\n","import { round2 } from './geometry'\nimport type { Rect, StructureSource, WaterTank } from './types'\n\ntype Rng = () => number\n\nconst TANK_SIDE = 1.1\nconst NOT_UNDER_TANK = ['void', 'elevator', 'stairs', 'balcony', 'porch']\nconst WET_ROOMS = ['bathroom', 'kitchen', 'laundry']\nconst ATTIC_CHANCE = 0.12\nconst clamp = (value: number, low: number, high: number): number => Math.max(low, Math.min(high, value))\n\nexport interface TankPlanOptions {\n /** Litres by template id or style id (default: budget 500, mid 1000, mansion 3000, any other 2000). */\n capacities?: Record<string, number>\n /** Where the tank goes; default: on the slab of a flat roof, else on a raised platform (the attic one time in eight). */\n location?: (source: StructureSource, rng: Rng) => WaterTank['place']\n /** A template with its own tank (a trestle for the rural water) answers here instead. */\n custom?: (source: StructureSource, rng: Rng) => WaterTank | null\n}\n\nconst DEFAULT_CAPACITIES: Record<string, number> = { budget: 500, mid: 1000, mansion: 3000 }\n\nfunction capacityOf(source: StructureSource, capacities: Record<string, number>): number {\n return capacities[source.style ?? ''] ?? capacities[source.template ?? ''] ?? 2000\n}\n\n/** Candidate spot: the room part with the least weight (wet rooms first, terraces last, near the reference point or the middle). */\nfunction bestSpot(source: StructureSource, floor: number, reference: { u: number; v: number } | undefined): { roomType: string; roomId: string; rect: Rect } | undefined {\n const centre: [number, number] = reference ? [reference.u, reference.v] : [source.w / 2, source.d / 2]\n let best: { roomType: string; roomId: string; rect: Rect; weight: number } | undefined\n for (const room of source.rooms.filter((r) => r.floor === floor && !NOT_UNDER_TANK.includes(r.type))) {\n for (const part of room.parts) {\n const rect: Rect = [part[0] + 0.4, part[1] + 0.4, part[2] - 0.4, part[3] - 0.4]\n if (rect[2] - rect[0] < TANK_SIDE || rect[3] - rect[1] < TANK_SIDE) continue\n const base = WET_ROOMS.includes(room.type) ? 0 : room.type === 'terrace' ? 500 : 100\n const weight = base + Math.hypot((rect[0] + rect[2]) / 2 - centre[0], (rect[1] + rect[3]) / 2 - centre[1])\n if (!best || weight < best.weight) best = { roomType: room.type, roomId: room.id, rect, weight }\n }\n }\n return best\n}\n\nfunction raisedPlatform(source: StructureSource, u: number, v: number, baseY: number): NonNullable<WaterTank['platform']> {\n const margin = 0.12\n const edge = Math.max(0, Math.min(u, source.w - u, v, source.d - v))\n const rise = round2(clamp(edge * 0.35 + 0.7, 1.1, 2.4))\n const thickness = 0.12\n const reach = TANK_SIDE / 2 + margin - 0.06\n const pillars = ([[-1, -1], [1, -1], [-1, 1], [1, 1]] as const).map(([a, b]) => ({ u: round2(u + a * reach), v: round2(v + b * reach), side: 0.12 }))\n const half = TANK_SIDE / 2 + margin\n return { aabb: [u - half, v - half, u + half, v + half].map(round2) as Rect, baseY, height: rise, thickness, topY: round2(baseY + rise + thickness), pillars, ladder: true }\n}\n\n/**\n * The water tank of a house: on the roof slab, in the attic, or on a platform that rises out of the roof, never in the yard. Null for a plan without\n * a lot (an apartment) or a commercial building, and when no room has space.\n */\nexport function planWaterTank(source: StructureSource, rng: Rng, options: TankPlanOptions = {}): WaterTank | null {\n if (!source.lot || source.style === 'commercial') return null\n if (options.custom) return options.custom(source, rng)\n const floor = source.floors.length - 1\n const level = source.floors[floor]!\n const capacity = capacityOf(source, { ...DEFAULT_CAPACITIES, ...options.capacities })\n const height = capacity >= 2000 ? 1.4 : capacity === 1000 ? 1.0 : 0.85\n const place = options.location ? options.location(source, rng) : source.facade.roof === 'slab' ? 'slab' : rng() < ATTIC_CHANCE ? 'attic' : 'raised_slab'\n const reference = (source.facade.slab as { waterTank?: { u: number; v: number } } | undefined)?.waterTank\n const spot = bestSpot(source, floor, reference)\n if (!spot) return null\n const target = reference ? [reference.u, reference.v] : [(spot.rect[0] + spot.rect[2]) / 2, (spot.rect[1] + spot.rect[3]) / 2]\n const u = clamp(target[0]!, spot.rect[0] + TANK_SIDE / 2, spot.rect[2] - TANK_SIDE / 2)\n const v = clamp(target[1]!, spot.rect[1] + TANK_SIDE / 2, spot.rect[3] - TANK_SIDE / 2)\n const where = spot.roomType === 'terrace' ? 'slab' : place\n const slabY = round2(spot.roomType === 'terrace' ? level.y0 : level.y0 + level.ceiling)\n const tank: WaterTank = {\n id: 'water_tank', kind: 'water_tank', itemType: 'water_tank', place: where, floor, room: spot.roomId, u: round2(u), v: round2(v), y: slabY, w: TANK_SIDE, d: TANK_SIDE, h: height,\n capacity, aabb: [u - TANK_SIDE / 2, v - TANK_SIDE / 2, u + TANK_SIDE / 2, v + TANK_SIDE / 2].map(round2) as Rect,\n }\n if (where === 'raised_slab') {\n tank.platform = raisedPlatform(source, u, v, slabY)\n tank.y = tank.platform.topY\n }\n return tank\n}\n","import type { ViewerLayer, ViewerLayerContext, ViewerLayerLegendEntry } from '@adatechnology/game-floorplan'\n\nimport type { StructurePart } from './types'\n\ntype MaterialGroup = 'concrete' | 'steel' | 'masonry' | 'wood'\n\nconst COLORS: Record<MaterialGroup, string> = { concrete: '#7d8590', steel: '#3d6fb0', masonry: '#b5654b', wood: '#a0693a' }\nconst BEAM_IDS = ['plate_', 'porch_beam', 'base_beam', 'trestle_beam']\n\nexport const LAYER_ID = 'structure'\n\nexport function groupOf(material: string): MaterialGroup {\n if (material === 'concrete') return 'concrete'\n if (material === 'steel' || material === 'aluminium' || material === 'cast_iron') return 'steel'\n if (material === 'brick' || material === 'stone' || material === 'ceramic') return 'masonry'\n return 'wood'\n}\n\nconst isRoofFrame = (part: StructurePart): boolean => ['truss', 'rafter', 'ridge'].some((prefix) => part.id.startsWith(prefix))\nconst isDrawnBeam = (part: StructurePart): boolean => part.role === 'beam' && BEAM_IDS.some((prefix) => part.id.startsWith(prefix))\n\nfunction drawColumns(context: ViewerLayerContext, parts: readonly StructurePart[]): void {\n for (const part of parts.filter((p) => p.role === 'column')) {\n const color = COLORS[groupOf(part.material)]\n if (groupOf(part.material) === 'wood') context.rect(part.aabb, null, color, 2)\n else context.rect(part.aabb, color, null)\n context.hit(part.aabb, `${part.id} · column · ${part.material} · ${part.mass} kg`)\n }\n}\n\nfunction drawBeams(context: ViewerLayerContext, parts: readonly StructurePart[]): void {\n context.g.save()\n context.g.setLineDash([6, 4])\n for (const part of parts.filter(isDrawnBeam)) {\n context.rect(part.aabb, null, COLORS[groupOf(part.material)], 1.5)\n context.hit(part.aabb, `${part.id} · beam · ${part.material} · ${part.mass} kg`)\n }\n context.g.restore()\n}\n\nfunction drawRoofFrames(context: ViewerLayerContext, parts: readonly StructurePart[]): void {\n context.g.save()\n context.g.strokeStyle = COLORS.wood\n context.g.lineWidth = 1\n for (const part of parts.filter(isRoofFrame)) {\n const [u0, v0, u1, v1] = part.aabb\n const alongV = v1 - v0 > u1 - u0\n context.g.beginPath()\n if (alongV) { context.g.moveTo(context.X((u0 + u1) / 2), context.Z(v0)); context.g.lineTo(context.X((u0 + u1) / 2), context.Z(v1)) }\n else { context.g.moveTo(context.X(u0), context.Z((v0 + v1) / 2)); context.g.lineTo(context.X(u1), context.Z((v0 + v1) / 2)) }\n context.g.stroke()\n }\n context.g.restore()\n}\n\nfunction drawPorchRoofs(context: ViewerLayerContext, parts: readonly StructurePart[]): void {\n context.g.save()\n context.g.setLineDash([2, 4])\n for (const part of parts.filter((p) => p.id.startsWith('porch_roof'))) context.rect(part.aabb, null, COLORS.wood, 1)\n context.g.restore()\n}\n\n/** What the viewer draws at one storey: pillars (filled for concrete, steel and masonry, hollow for wood), dashed beams, trusses on the top storey, the porch roof outline. */\nexport function drawStructure(context: ViewerLayerContext): void {\n const structure = context.plan.structure\n if (!structure) return\n const floor = context.all ? 0 : context.floor\n const here = (structure.parts as StructurePart[]).filter((part) => part.floor === floor)\n drawPorchRoofs(context, here)\n if (floor === (context.plan.roof?.bearingFloor ?? 0)) drawRoofFrames(context, structure.parts)\n drawBeams(context, here)\n drawColumns(context, here)\n}\n\nexport function structureLegend(plan: { structure?: { parts: StructurePart[] } }): ViewerLayerLegendEntry[] {\n const parts = plan.structure?.parts ?? []\n const entries: ViewerLayerLegendEntry[] = []\n for (const group of ['concrete', 'steel', 'masonry', 'wood'] as const) {\n const columns = parts.some((p) => p.role === 'column' && groupOf(p.material) === group)\n if (columns) entries.push({ label: `structure_column_${group}`, color: COLORS[group], shape: group === 'wood' ? 'hollow' : 'filled' })\n }\n for (const group of ['concrete', 'wood'] as const) {\n if (parts.some((p) => isDrawnBeam(p) && groupOf(p.material) === group)) entries.push({ label: `structure_beam_${group}`, color: COLORS[group], shape: 'dashed' })\n }\n if (parts.some(isRoofFrame)) entries.push({ label: 'structure_roof_frame', color: COLORS.wood, shape: 'line' })\n return entries\n}\n\nexport const structureLayer: ViewerLayer = {\n id: LAYER_ID,\n label: 'structure_layer',\n defaultOn: false,\n draw: drawStructure,\n legend: structureLegend,\n}\n","import type { FloorplanEngine, ResultExtensionContext } from '@adatechnology/game-floorplan'\n\nimport { constructionFor } from './construction'\nimport enLocale from './locales/en.json'\nimport ptBrLocale from './locales/pt-BR.json'\nimport type { ConstructionBuild } from './registry'\nimport { buildStructure } from './structure'\nimport { contentOf } from './utilities/content'\nimport { planContents, planUtilities } from './utilities'\nimport { addOutbuildingPaths, planOutbuildings } from './utilities/outbuildings'\nimport type { EnergyConfig } from './utilities/electrical'\nimport type { TankPlanOptions } from './water-tank'\nimport { planWaterTank } from './water-tank'\nimport { structureLayer } from './viewer-layer'\nimport type { Roof, StructureOptions, WallDetail } from './types'\n\nexport interface StructurePackOptions {\n /** Litres of the tank by template id or style id. */\n tankCapacities?: Record<string, number>\n}\n\ntype Cache = { build: ConstructionBuild; roof?: Roof }\nconst CACHE = new WeakMap<object, Cache>()\n\nconst cacheOf = (result: object): Cache => {\n const cache = CACHE.get(result)\n if (!cache) throw new Error('The construction extension did not run for this plan')\n return cache\n}\n\nfunction constructionExtension(context: ResultExtensionContext): unknown {\n const build = constructionFor({ result: context.result as never, seed: context.seed, template: context.plan.tpl as never, options: context.options })\n CACHE.set(context.result, { build })\n return build.construction\n}\n\nfunction structureExtension(context: ResultExtensionContext): unknown {\n const cache = cacheOf(context.result)\n const options: StructureOptions = { construction: cache.build.construction, extras: cache.build.extras ?? {}, tank: context.result.waterTank ?? null, wallDetail: (context.options.wallDetail ?? 'panels') as WallDetail }\n const { roof, ...structure } = buildStructure(context.result, options)\n cache.roof = roof\n for (const part of structure.parts) {\n if (part.door === undefined || part.steps === undefined) continue\n const door = context.result.doors.find((d: { id: string }) => d.id === part.door)\n if (door) door.steps = part.steps\n }\n return structure\n}\n\nconst COOKING_CYLINDER = { type: 'cooking_gas_cylinder', category: 'cooking_gas_cylinder', w: 0.36, d: 0.36, h: 0.48 }\n\nfunction energyOf(context: ResultExtensionContext): EnergyConfig | undefined {\n const energy = context.plan.tpl.energy\n return typeof energy === 'function' ? energy(context.options, context.plan.w, context.plan.d) : undefined\n}\n\n/**\n * Registers the structure into the engine: `result.construction`, `result.structureExtras`, `result.waterTank`, `result.structure` and `result.roof` of every plan,\n * and the structure layer of the 2D viewer. Register the content packs first.\n */\nexport function register(engine: FloorplanEngine, options: StructurePackOptions = {}): void {\n engine.registerLocale('en', enLocale)\n engine.registerLocale('pt-BR', ptBrLocale)\n engine.registerResultExtension('construction', constructionExtension)\n engine.registerResultExtension('structureExtras', (context) => cacheOf(context.result).build.extras ?? {}, { after: ['construction'] })\n engine.registerResultExtension(\n 'waterTank',\n (context) => {\n const tank: TankPlanOptions = { capacities: options.tankCapacities, custom: context.plan.tpl.tank, location: context.plan.tpl.tankLocation }\n return planWaterTank(context.result as never, context.rng, tank)\n },\n { after: ['construction'], seedKey: 'caixa' },\n )\n engine.registerResultExtension('structure', structureExtension, { after: ['construction', 'structureExtras', 'waterTank'] })\n engine.registerResultExtension('roof', (context) => cacheOf(context.result).roof ?? null, { after: ['structure'] })\n engine.registerViewerLayer(structureLayer)\n engine.registerItem(COOKING_CYLINDER)\n engine.registerResultExtension('contents', (context) => planContents({ items: context.result.items, state: context.result.state, place: context.plan.tpl.place ?? 'house', ...(typeof context.options.day === 'number' ? { day: context.options.day } : {}), ...(typeof context.options.region === 'string' ? { region: context.options.region } : {}), rngFor: (key) => engine.createRng(context.seed, key), findsFor: (query) => { const answered = engine.findsAnswer(query); return answered ?? contentOf({ container: query.container, state: query.state, rng: query.rng, footprint: query.footprint ?? 0.5 }) } }))\n engine.registerResultExtension('outbuildings', (context) => {\n const outbuildings = planOutbuildings({ plan: context.plan, items: context.result.items, catalog: engine.catalog, rngFor: (key) => engine.createRng(context.seed, key) })\n if (context.result.lot) addOutbuildingPaths(context.result.lot, outbuildings, context.result.items)\n return outbuildings\n }, { after: ['contents'] })\n engine.registerResultExtension('utilities', (context) => planUtilities({ plan: context.plan, items: context.result.items, stateItems: context.result.stateItems, tank: context.result.waterTank ?? null, ...(energyOf(context) ? { energy: energyOf(context) } : {}), rngFor: (key) => engine.createRng(context.seed, key) }), { after: ['outbuildings', 'waterTank'] })\n}\n","import type { Vec3 } from './destruction'\n\n/**\n * The numbers of the shove a blast gives to a body that moves (a loose item, a piece of furniture, a person): all of them a game value, with a default that reads well in a room,\n * not a physical table. A host reads them once and lends them to the modules that move their own bodies (`ModuleHost.blastShove`).\n */\nexport interface BlastShoveOptions {\n /**\n * The share of the blast energy that reaches a body as motion: the speed at the centre is `sqrt(2 * energy * coupling / mass)`, before the falloff (default 0.02).\n */\n readonly coupling?: number\n /** Fastest a body is thrown, in m/s, at the centre of the blast (default 20). */\n readonly maxSpeed?: number\n /** How much of the push goes up: the direction is `(away, lift)` normalised from the horizontal outward direction (default 0.3). */\n readonly lift?: number\n /** Below this speed (m/s) nothing moves: a heavy thing far from a small blast stays where it is (default 0.3). */\n readonly minSpeed?: number\n /** Exponent of the falloff `(1 - distance / radius) ^ power`, the same as the damage of the destruction world (default 2). */\n readonly falloffPower?: number\n}\n\n/** The defaults of `BlastShoveOptions`. */\nexport const DEFAULT_BLAST_SHOVE: Readonly<Required<BlastShoveOptions>> = { coupling: 0.02, maxSpeed: 20, lift: 0.3, minSpeed: 0.3, falloffPower: 2 }\n\n/** A blast as the shove reads it: where, how much energy (J) and how far it reaches (m). `reach` (0..1) is the share that got through what stood in the way. */\nexport interface BlastSource {\n readonly point: Vec3\n readonly energy: number\n readonly radius: number\n readonly reach?: number\n}\n\n/** What a blast does to one body: how fast it leaves (m/s), the unit direction it leaves in, and how far from the centre it was. */\nexport interface BlastShove {\n readonly speed: number\n readonly direction: Vec3\n readonly distance: number\n /** The falloff applied, 0..1. */\n readonly falloff: number\n}\n\n/**\n * The shove a blast gives to a body of `mass` kg whose centre is at `position`: away from the centre, lifted a little, with the speed\n * `min(maxSpeed, sqrt(2 * energy * reach * coupling / mass)) * (1 - distance / radius) ^ 2`. Undefined when the body is outside the radius or the speed is under `minSpeed`.\n * The same rule moves the loose items and furniture of the test room and the people of the characters module, so a game that tunes the options tunes all of them.\n */\nexport function blastShove(blast: BlastSource, target: { readonly position: Vec3; readonly mass: number }, options: BlastShoveOptions = {}): BlastShove | undefined {\n const o = { ...DEFAULT_BLAST_SHOVE, ...options }\n const dx = target.position[0] - blast.point[0]\n const dy = target.position[1] - blast.point[1]\n const dz = target.position[2] - blast.point[2]\n const distance = Math.hypot(dx, dy, dz)\n if (!(blast.radius > 0) || distance > blast.radius) return undefined\n const falloff = (1 - distance / blast.radius) ** o.falloffPower\n const mass = Math.max(target.mass, 0.05)\n const speed = Math.min(o.maxSpeed, Math.sqrt((2 * blast.energy * (blast.reach ?? 1) * o.coupling) / mass)) * falloff\n if (!(speed >= o.minSpeed)) return undefined\n // straight above or below the centre there is no \"away\": the push goes up\n const direction: Vec3 = distance > 1e-4 ? [dx / distance, dy / distance + o.lift, dz / distance] : [0, 1, 0]\n const length = Math.hypot(direction[0], direction[1], direction[2])\n return { speed, direction: [direction[0] / length, direction[1] / length, direction[2] / length], distance, falloff }\n}\n","import type { DamageType, DestructibleSpec, DestructionEvent, Hit, JointSpec, ObjectState, ToolKind, Vec3 } from './destruction'\n\n/**\n * What a game module implements for an object whose behaviour it owns (a vehicle with its own panel deformation, a creature, a machine). The\n * world (`DestructionWorld.register`) hosts it next to its own objects: raycast, shoot, explode, hit, disassemble, extinguish, update, state,\n * reset and `on` all route to it.\n *\n * Space: the impl receives hits in WORLD space and returns events in WORLD space (it owns its transform; the transform given to `register` or\n * `setTransform` is only used by the world for raycasts and blast range). Every event must carry `object === id` and name parts listed by\n * `describe()`.\n */\nexport interface DestructibleImpl {\n readonly id: string\n readonly name?: string\n /** Parts, joints and structure in the impl's local space, for raycast, inspector and log. Called often: keep it cheap. */\n describe(): DestructibleSpec\n /** Apply one hit (see `IMPACT_CONTRACT` for the fields per type) and return the events it caused. */\n hit(hit: Hit): DestructionEvent[]\n /** Advance fire, melting, collapse and other timed behaviour. */\n update?(dt: number): DestructionEvent[]\n state(): ObjectState\n reset?(): void\n /** Same contract as `DestructionWorld.disassemble`: progress 0..1, or -1 when the tool cannot undo the joint. */\n disassemble?(jointId: string, tool: ToolKind, dt: number): number\n extinguish?(partId?: string): void\n /** Optional: an animation moved a part; `position` / `rotation` (Euler XYZ, radians) are object-local. Keep raycast and hit shapes in sync. */\n setPartPose?(partId: string, position: Vec3, rotation?: Vec3): void\n /** Plain JSON of the impl's own state, stored in `DestructionSnapshot.impls`. */\n serialize?(): unknown\n load?(data: unknown): void\n}\n\n/** The fields a weapon or hazard must put in a `Hit`, per damage type. THE impact contract. */\nexport interface ImpactContract {\n required: string[]\n optional: string[]\n note: string\n}\n\nexport const IMPACT_CONTRACT: Record<DamageType, ImpactContract> = {\n ballistic: { required: ['type', 'point', 'direction', 'energy', 'caliber'], optional: ['space', 'source'], note: 'bullets and pellets: joules and diameter in millimetres' },\n blunt: { required: ['type', 'point', 'energy'], optional: ['direction', 'radius', 'space', 'source'], note: 'contact radius in metres (default 3 cm)' },\n slash: { required: ['type', 'point', 'energy'], optional: ['direction', 'radius', 'space', 'source'], note: 'axes, knives, machetes' },\n explosive: { required: ['type', 'point', 'energy', 'radius'], optional: ['lethalRadius', 'space', 'source'], note: 'point is the centre of the blast, radius the range in metres' },\n fire: { required: ['type', 'point', 'temperature', 'radius'], optional: ['duration', 'space', 'source'], note: 'flame temperature in °C; duration in seconds (call every frame with `dt`)' },\n heat: { required: ['type', 'point', 'temperature', 'radius'], optional: ['duration', 'space', 'source'], note: 'heat without flame (cutting torch, hot plate)' },\n}\n\n/** Problems with a hit according to the impact contract (empty when it is valid). */\nexport const checkHit = (hit: Hit): string[] => {\n const c = IMPACT_CONTRACT[hit.type]\n if (!c) return [`unknown damage type \"${String(hit.type)}\"`]\n const out: string[] = []\n for (const f of c.required) {\n const v = (hit as unknown as Record<string, unknown>)[f]\n if (v === undefined || (Array.isArray(v) ? v.some((n) => !Number.isFinite(n)) : typeof v === 'number' && !Number.isFinite(v))) out.push(`${hit.type} hit needs \"${f}\"`)\n }\n return out\n}\n\nexport interface CheckOptions {\n /**\n * Ids of every material the impl may use (the contracts package does not know the materials of your world: pass the ids of\n * `world.materials`, or the built-in plus your own). When omitted, the material check is skipped.\n */\n materials?: Iterable<string>\n}\n\nconst finiteJson = (v: unknown, path: string, out: string[]) => {\n if (typeof v === 'number') {\n if (!Number.isFinite(v)) out.push(`${path} is not a finite number`)\n } else if (Array.isArray(v)) v.forEach((x, i) => finiteJson(x, `${path}[${i}]`, out))\n else if (v && typeof v === 'object') for (const [k, x] of Object.entries(v)) finiteJson(x, `${path}.${k}`, out)\n else if (typeof v === 'function' || typeof v === 'symbol' || typeof v === 'bigint') out.push(`${path} is not JSON`)\n}\n\n/**\n * Contract checker for the test room (it needs no world): `describe()` is valid, a 500 J ballistic hit at a part centre returns well-formed events of this impl, `state()`\n * matches `describe()`, hit points never go negative, `update(0.016)` returns an array and every event is JSON-serializable. It hits the impl\n * (and calls `reset()` afterwards when there is one).\n */\nexport const checkDestructible = (impl: DestructibleImpl, options: CheckOptions = {}): { ok: boolean; problems: string[] } => {\n const problems: string[] = []\n const known = options.materials ? new Set(options.materials) : null\n let spec: DestructibleSpec | undefined\n try {\n spec = impl.describe()\n } catch (e) {\n return { ok: false, problems: [`describe() threw: ${String(e)}`] }\n }\n if (!spec || !Array.isArray(spec.parts) || spec.parts.length === 0) return { ok: false, problems: ['describe() must return at least one part'] }\n const ids = new Set<string>()\n for (const p of spec.parts) {\n if (ids.has(p.id)) problems.push(`duplicate part id \"${p.id}\"`)\n ids.add(p.id)\n if (known && !known.has(p.material)) problems.push(`part \"${p.id}\" has unknown material \"${p.material}\"`)\n if (!p.shape || !['box', 'cylinder', 'sphere'].includes(p.shape.kind)) problems.push(`part \"${p.id}\" has no valid shape`)\n if (!Array.isArray(p.position) || p.position.length !== 3) problems.push(`part \"${p.id}\" has no position`)\n }\n const jointIds = new Set<string>()\n for (const j of (spec.joints ?? []) as JointSpec[]) {\n if (!ids.has(j.a) || !ids.has(j.b)) problems.push(`joint \"${j.id ?? `${j.a}~${j.b}`}\" references an unknown part`)\n const jid = j.id ?? `${j.a}~${j.b}`\n if (jointIds.has(jid)) problems.push(`duplicate joint id \"${jid}\"`)\n jointIds.add(jid)\n }\n const checkState = (label: string) => {\n let st: ObjectState\n try {\n st = impl.state()\n } catch (e) {\n problems.push(`state() threw ${label}: ${String(e)}`)\n return\n }\n const sids = st.parts.map((p) => p.id).sort().join(',')\n if (sids !== [...ids].sort().join(',')) problems.push(`state() part ids do not match describe() ${label}`)\n for (const p of st.parts) if (!(p.hp >= 0)) problems.push(`part \"${p.id}\" has negative or invalid hp ${label}`)\n }\n const checkEvents = (events: unknown, label: string) => {\n if (!Array.isArray(events)) {\n problems.push(`${label} must return an array`)\n return\n }\n const evs = events as DestructionEvent[]\n evs.forEach((e, i) => {\n if (e.object !== impl.id) problems.push(`${label} event ${i} (${e.type}) has object \"${String(e.object)}\", expected \"${impl.id}\"`)\n const part = (e as { part?: string }).part\n if (part !== undefined && !ids.has(part)) problems.push(`${label} event ${i} (${e.type}) names unknown part \"${part}\"`)\n })\n const bad: string[] = []\n finiteJson(evs, 'events', bad)\n problems.push(...bad.map((b) => `${label}: ${b}`))\n try {\n const s = JSON.stringify(evs)\n if (JSON.stringify(JSON.parse(s)) !== s) problems.push(`${label} events do not survive a JSON round trip`)\n } catch (e) {\n problems.push(`${label} events are not JSON-serializable: ${String(e)}`)\n }\n }\n checkState('before the hit')\n const target = spec.parts[0]\n try {\n const hit: Hit = { type: 'ballistic', point: [target.position[0], target.position[1], target.position[2]], direction: [0, 0, -1], energy: 500, caliber: 9 }\n checkEvents(impl.hit(hit), 'hit()')\n } catch (e) {\n problems.push(`hit() threw: ${String(e)}`)\n }\n checkState('after the hit')\n if (impl.update) {\n try {\n checkEvents(impl.update(0.016), 'update()')\n } catch (e) {\n problems.push(`update() threw: ${String(e)}`)\n }\n checkState('after update')\n }\n try {\n impl.reset?.()\n } catch (e) {\n problems.push(`reset() threw: ${String(e)}`)\n }\n return { ok: problems.length === 0, problems }\n}\n","/** The slots of a body an item can cover (the item slot vocabulary: game-items imports it from here). */\nexport type BodySlot = 'head' | 'eyes' | 'torso' | 'arms' | 'hands' | 'legs' | 'feet' | 'over'\n\n/** The 11 segments of the detailed body model (the Arsenal ids). */\nexport type SegmentKind = 'head' | 'jaw' | 'neck' | 'torso' | 'pelvis' | 'upperArm' | 'forearm' | 'hand' | 'thigh' | 'shin' | 'foot'\n\n/** The 6 regions of the crowd model (the game regions 0..5). */\nexport type BodyRegion = 'head' | 'torso' | 'armL' | 'armR' | 'legL' | 'legR'\n\n/** Bits of the `missing` mask of a body. The instanced body shader reads them, so the values are part of the contract. */\nexport const MISSING_BITS = {\n head: 1,\n armL: 2,\n armR: 4,\n legL: 8,\n legR: 16,\n armLBroken: 32,\n armRBroken: 64,\n legLBroken: 128,\n legRBroken: 256,\n jaw: 512,\n} as const\n","import type { DestructibleSpec, PartSpec } from './destruction'\n\nexport interface CheckSpecOptions {\n /** Known material ids. When given, every part's material must be one of them. */\n materials?: Iterable<string>\n}\n\nexport interface SpecReport {\n /** False when there is at least one problem (warnings do not count). */\n ok: boolean\n problems: string[]\n /** Things that are legal but probably wrong, e.g. structural parts that cannot reach an anchored part. */\n warnings: string[]\n}\n\nconst STRUCTURE_ROLES = ['foundation', 'column', 'beam', 'slab', 'wall', 'partition', 'roof', 'stair', 'none']\nconst BEARS = [true, false, 'a_on_b', 'b_on_a']\n\nconst finite = (n: unknown): n is number => typeof n === 'number' && Number.isFinite(n)\nconst positive = (n: unknown): boolean => finite(n) && n > 0\nconst vec3 = (v: unknown): boolean => Array.isArray(v) && v.length === 3 && v.every(finite)\nconst nonNegative = (n: unknown): boolean => n === undefined || (finite(n) && n >= 0)\n\nconst FACES = ['both', '+', '-']\nconst BONDS = ['running', 'stack']\n\n/** Layers, reinforcement, units and breach: known materials, finite positive sizes. */\nconst checkStagedFields = (p: PartSpec | undefined, label: string, materials: Set<string> | null, problems: string[]): void => {\n const known = (m: unknown, what: string): void => {\n if (materials && !materials.has(m as string)) problems.push(`${label} ${what} has unknown material \"${String(m)}\"`)\n }\n ;(p?.layers ?? []).forEach((l, i) => {\n known(l?.material, `layer ${i}`)\n if (!positive(l?.thickness)) problems.push(`${label} layer ${i} thickness must be finite and positive`)\n if (!FACES.includes(l?.faces)) problems.push(`${label} layer ${i} has an invalid faces \"${String(l?.faces)}\"`)\n })\n const r = p?.reinforcement\n if (r) {\n known(r.material, 'reinforcement')\n if (!positive(r.spacing) || !positive(r.diameter)) problems.push(`${label} reinforcement spacing and diameter must be finite and positive`)\n if (r.residualCapacity !== undefined && !(finite(r.residualCapacity) && r.residualCapacity >= 0 && r.residualCapacity <= 1)) problems.push(`${label} reinforcement residualCapacity must be between 0 and 1`)\n }\n const u = p?.units\n if (u) {\n known(u.mortar, 'units mortar')\n if (!vec3(u.size) || !u.size.every(positive)) problems.push(`${label} units size must be three finite positive numbers`)\n if (!BONDS.includes(u.bond)) problems.push(`${label} units has an invalid bond \"${String(u.bond)}\"`)\n }\n if (p?.breach && p.breach.area !== undefined && !positive(p.breach.area)) problems.push(`${label} breach area must be finite and positive`)\n}\n\n/**\n * Static checks on a `DestructibleSpec` (no world needed), for items that give a `spec` instead of an `impl`: unique part ids, known materials\n * (when `options.materials` is given), joints that reference existing, different parts, finite positive sizes, non-negative mass / hp / capacity,\n * valid structure roles and `bears` directions. A structural part with no path of joints to an anchored part is a warning, not a problem: it\n * is allowed, it just falls.\n */\nexport const checkSpec = (spec: DestructibleSpec, options: CheckSpecOptions = {}): SpecReport => {\n const problems: string[] = []\n const warnings: string[] = []\n const materials = options.materials ? new Set(options.materials) : null\n const parts = Array.isArray(spec?.parts) ? spec.parts : []\n if (!Array.isArray(spec?.parts) || parts.length === 0) problems.push('the spec needs at least one part')\n const ids = new Set<string>()\n for (const p of parts) {\n const id = String(p?.id ?? '')\n const label = `part \"${id}\"`\n if (id === '') problems.push('a part has no id')\n else if (ids.has(id)) problems.push(`duplicate part id \"${id}\"`)\n ids.add(id)\n if (materials && !materials.has(p?.material)) problems.push(`${label} has unknown material \"${String(p?.material)}\"`)\n else if (typeof p?.material !== 'string' || p.material === '') problems.push(`${label} needs a material`)\n const s = p?.shape\n if (s?.kind === 'box') {\n if (!Array.isArray(s.size) || s.size.length !== 3 || !s.size.every(positive)) problems.push(`${label} box size must be three finite positive numbers`)\n } else if (s?.kind === 'cylinder') {\n if (!positive(s.radius) || !positive(s.height)) problems.push(`${label} cylinder radius and height must be finite and positive`)\n } else if (s?.kind === 'sphere') {\n if (!positive(s.radius)) problems.push(`${label} sphere radius must be finite and positive`)\n } else problems.push(`${label} has an unknown shape`)\n if (!vec3(p?.position)) problems.push(`${label} needs a finite position [x, y, z]`)\n if (p?.rotation !== undefined && !vec3(p.rotation)) problems.push(`${label} has an invalid rotation`)\n for (const f of ['mass', 'hp', 'thickness'] as const) if (!nonNegative(p?.[f])) problems.push(`${label} ${f} must be a finite number >= 0`)\n if (p?.fill !== undefined && !(finite(p.fill) && p.fill >= 0 && p.fill <= 1)) problems.push(`${label} fill must be between 0 and 1`)\n if (p?.structure) {\n if (!STRUCTURE_ROLES.includes(p.structure.role)) problems.push(`${label} has an invalid structure role \"${String(p.structure.role)}\"`)\n if (!nonNegative(p.structure.capacity)) problems.push(`${label} structure capacity must be a finite number >= 0`)\n }\n if (p?.contains && !nonNegative(p.contains.liters)) problems.push(`${label} contains.liters must be a finite number >= 0`)\n checkStagedFields(p, label, materials, problems)\n }\n\n const jointIds = new Set<string>()\n const edges: Array<[string, string]> = []\n for (const j of spec?.joints ?? []) {\n const id = j.id ?? `${j.a}~${j.b}`\n const label = `joint \"${id}\"`\n if (jointIds.has(id)) problems.push(`duplicate joint id \"${id}\"`)\n jointIds.add(id)\n if (!ids.has(j.a)) problems.push(`${label} references unknown part \"${String(j.a)}\"`)\n if (!ids.has(j.b)) problems.push(`${label} references unknown part \"${String(j.b)}\"`)\n if (j.a === j.b) problems.push(`${label} joins part \"${String(j.a)}\" to itself`)\n if (j.bears !== undefined && !BEARS.includes(j.bears)) problems.push(`${label} has an invalid bears \"${String(j.bears)}\"`)\n if (!nonNegative(j.strength)) problems.push(`${label} strength must be a finite number >= 0`)\n if (!nonNegative(j.seconds)) problems.push(`${label} seconds must be a finite number >= 0`)\n if (j.bears !== false && ids.has(j.a) && ids.has(j.b) && j.a !== j.b) edges.push([j.a, j.b])\n }\n\n // structural parts must reach an anchored part over the joints (only when the spec lists its joints: otherwise they are inferred later)\n const structural = parts.filter((p) => p?.structure && p.structure.role !== 'none')\n if (structural.length && spec.joints) {\n const anchored = parts.filter((p) => p.anchored || p.structure?.role === 'foundation').map((p) => p.id)\n const adj = new Map<string, string[]>()\n for (const [a, b] of edges) {\n adj.set(a, [...(adj.get(a) ?? []), b])\n adj.set(b, [...(adj.get(b) ?? []), a])\n }\n const seen = new Set(anchored)\n const queue = [...anchored]\n while (queue.length) {\n for (const n of adj.get(queue.pop()!) ?? []) {\n if (seen.has(n)) continue\n seen.add(n)\n queue.push(n)\n }\n }\n const lost = structural.filter((p) => !seen.has(p.id)).map((p) => p.id)\n if (lost.length) warnings.push(`structural part(s) ${lost.map((i) => `\"${i}\"`).join(', ')} cannot reach an anchored part, so they will fall`)\n }\n return { ok: problems.length === 0, problems, warnings }\n}\n","import type { BallisticExtras, Hit, HitIgnition, Vec3 } from './destruction'\n\n/**\n * A ballistic shot (one per pellet) as a weapon module produces it. Plain data: any damage model can consume it (`shotToHit` makes the `Hit`).\n */\nexport interface Shot {\n origin: Vec3\n /** Unit vector. */\n direction: Vec3\n /** Muzzle energy in joules. */\n energy: number\n /** Bullet diameter in millimetres. */\n caliber: number\n /** snake_case calibre id, e.g. `9x19`. */\n caliberId: string\n /** Muzzle speed in m/s. */\n speed: number\n /** Projectile mass in grams (one pellet for a shotgun load). */\n mass?: number\n /** Energy at a distance in metres, with the calibre's drag. */\n energyAt(distance: number): number\n pellet: number\n /** snake_case weapon id. */\n weapon: string\n source?: string\n /** Kind of the round that was loaded (`fmj`, `hp`, `ap`, `buck`, `slug`, `incendiary`, `tracer`...). */\n ammo?: string\n /** Millimetres of steel, concrete, brick and wood the round goes through at the muzzle (the ammo table of the weapons module). `shotToHit` scales it by the energy left. */\n penetration?: Readonly<Record<string, number>>\n incendiary?: boolean\n tracer?: boolean\n /** Chances that the round lights flammable vapour or fuel. */\n ignition?: HitIgnition\n}\n\n/**\n * The fields of the round that a damage model takes besides the geometry: the penetration by material scaled by the energy that is left at `distance`\n * (linear in the energy: half the energy goes through half as much), the incendiary and tracer flags and the ignition chances. Pass it as the sixth\n * argument of `DestructionWorld.shoot` or spread it in a `Hit`.\n */\nexport const shotExtras = (shot: Shot, distance = 0): BallisticExtras => {\n const out: { -readonly [K in keyof BallisticExtras]: BallisticExtras[K] } = {}\n if (shot.penetration) {\n const k = shot.energy > 0 ? Math.min(1, Math.max(0, shot.energyAt(distance) / shot.energy)) : 1\n const scaled: Record<string, number> = {}\n for (const key of Object.keys(shot.penetration)) scaled[key] = shot.penetration[key]! * k\n out.penetration = scaled\n }\n if (shot.incendiary) out.incendiary = true\n if (shot.tracer) out.tracer = true\n if (shot.ignition) out.ignition = { spark: shot.ignition.spark, flame: shot.ignition.flame }\n return out\n}\n\n/** One use of a non-firearm (melee swing, flame tick, heat tick, throw, tool tick, extinguisher tick). */\nexport type Use =\n | { kind: 'melee'; damage: 'blunt' | 'slash'; energy: number; radius: number; reach: number; origin: Vec3; direction: Vec3 }\n | { kind: 'flame'; temperature: number; radius: number; range: number; cone: boolean; duration: number; origin: Vec3; direction: Vec3 }\n | { kind: 'heat'; temperature: number; radius: number; range: number; duration: number; origin: Vec3; direction: Vec3 }\n | {\n kind: 'throw'\n energy: number\n radius: number\n fuse: number\n velocity: Vec3\n origin: Vec3\n fire?: { temperature: number; radius: number; seconds: number }\n /** Explosive id (`m67`, `molotov`, `pg7v`...): the host looks the numbers up in the arsenal. Absent on a plain thrown object. */\n explosive?: string\n /** What sets it off: `timer` after `fuse` seconds, `impact` on the first hit once armed. */\n trigger?: 'timer' | 'impact'\n /** Metres the projectile must fly before an impact sets it off; closer, it hits without exploding (rocket launchers). */\n armDistance?: number\n /** Radius in metres of the wounding area (`radius` is the lethal one). */\n injuryRadius?: number\n /** Seconds the blast stuns whoever is inside the injury radius (flashbang). */\n stunSeconds?: number\n /** Seconds the thrower held it after pulling the pin: `fuse` is what was left of the full fuse when it left the hand. */\n cooked?: number\n /** Went off in the thrower's hand (held past the fuse): no velocity, `fuse` is 0 and the blast is at `origin`. */\n inHand?: boolean\n }\n /** An explosive set down where the trigger is pulled (mine, C4, charge): it waits for its trigger instead of flying. */\n | {\n kind: 'place'\n explosive: string\n /** `wire`: something trips it; `remote`: the player fires it; `timer`: after `fuse` seconds. */\n triggers: readonly ('timer' | 'wire' | 'remote')[]\n energy: number\n /** Lethal radius in metres. */\n radius: number\n injuryRadius: number\n /** Cone the blast goes through, in front of `direction` (mine); absent for a blast in every direction. */\n cone?: { halfAngleDeg: number; length: number }\n /** The wire a `wire` charge stretches from where it is set down: metres out, degrees from its facing (counter-clockwise from above) and metres above it. */\n tripwire?: { length: number; angleDeg: number; height: number }\n fuse?: number\n origin: Vec3\n direction: Vec3\n }\n /** The blast behind a rocket launcher: dangerous inside `radius` metres, in the cone around `direction` (pointing away from the target). */\n | { kind: 'backblast'; radius: number; halfAngleDeg: number; origin: Vec3; direction: Vec3 }\n | { kind: 'tool'; tool: string; reach: number; duration: number; origin: Vec3; direction: Vec3 }\n | { kind: 'extinguish'; range: number; coolC: number; duration: number; origin: Vec3; direction: Vec3 }\n | { kind: 'hand'; reach: number; origin: Vec3; direction: Vec3 }\n\n/**\n * The `Hit` a ballistic shot makes at `point` (world space): the energy is what is left of the shot at that distance from its origin\n * (`shot.energyAt`), the direction and calibre come from the shot. `normal` (the surface normal at the point, when the caller knows it) does not\n * change the hit; it is accepted so that callers can pass what their raycast returned and so that a stricter implementation could use it.\n */\nexport const shotToHit = (shot: Shot, point: Vec3, normal?: Vec3): Hit => {\n void normal\n const dx = point[0] - shot.origin[0]\n const dy = point[1] - shot.origin[1]\n const dz = point[2] - shot.origin[2]\n const distance = Math.hypot(dx, dy, dz)\n return {\n type: 'ballistic',\n point: [point[0], point[1], point[2]],\n direction: [shot.direction[0], shot.direction[1], shot.direction[2]],\n energy: shot.energyAt(distance),\n caliber: shot.caliber,\n ...(shot.mass === undefined ? {} : { mass: shot.mass }),\n ...shotExtras(shot, distance),\n source: shot.source ?? shot.weapon,\n }\n}\n\n/**\n * The `Hit` a non-firearm `Use` makes at `point` (world space), or `null` for uses that do not damage by themselves.\n *\n * - `melee` -> `blunt` / `slash` with the swing's `energy`, contact `radius` and `direction`;\n * - `flame` -> `fire` and `heat` -> `heat`, with `temperature`, `duration` and a contact radius of at most 0.3 m (one ray of the cone);\n * - `throw` -> the blast (`explosive`, `energy`, `radius`, centred on `point`, the place it detonates). A thrown item with no blast energy but\n * a `fire` patch (a molotov) gives that patch as a `fire` hit (`temperature`, `radius`, `seconds` as `duration`). No energy and no fire -> `null`;\n * - `tool`, `extinguish` and `hand` -> `null` (tools work on joints, the extinguisher cools, the hand only grabs).\n *\n * `normal` does not change the hit (same as `shotToHit`).\n */\nexport const useToHit = (use: Use, point: Vec3, normal?: Vec3): Hit | null => {\n void normal\n const p: Vec3 = [point[0], point[1], point[2]]\n switch (use.kind) {\n case 'melee':\n return { type: use.damage, point: p, direction: [use.direction[0], use.direction[1], use.direction[2]], energy: use.energy, radius: use.radius }\n case 'flame':\n case 'heat':\n return {\n type: use.kind === 'flame' ? 'fire' : 'heat',\n point: p,\n direction: [use.direction[0], use.direction[1], use.direction[2]],\n temperature: use.temperature,\n radius: Math.min(use.radius, 0.3),\n duration: use.duration,\n }\n case 'throw':\n if (use.energy > 0) return { type: 'explosive', point: p, energy: use.energy, radius: use.radius }\n if (use.fire) return { type: 'fire', point: p, temperature: use.fire.temperature, radius: use.fire.radius, duration: use.fire.seconds }\n return null\n default:\n return null\n }\n}\n","import type { Hit } from './destruction'\n\n/**\n * How a container of flammable fluid (a fuel tank, a jerrycan, a gas bottle) is set alight by what hits it. A normal bullet that goes through only\n * makes a leak; the leak lights when something supplies a flame: a spark of a hard round on metal, an incendiary or tracer round, a fire nearby\n * or a blast. These are the numbers of the target side; the numbers of the round (core, jacket, incendiary, tracer) are in the weapons module\n * (`rules.ignition` of `@adatechnology/game-weapons`) and reach the target in `Hit.ignition`. Every number is a default to be changed per game.\n */\nexport interface IgnitionRules {\n /**\n * How much of the spark and of the flame of a round reaches the vapour, by how full the container is: points `[filled, factor]`, `filled` 0..1\n * (litres over capacity), `factor` 0..1, linear between points. A full container holds a mixture too rich to burn (the vapour has no air) and\n * mostly leaks; a nearly empty one holds the vapour/air mixture of a flammable range and lights the easiest; a dry one has little vapour left.\n * Default: 0.6 empty, 1 at 10 percent, 0.6 at 35, 0.3 at 65, 0.15 at 90 and 0.12 full.\n */\n fillCurve: ReadonlyArray<readonly [number, number]>\n /** 0..1: how much of the fill factor also weighs on the flame of an incendiary or tracer (1: as much as on a spark; 0: not at all). Default 0.5. */\n flameFillInfluence: number\n /** Chance of the flame of a round that is flagged `incendiary` or `tracer` but carries no `ignition` numbers (a host that passes only the flags). */\n flameDefaults: { incendiary: number; tracer: number }\n /**\n * What a spark needs to strike: a factor 0..1 by material id of the struck part. A material that is not listed but is metal takes\n * `sparkMetalDefault`; a part that is not metal never sparks. Default: steel and iron 1, aluminium 0.25.\n */\n sparkTarget: Readonly<Record<string, number>>\n sparkMetalDefault: number\n /**\n * Factor 0..1 on the spark by fluid (default 1): diesel has a flash point of 52 degrees C and more, so a spark that lights petrol vapour does\n * not light it (a flame does). Default: diesel 0.15.\n */\n sparkFluid: Readonly<Record<string, number>>\n /** A leaking container of flammable fluid within `radius` metres of a burning part or a burning fuel stain lights at `chancePerSecond`. */\n fireNear: { radius: number; chancePerSecond: number }\n}\n\n/** Defaults of `IgnitionRules`. */\nexport const DEFAULT_IGNITION_RULES: IgnitionRules = {\n fillCurve: [\n [0, 0.6],\n [0.1, 1],\n [0.35, 0.6],\n [0.65, 0.3],\n [0.9, 0.15],\n [1, 0.12],\n ],\n flameFillInfluence: 0.5,\n flameDefaults: { incendiary: 0.7, tracer: 0.2 },\n sparkTarget: { steel: 1, iron: 1, aluminium: 0.25 },\n sparkMetalDefault: 0.5,\n sparkFluid: { diesel: 0.15 },\n fireNear: { radius: 1.5, chancePerSecond: 0.5 },\n}\n\n/** Merges a partial `IgnitionRules` over the defaults (an object is merged one level deep). */\nexport const resolveIgnitionRules = (rules?: Partial<IgnitionRules>): IgnitionRules => ({\n ...DEFAULT_IGNITION_RULES,\n ...rules,\n flameDefaults: { ...DEFAULT_IGNITION_RULES.flameDefaults, ...rules?.flameDefaults },\n sparkTarget: { ...DEFAULT_IGNITION_RULES.sparkTarget, ...rules?.sparkTarget },\n sparkFluid: { ...DEFAULT_IGNITION_RULES.sparkFluid, ...rules?.sparkFluid },\n fireNear: { ...DEFAULT_IGNITION_RULES.fireNear, ...rules?.fireNear },\n})\n\n/** Linear interpolation of the fill curve at `fill` (0..1); outside the points it keeps the first or the last. */\nexport const fillFactor = (fill: number, curve: IgnitionRules['fillCurve'] = DEFAULT_IGNITION_RULES.fillCurve): number => {\n if (curve.length === 0) return 1\n const f = Math.min(1, Math.max(0, fill))\n if (f <= curve[0]![0]) return curve[0]![1]\n for (let i = 1; i < curve.length; i++) {\n const [x1, y1] = curve[i]!\n const [x0, y0] = curve[i - 1]!\n if (f <= x1) return x1 === x0 ? y1 : y0 + ((y1 - y0) * (f - x0)) / (x1 - x0)\n }\n return curve[curve.length - 1]![1]\n}\n\n/** The factor of what a spark strikes: 0 when the struck part is not metal. */\nexport const sparkTargetFactor = (materialId: string, metal: boolean, rules: IgnitionRules = DEFAULT_IGNITION_RULES): number =>\n !metal ? 0 : rules.sparkTarget[materialId] ?? rules.sparkMetalDefault\n\n/**\n * Chance that one round that went through the wall of a container lights the fluid that leaks: the spark (only on metal) and the flame (any\n * wall), each weighed by the fill of the container; the two are independent. 0 when the round carries nothing (`Hit.ignition` absent and not\n * flagged `incendiary` or `tracer`): a plain bullet on a plain wall only leaks.\n */\nexport const ignitionChance = (hit: Pick<Hit, 'incendiary' | 'tracer' | 'ignition'>, target: { sparkTarget: number; fill: number; fluid?: string }, rules: IgnitionRules = DEFAULT_IGNITION_RULES): number => {\n const k = fillFactor(target.fill, rules.fillCurve)\n const spark = (hit.ignition?.spark ?? 0) * target.sparkTarget * (target.fluid === undefined ? 1 : rules.sparkFluid[target.fluid] ?? 1) * k\n const flameBase = hit.ignition?.flame ?? Math.max(hit.incendiary ? rules.flameDefaults.incendiary : 0, hit.tracer ? rules.flameDefaults.tracer : 0)\n const flame = flameBase * (1 - rules.flameFillInfluence * (1 - k))\n return 1 - (1 - Math.min(1, Math.max(0, spark))) * (1 - Math.min(1, Math.max(0, flame)))\n}\n","import type { Vec3 } from './destruction'\n\n/** Pose of one part (or of the whole item) at a key: position offset in metres and Euler XYZ rotation in radians, both relative to the rest pose. */\nexport interface AnimationPose {\n position?: Vec3\n rotation?: Vec3\n}\n\nexport interface AnimationKey {\n /** Seconds from the start of the clip. */\n t: number\n /** Pose of the item's root. */\n position?: Vec3\n rotation?: Vec3\n /** Poses of named parts: the key is a destruction part id (a pistol `reload` moves `mag`; a car door `open` rotates `door_l`). */\n parts?: Record<string, AnimationPose>\n}\n\nexport interface AnimationEventSpec {\n /** Seconds from the start of the clip. */\n t: number\n /** snake_case type the host maps (`sound`, `eject_casing`, `door_latch`...). */\n type: string\n data?: Record<string, unknown>\n}\n\n/** A use animation a module brings with its item. Poses between keys are interpolated by the player (the test room does it linearly). */\nexport interface AnimationClipSpec {\n /** snake_case: `reload`, `open`, `drink`... Unique within the item. */\n id: string\n /** Seconds. */\n duration: number\n keys: AnimationKey[]\n events?: AnimationEventSpec[]\n}\n\n/** What an item exposes when it brings its own animations. */\nexport interface ItemAnimationContract {\n animations: AnimationClipSpec[]\n}\n\nconst finite3 = (v: unknown): boolean => Array.isArray(v) && v.length === 3 && v.every((n) => typeof n === 'number' && Number.isFinite(n))\n\n/**\n * Problems with a clip (empty when it is valid): a snake_case id, a positive finite duration, at least one key, key and event times inside\n * `[0, duration]` and not going backwards, finite vectors, every named part one of `partIds`, event types that are non-empty strings and\n * JSON-serializable event data.\n */\nexport const checkAnimation = (clip: AnimationClipSpec, partIds: Iterable<string>): { ok: boolean; problems: string[] } => {\n const problems: string[] = []\n const parts = new Set(partIds)\n const id = String(clip?.id ?? '')\n if (!/^[a-z][a-z0-9_]*$/.test(id)) problems.push(`clip id \"${id}\" must be snake_case`)\n const label = `clip \"${id}\"`\n if (!(typeof clip?.duration === 'number' && Number.isFinite(clip.duration) && clip.duration > 0)) problems.push(`${label} needs a positive finite duration`)\n const dur = typeof clip?.duration === 'number' && clip.duration > 0 ? clip.duration : Infinity\n if (!Array.isArray(clip?.keys) || clip.keys.length === 0) {\n problems.push(`${label} needs at least one key`)\n return { ok: false, problems }\n }\n let prev = -Infinity\n clip.keys.forEach((k, i) => {\n if (!(typeof k.t === 'number' && Number.isFinite(k.t)) || k.t < 0 || k.t > dur + 1e-9) problems.push(`${label} key ${i} has t=${String(k.t)} outside 0..${dur}`)\n else if (k.t < prev) problems.push(`${label} key ${i} goes back in time (${k.t} < ${prev})`)\n else prev = k.t\n for (const f of ['position', 'rotation'] as const) if (k[f] !== undefined && !finite3(k[f])) problems.push(`${label} key ${i} has an invalid ${f}`)\n for (const [pid, pose] of Object.entries(k.parts ?? {})) {\n if (!parts.has(pid)) problems.push(`${label} key ${i} moves unknown part \"${pid}\"`)\n for (const f of ['position', 'rotation'] as const) if (pose?.[f] !== undefined && !finite3(pose[f])) problems.push(`${label} key ${i} part \"${pid}\" has an invalid ${f}`)\n }\n })\n let prevEv = -Infinity\n ;(clip.events ?? []).forEach((e, i) => {\n if (!(typeof e.t === 'number' && Number.isFinite(e.t)) || e.t < 0 || e.t > dur + 1e-9) problems.push(`${label} event ${i} has t=${String(e.t)} outside 0..${dur}`)\n else if (e.t < prevEv) problems.push(`${label} event ${i} goes back in time`)\n else prevEv = e.t\n if (typeof e.type !== 'string' || e.type === '') problems.push(`${label} event ${i} needs a type`)\n try {\n JSON.stringify(e.data ?? {})\n } catch {\n problems.push(`${label} event ${i} data is not JSON`)\n }\n })\n return { ok: problems.length === 0, problems }\n}\n","import type { AnimationClipSpec, AnimationEventSpec, AnimationPose } from './animation'\nimport { checkAnimation } from './animation'\nimport type { HostEvent } from './module'\n\n/** Clips a tool can bring, one per move of its cycle. A tool brings the ones it has; a missing clip is simply not played. */\nexport const TOOL_CLIP = {\n DRAW: 'draw',\n SHOT: 'shot',\n MISFIRE: 'misfire',\n EMPTY: 'empty',\n CYCLE: 'cycle',\n RELOAD: 'reload',\n FEED: 'feed',\n FAULT: 'fault',\n CLEAR: 'clear',\n SAFETY_ON: 'safety_on',\n SAFETY_OFF: 'safety_off',\n MODE: 'mode',\n /** A throwable with the pin out, held until it is thrown. */\n COOK: 'cook',\n /** The stock folds, unfolds, slides in or out (variants `fold`, `unfold`, `collapse`, `extend`). */\n STOCK: 'stock',\n /** A light or a laser is switched (variants `on`, `off`). */\n TOGGLE: 'toggle',\n} as const\nexport type ToolClipId = (typeof TOOL_CLIP)[keyof typeof TOOL_CLIP]\n\n/** What a renderer does when a rule event arrives. `variant` picks `<clip>_<variant>` when the tool has it, else `<clip>`. */\nexport type ToolAnimationStep =\n | { readonly type: 'play'; readonly clip: ToolClipId; readonly variant?: string; readonly duration?: number; readonly repeat?: number }\n /** Move the clip that is playing to the marker (a clip event `stage` with `data.stage`) the rule just reached. */\n | { readonly type: 'sync'; readonly stage: string }\n /** The rule says the phase is over: the clip jumps to its end if it is still running. */\n | { readonly type: 'finish'; readonly clip: ToolClipId }\n\nconst stockVariant = (event: Extract<HostEvent, { type: 'stock' }>): string => {\n const isFolding = event.kind === undefined ? false : event.kind.includes('fold')\n if (event.state === 'collapsed') return isFolding ? 'fold' : 'collapse'\n return isFolding ? 'unfold' : 'extend'\n}\n\n/** The move a host event asks of the tool in hand, or null when it has no motion. */\nexport const toolAnimationStep = (event: HostEvent): ToolAnimationStep | null => {\n switch (event.type) {\n case 'tool':\n return { type: 'play', clip: TOOL_CLIP.DRAW, ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'shot':\n return { type: 'play', clip: TOOL_CLIP.SHOT, repeat: Math.max(1, event.rounds ?? 1) }\n case 'misfire':\n return { type: 'play', clip: TOOL_CLIP.MISFIRE }\n case 'empty':\n return { type: 'play', clip: TOOL_CLIP.EMPTY }\n case 'mode':\n return { type: 'play', clip: TOOL_CLIP.MODE, variant: event.mode }\n case 'fault':\n return { type: 'play', clip: TOOL_CLIP.FAULT, variant: event.fault }\n case 'clear':\n if (event.phase === 'end') return { type: 'finish', clip: TOOL_CLIP.CLEAR }\n return { type: 'play', clip: TOOL_CLIP.CLEAR, variant: event.fault, ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'safety':\n return { type: 'play', clip: event.on ? TOOL_CLIP.SAFETY_ON : TOOL_CLIP.SAFETY_OFF }\n case 'cycle':\n if (event.phase === 'end') return { type: 'finish', clip: TOOL_CLIP.CYCLE }\n return { type: 'play', clip: TOOL_CLIP.CYCLE, ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'reload':\n if (event.phase === 'end') return { type: 'finish', clip: TOOL_CLIP.RELOAD }\n return { type: 'play', clip: TOOL_CLIP.RELOAD, ...(event.kind === undefined ? {} : { variant: event.kind }), ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'stage':\n return { type: 'sync', stage: event.stage }\n case 'feed':\n return { type: 'play', clip: TOOL_CLIP.FEED }\n case 'cook':\n if (event.phase === 'start') return { type: 'play', clip: TOOL_CLIP.COOK, duration: event.fuse }\n return { type: 'finish', clip: TOOL_CLIP.COOK }\n case 'stock':\n return { type: 'play', clip: TOOL_CLIP.STOCK, variant: stockVariant(event), ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'toggle':\n return { type: 'play', clip: TOOL_CLIP.TOGGLE, variant: event.on ? 'on' : 'off' }\n default:\n return null\n }\n}\n\n/** Where a renderer puts the poses: every part of the tool by id (the ids the clips move), and the whole tool. Poses are offsets from rest. */\nexport interface ToolRig {\n setPartPose(partId: string, pose: AnimationPose): void\n setRootPose?(pose: AnimationPose): void\n}\n\n/** Clips by id, with the variants as `<clip>_<variant>`. */\nexport type ToolClipSet = Readonly<Record<string, AnimationClipSpec>>\n\n/** A renderer's tool animator: feed it the host events and the frame time. */\nexport interface ToolAnimator {\n handle(event: HostEvent): void\n update(dt: number): void\n /** Ids of the clips playing now. */\n readonly playing: readonly string[]\n dispose(): void\n}\n\nexport const STAGE_EVENT = 'stage'\n\n/** The clip with its times (keys and events) scaled so that it lasts `duration` seconds. */\nexport const scaleClip = (clip: AnimationClipSpec, duration: number): AnimationClipSpec => {\n const factor = clip.duration > 0 ? duration / clip.duration : 1\n return {\n ...clip,\n duration,\n keys: clip.keys.map((key) => ({ ...key, t: key.t * factor })),\n ...(clip.events ? { events: clip.events.map((event) => ({ ...event, t: event.t * factor })) } : {}),\n }\n}\n\nconst ZERO: [number, number, number] = [0, 0, 0]\nconst mix = (from: readonly number[], to: readonly number[], fraction: number): [number, number, number] => [\n (from[0] ?? 0) + ((to[0] ?? 0) - (from[0] ?? 0)) * fraction,\n (from[1] ?? 0) + ((to[1] ?? 0) - (from[1] ?? 0)) * fraction,\n (from[2] ?? 0) + ((to[2] ?? 0) - (from[2] ?? 0)) * fraction,\n]\n\n/** Pose of the whole tool (`partId` undefined) or of one part at `time`, linear between keys; a key that does not name it means rest. */\nexport const sampleClip = (clip: AnimationClipSpec, partId: string | undefined, time: number): { position: [number, number, number]; rotation: [number, number, number] } => {\n const points = clip.keys.map((key) => {\n const pose = partId === undefined ? key : key.parts?.[partId]\n return { t: key.t, position: pose?.position ?? ZERO, rotation: pose?.rotation ?? ZERO }\n })\n const first = points[0]\n if (!first || first.t > 0) points.unshift({ t: 0, position: ZERO, rotation: ZERO })\n const last = points[points.length - 1]\n if (!last) return { position: ZERO, rotation: ZERO }\n if (time >= last.t) return { position: mix(last.position, last.position, 0), rotation: mix(last.rotation, last.rotation, 0) }\n const index = Math.max(0, points.findIndex((point, i) => time >= point.t && time < (points[i + 1]?.t ?? Infinity)))\n const from = points[index]\n const to = points[index + 1]\n if (!from || !to) return { position: ZERO, rotation: ZERO }\n const fraction = to.t > from.t ? (time - from.t) / (to.t - from.t) : 0\n return { position: mix(from.position, to.position, fraction), rotation: mix(from.rotation, to.rotation, fraction) }\n}\n\n/** Problems with a clip set (empty when valid): each key is the clip id (or `<clip>_<variant>`), every clip passes `checkAnimation`, and a `stage` event names its stage. */\nexport const checkToolClips = (clips: ToolClipSet, partIds: Iterable<string>): { ok: boolean; problems: string[] } => {\n const parts = [...partIds]\n const problems: string[] = []\n for (const [key, clip] of Object.entries(clips)) {\n if (clip.id !== key) problems.push(`clip \"${key}\" has the id \"${clip.id}\"`)\n if (!(clip.duration > 0)) problems.push(`clip \"${key}\" has no duration`)\n problems.push(...checkAnimation(clip, parts).problems)\n for (const event of clip.events ?? []) if (event.type === STAGE_EVENT && typeof event.data?.stage !== 'string') problems.push(`clip \"${key}\" has a stage event without data.stage`)\n }\n return { ok: problems.length === 0, problems }\n}\n\ninterface Instance {\n readonly name: string\n readonly clip: AnimationClipSpec\n time: number\n delay: number\n fired: number\n}\n\nexport interface ToolClipPlayerOptions {\n clips: ToolClipSet\n rig: ToolRig\n /** Called for each clip event as its time passes (`eject_casing`, `drop_magazine`, `stage`...). */\n onEvent?(event: AnimationEventSpec, clip: string): void\n /** Seconds between the rounds of a `repeat` (a burst): default 0.1. */\n repeatInterval?(): number\n}\n\n/** The default player of a tool's clips: runs the steps of `toolAnimationStep` against a rig, scaled to the duration the rule gives. */\nexport interface ToolClipPlayer {\n apply(step: ToolAnimationStep): void\n update(dt: number): void\n readonly playing: readonly string[]\n /** The clips being played with the time each has reached and the clip itself (scaled to the duration the rule gave), for a renderer that has to follow what the clip does now (the hands working a part). */\n readonly running: ReadonlyArray<{ readonly name: string; readonly time: number; readonly clip: AnimationClipSpec }>\n}\n\nexport const createToolClipPlayer = (options: ToolClipPlayerOptions): ToolClipPlayer => {\n const { clips, rig, onEvent } = options\n let instances: Instance[] = []\n\n const find = (clip: string, variant?: string): { name: string; clip: AnimationClipSpec } | undefined => {\n const name = variant !== undefined && clips[`${clip}_${variant}`] ? `${clip}_${variant}` : clip\n const found = clips[name]\n return found ? { name, clip: found } : undefined\n }\n\n const render = (instance: Instance): void => {\n const time = Math.min(instance.time, instance.clip.duration)\n const root = sampleClip(instance.clip, undefined, time)\n if (instance.clip.keys.some((key) => key.position || key.rotation)) rig.setRootPose?.(root)\n const touched = new Set(instance.clip.keys.flatMap((key) => Object.keys(key.parts ?? {})))\n for (const id of touched) rig.setPartPose(id, sampleClip(instance.clip, id, time))\n }\n\n const fireEvents = (instance: Instance, upTo: number): void => {\n const events = instance.clip.events ?? []\n while (instance.fired < events.length && (events[instance.fired]?.t ?? Infinity) <= upTo + 1e-9) {\n const event = events[instance.fired]\n instance.fired += 1\n if (event) onEvent?.(event, instance.name)\n }\n }\n\n return {\n apply(step) {\n if (step.type === 'sync') {\n for (const instance of instances) {\n const marker = (instance.clip.events ?? []).find((event) => event.type === STAGE_EVENT && event.data?.stage === step.stage)\n if (marker && instance.time < marker.t) instance.time = marker.t\n }\n return\n }\n if (step.type === 'finish') {\n for (const instance of instances) {\n if (instance.name !== step.clip && !instance.name.startsWith(`${step.clip}_`)) continue\n fireEvents(instance, instance.clip.duration)\n instance.time = instance.clip.duration\n }\n return\n }\n const found = find(step.clip, step.variant)\n if (!found) return\n const clip = step.duration && step.duration > 0 ? scaleClip(found.clip, step.duration) : found.clip\n const interval = options.repeatInterval?.() ?? 0.1\n instances = instances.filter((existing) => existing.name !== found.name || existing.delay > 0)\n for (let round = 0; round < (step.repeat ?? 1); round++) {\n instances.push({ name: found.name, clip, time: 0, delay: round * interval, fired: 0 })\n }\n },\n update(dt) {\n for (const instance of instances) {\n const carried = instance.delay > 0 ? dt - instance.delay : dt\n if (instance.delay > 0) {\n instance.delay = Math.max(0, instance.delay - dt)\n if (instance.delay > 0) continue\n }\n instance.time += carried\n fireEvents(instance, instance.time)\n render(instance)\n }\n instances = instances.filter((instance) => instance.delay > 0 || instance.time < instance.clip.duration)\n },\n get playing() {\n return instances.map((instance) => instance.name)\n },\n get running() {\n return instances.filter((instance) => instance.delay <= 0).map((instance) => ({ name: instance.name, time: instance.time, clip: instance.clip }))\n },\n }\n}\n","type PlainObject = Record<string, unknown>\ntype Entry = { readonly id: string }\n\n/** Keys that would reach the prototype of the result when a patch comes from parsed JSON. */\nconst UNSAFE_KEYS: ReadonlySet<string> = new Set(['__proto__', 'constructor', 'prototype'])\n\nconst isPlainObject = (value: unknown): value is PlainObject =>\n typeof value === 'object' && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype\n\n/** Recursively optional; arrays and functions are replaced as a whole, objects are merged. */\nexport type DeepPartial<TValue> = TValue extends (...args: never[]) => unknown\n ? TValue\n : TValue extends readonly unknown[]\n ? TValue\n : TValue extends object\n ? { [TKey in keyof TValue]?: DeepPartial<TValue[TKey]> }\n : TValue\n\n/** Merges `patch` over `base`: plain objects merge field by field, arrays, functions and primitives replace. `undefined` in the patch is ignored. */\nexport const deepMerge = <TBase extends object>(base: TBase, patch: object | undefined): TBase => {\n if (!patch) return base\n const result: PlainObject = { ...(base as PlainObject) }\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined || UNSAFE_KEYS.has(key)) continue\n const current = result[key]\n result[key] = isPlainObject(current) && isPlainObject(value) ? deepMerge(current, value) : value\n }\n return result as TBase\n}\n\n/** The shipped entries with the ones from `extra` added or, when the id exists, replaced. */\nexport const mergeById = <TEntry extends Entry>(shipped: readonly TEntry[], extra: readonly TEntry[] | undefined): Map<string, TEntry> => {\n const entries = new Map<string, TEntry>()\n for (const entry of [...shipped, ...(extra ?? [])]) entries.set(entry.id, entry)\n return entries\n}\n\n/** Applies `patch` by id; a patch for an id that does not exist is ignored. */\nexport const applyPatches = <TEntry extends Entry>(entries: Map<string, TEntry>, patches: Readonly<Record<string, DeepPartial<TEntry> | Partial<TEntry>>> | undefined): void => {\n for (const [id, patch] of Object.entries(patches ?? {})) {\n const entry = entries.get(id)\n if (entry) entries.set(id, deepMerge(entry, patch))\n }\n}\n\nexport const removeIds = (entries: Map<string, unknown>, ids: readonly string[] | undefined): void => {\n for (const id of ids ?? []) entries.delete(id)\n}\n","import type { Vec3 } from './destruction'\n\n/**\n * The bench of a module: controls, layers and counters it declares as data. The host keeps the values, draws them in a generic way and hands\n * every change back through `ModuleHost.bench`. Nothing here is specific to a kind of module.\n */\nexport type ControlValue = number | boolean | string\n\nexport interface ChoiceOption {\n readonly id: string\n readonly name: string\n /** Heading the host lists the option under (`optgroup`, a grouped row of buttons). Options of a group must sit next to each other. */\n readonly group?: string\n}\n\ninterface ControlBase {\n /** snake_case, unique across the module's controls, layers and metrics. */\n readonly id: string\n /** Display name, already translated for the locale the host asked for. */\n readonly name: string\n readonly hint?: string\n readonly hidden?: boolean\n /**\n * The change (or the press, for an action) takes a noticeable time, a third of a second or more: the host shows its loading indicator while it works, with this text, or the control's name for `true`.\n * Only the host's own controls panel does it; a change made through `TestRoom.bench().set / act` runs at once.\n */\n readonly slow?: boolean | string\n}\n\nexport interface NumberControl extends ControlBase {\n readonly kind: 'number'\n readonly min: number\n readonly max: number\n readonly step?: number\n readonly unit?: string\n readonly default: number\n}\n\nexport interface BooleanControl extends ControlBase {\n readonly kind: 'boolean'\n readonly default: boolean\n}\n\nexport interface ChoiceControl extends ControlBase {\n readonly kind: 'choice'\n readonly options: readonly ChoiceOption[]\n readonly default: string\n}\n\n/** A button: no value, only the press. */\nexport interface ActionControl extends ControlBase {\n readonly kind: 'action'\n}\n\nexport type ModuleControl = NumberControl | BooleanControl | ChoiceControl | ActionControl\n\n/** Something of the module the viewer turns on or off (smoke, flash, casings). */\nexport interface ModuleLayer {\n readonly id: string\n readonly name: string\n /** On unless `false`. */\n readonly default?: boolean\n}\n\n/** Pulled: the room calls read only when it samples (~4 Hz, or on TestRoom.metrics()). */\nexport interface ModuleMetric {\n readonly id: string\n readonly name: string\n readonly unit?: string\n /** Budget: the host shows a bar and warns past it. */\n readonly max?: number\n readonly digits?: number\n read(): number | string\n}\n\nexport type BenchChange =\n | { readonly kind: 'control'; readonly id: string; readonly value: ControlValue }\n | { readonly kind: 'layer'; readonly id: string; readonly on: boolean }\n | { readonly kind: 'action'; readonly id: string }\n\nexport interface ControlPatch {\n readonly hidden?: boolean\n readonly disabled?: boolean\n readonly options?: readonly ChoiceOption[]\n readonly value?: ControlValue\n}\n\n/** What the host lends a module that declares a bench: the current values and the changes. */\nexport interface ModuleBench {\n value(id: string): ControlValue | undefined\n layer(id: string): boolean\n /** Right after attach returns, the host sends one change per control (not actions) and per layer, in declaration order. */\n onChange(listener: (change: BenchChange) => void): () => void\n /** `value` sets without emitting (no echo loops); `options` falls back to the first option if the value is no longer offered. */\n patch(id: string, patch: ControlPatch): void\n /** Move the host camera (a near / middle / far choice). */\n look(eye: Vec3, target: Vec3): void\n /** Shows a sheet on the host's panel, or takes it down with `null`. A host without a sheet area ignores it. */\n sheet?(sheet: BenchSheet | null): void\n}\n\n/**\n * A card of text the module puts on the host's panel (the sheet of an effect, of a weapon): what it is, its numbers, its steps, its colours and,\n * optionally, a strip of segments over time. Names and texts are already translated for the host's locale.\n */\nexport interface BenchSheet {\n readonly kicker?: string\n readonly title: string\n readonly body?: string\n readonly facts?: readonly { readonly label: string; readonly value: string }[]\n readonly steps?: readonly { readonly at: string; readonly text: string }[]\n readonly swatches?: readonly { readonly color: string; readonly name: string }[]\n readonly note?: string\n /** A strip of named segments (seconds), with tick marks and a playhead that follows the module metric `metric`. */\n readonly timeline?: {\n readonly segments: readonly { readonly name: string; readonly start: number; readonly end: number; readonly color: string }[]\n readonly ticks: readonly number[]\n readonly metric: string\n }\n}\n\nexport interface BenchReport {\n readonly ok: boolean\n readonly problems: readonly string[]\n}\n\nexport interface BenchDeclaration {\n readonly controls?: readonly ModuleControl[]\n readonly layers?: readonly ModuleLayer[]\n readonly metrics?: readonly ModuleMetric[]\n}\n\nconst SNAKE_CASE = /^[a-z][a-z0-9_]*$/\nconst finite = (n: unknown): n is number => typeof n === 'number' && Number.isFinite(n)\n\nfunction checkControl(control: ModuleControl, problems: string[]): void {\n const label = `control \"${control.id}\"`\n if (control.kind === 'number') {\n if (!finite(control.min) || !finite(control.max) || control.min >= control.max) problems.push(`${label} needs min < max`)\n if (control.step !== undefined && !(finite(control.step) && control.step > 0)) problems.push(`${label} needs a step > 0`)\n if (!finite(control.default) || control.default < control.min || control.default > control.max) problems.push(`${label} default ${String(control.default)} is outside ${control.min}..${control.max}`)\n return\n }\n if (control.kind !== 'choice') return\n if (control.options.length === 0) {\n problems.push(`${label} needs at least one option`)\n return\n }\n const seen = new Set<string>()\n const groups = new Set<string>()\n let previousGroup: string | undefined\n for (const option of control.options) {\n if (seen.has(option.id)) problems.push(`${label} repeats option \"${option.id}\"`)\n seen.add(option.id)\n if (option.group !== undefined && (typeof option.group !== 'string' || option.group === '')) problems.push(`${label} option \"${option.id}\" has an empty group`)\n else if (option.group !== undefined && option.group !== previousGroup && groups.has(option.group)) problems.push(`${label} group \"${option.group}\" is split: its options must be next to each other`)\n if (typeof option.group === 'string' && option.group !== '') groups.add(option.group)\n previousGroup = option.group\n }\n if (!seen.has(control.default)) problems.push(`${label} default \"${control.default}\" is not among its options`)\n}\n\n/** snake_case ids unique across controls, layers and metrics; min < max; step > 0; default in range; options non-empty, unique, default among them, each group in one run; metric max > 0. */\nexport function checkBench(declared: BenchDeclaration): BenchReport {\n const problems: string[] = []\n const ids = new Set<string>()\n const claim = (kind: string, id: string): void => {\n if (!SNAKE_CASE.test(id)) problems.push(`${kind} id \"${id}\" must be snake_case`)\n if (ids.has(id)) problems.push(`duplicate id \"${id}\" across controls, layers and metrics`)\n ids.add(id)\n }\n for (const control of declared.controls ?? []) {\n claim('control', control.id)\n checkControl(control, problems)\n }\n for (const layer of declared.layers ?? []) claim('layer', layer.id)\n for (const metric of declared.metrics ?? []) {\n claim('metric', metric.id)\n if (metric.max !== undefined && !(finite(metric.max) && metric.max > 0)) problems.push(`metric \"${metric.id}\" needs a max > 0`)\n }\n return { ok: problems.length === 0, problems }\n}\n","/** The weather, light and ground as the world is right now. Written by whoever drives the weather, read by whoever reacts to it. */\nexport interface EnvironmentState {\n /** Rain in mm/h; 0 is dry. */\n readonly rain: number\n /** Wind in m/s along x and z, and its strength (the length of that vector). */\n readonly windX: number\n readonly windZ: number\n readonly windSpeed: number\n /** Strongest gust in m/s. */\n readonly gust: number\n /** Render fog far distance in metres. */\n readonly fogFar: number\n /** How far one can see for gameplay, in metres (not the render fog). */\n readonly visibility: number\n /** 0 is full daylight, 1 is the darkest night. */\n readonly nightFactor: number\n readonly temperatureC: number\n /** Wet ground, 0..1: rises with rain and dries after it stops. */\n readonly wetness: number\n}\n\nexport type EnvironmentKey = keyof EnvironmentState\n\n/** A calm dry day (the normal world, before anything went wrong). */\nexport const DEFAULT_ENVIRONMENT: EnvironmentState = {\n rain: 0,\n windX: 0,\n windZ: 0,\n windSpeed: 0,\n gust: 0,\n fogFar: 220,\n visibility: 220,\n nightFactor: 0,\n temperatureC: 20,\n wetness: 0,\n}\n\n/** The host's environment (`ModuleHost.environment`): a store the weather module writes to and the others read. */\nexport interface EnvironmentBus {\n get(): EnvironmentState\n /** Merges `patch` into the state; listeners hear it only when a value really changed. */\n set(patch: Partial<EnvironmentState>): void\n /** Hears every change with the keys that changed. Returns the unsubscribe function. */\n on(listener: (state: EnvironmentState, changed: readonly EnvironmentKey[]) => void): () => void\n}\n\n/** A plain store that implements the bus; the test room and tests use it, a game may bring its own. */\nexport function createEnvironmentBus(initial: Partial<EnvironmentState> = {}): EnvironmentBus {\n let state: EnvironmentState = { ...DEFAULT_ENVIRONMENT, ...initial }\n const listeners = new Set<(state: EnvironmentState, changed: readonly EnvironmentKey[]) => void>()\n return {\n get: () => state,\n set(patch) {\n const changed = (Object.keys(patch) as EnvironmentKey[]).filter((key) => patch[key] !== undefined && patch[key] !== state[key])\n if (changed.length === 0) return\n const next = { ...state } as { -readonly [Key in EnvironmentKey]: number }\n for (const key of changed) next[key] = patch[key] as number\n state = next\n for (const listener of [...listeners]) listener(state, changed)\n },\n on(listener) {\n listeners.add(listener)\n return () => void listeners.delete(listener)\n },\n }\n}\n","import { applyPatches, deepMerge, mergeById, removeIds } from './registry'\nimport type { DeepPartial } from './registry'\n\n/** One category (kind) of items. Defaults and required contracts are inherited from the `extends` chain. */\nexport interface CategoryDef<TDefaults extends object = Record<string, unknown>> {\n readonly id: string\n /** Parent category id; the child inherits its defaults and its required contracts. */\n readonly extends?: string\n /** Field values every entry of this kind starts with; objects merge down the chain, arrays replace. */\n readonly defaults?: DeepPartial<TDefaults>\n /** Contract ids (`ContractChecker.id`) every entry of this kind, or of a descendant, must satisfy. */\n readonly requires?: readonly string[]\n /** An abstract category only groups: entries cannot declare it directly, only its descendants. */\n readonly abstract?: boolean\n}\n\n/** Where a checker is being run: the entry's kind and the chain of categories root first. */\nexport interface ContractContext {\n readonly kind: string\n readonly chain: readonly string[]\n}\n\n/** A named contract: returns the problems of an entry, each a short phrase like `missing leftover.despawnSeconds`. Empty means it holds. */\nexport interface ContractChecker<TEntry> {\n readonly id: string\n check(entry: TEntry, ctx: ContractContext): string[]\n}\n\nexport interface CategoryOptions {\n /** Categories added to the shipped ones; the same id replaces. */\n readonly extra?: readonly CategoryDef[]\n /** Partial changes by id, applied after `extra`. */\n readonly patches?: Readonly<Record<string, DeepPartial<CategoryDef> | Partial<CategoryDef>>>\n /** Ids taken out of the tree (their children are then reported by `check()`). */\n readonly remove?: readonly string[]\n}\n\nexport interface CategoryRegistry {\n get(id: string): CategoryDef | undefined\n has(id: string): boolean\n ids(): string[]\n /** Root first, ending at `id`. Throws on an unknown id, an unknown parent or a cycle. */\n chain(id: string): string[]\n /** `defaults` merged along the chain, root first, so the closest category wins. */\n defaults(id: string): Record<string, unknown>\n /** Union of `requires` along the chain, order kept, without duplicates. */\n requires(id: string): string[]\n /** True when `id` is `ancestorId` or descends from it. */\n isA(id: string, ancestorId: string): boolean\n /** Problems in the tree itself: duplicate ids, unknown `extends`, cycles. */\n check(): string[]\n}\n\nexport interface CategorizedOptions {\n /** Field of the entry that names its category. Default `kind`. */\n readonly kindField?: string\n /** Known gaps by entry id: problems starting with one of these texts go to `allowed`, so the list can shrink over time. */\n readonly allow?: Readonly<Record<string, readonly string[]>>\n}\n\nexport interface CategorizedReport {\n readonly ok: boolean\n readonly problems: string[]\n readonly allowed: string[]\n}\n\nexport const defineCategories = (defs: readonly CategoryDef[], options: CategoryOptions = {}): CategoryRegistry => {\n const problems: string[] = []\n const duplicates = (list: readonly CategoryDef[]): void => {\n const ids = new Set<string>()\n for (const def of list) {\n if (ids.has(def.id)) problems.push(`duplicate category \"${def.id}\"`)\n ids.add(def.id)\n }\n }\n duplicates(defs)\n duplicates(options.extra ?? [])\n\n const entries = mergeById(defs, options.extra)\n applyPatches(entries, options.patches)\n removeIds(entries, options.remove)\n\n const chain = (id: string): string[] => {\n const path: string[] = []\n let current: string | undefined = id\n while (current !== undefined) {\n const def = entries.get(current)\n if (!def) throw new Error(path.length === 0 ? `unknown category \"${current}\"` : `category \"${path[0]}\" has unknown parent \"${current}\"`)\n if (path.includes(current)) throw new Error(`category cycle: ${[...path, current].reverse().join(' -> ')}`)\n path.push(current)\n current = def.extends\n }\n return path.reverse()\n }\n\n const registry: CategoryRegistry = {\n get: (id) => entries.get(id),\n has: (id) => entries.has(id),\n ids: () => [...entries.keys()],\n chain,\n defaults: (id) => chain(id).reduce<Record<string, unknown>>((acc, ancestor) => deepMerge(acc, entries.get(ancestor)?.defaults), {}),\n requires: (id) => {\n const out: string[] = []\n for (const ancestor of chain(id)) for (const contract of entries.get(ancestor)?.requires ?? []) if (!out.includes(contract)) out.push(contract)\n return out\n },\n isA: (id, ancestorId) => {\n try {\n return chain(id).includes(ancestorId)\n } catch {\n return false\n }\n },\n check: () => {\n const found = [...problems]\n for (const [id, def] of entries) {\n if (def.extends !== undefined && !entries.has(def.extends)) found.push(`category \"${id}\" extends unknown \"${def.extends}\"`)\n else {\n try {\n chain(id)\n } catch (error) {\n const message = (error as Error).message\n // The same cycle is found from each of its members; the dedupe keeps one line per distinct message.\n if (message.startsWith('category cycle') && !found.includes(message)) found.push(message)\n }\n }\n }\n return found\n },\n }\n return registry\n}\n\n/** The entry with the defaults of its category underneath: the entry wins, objects merge, arrays replace. */\nexport const resolveEntry = <TEntry extends object>(registry: CategoryRegistry, entry: TEntry, kindField = 'kind'): TEntry =>\n deepMerge(registry.defaults(String((entry as Record<string, unknown>)[kindField])) as TEntry, entry)\n\n/** Checks that each entry has a known, concrete kind and satisfies every contract its chain requires. */\nexport const checkCategorized = <TEntry extends { readonly id: string }>(\n entries: readonly TEntry[],\n registry: CategoryRegistry,\n checkers: readonly ContractChecker<TEntry>[],\n options: CategorizedOptions = {},\n): CategorizedReport => {\n const kindField = options.kindField ?? 'kind'\n const byId = new Map(checkers.map((checker) => [checker.id, checker]))\n const problems: string[] = [...registry.check()]\n const allowed: string[] = []\n\n for (const entry of entries) {\n const kind = String((entry as Record<string, unknown>)[kindField])\n if (!registry.has(kind)) {\n problems.push(`\"${entry.id}\" has unknown kind \"${kind}\"`)\n continue\n }\n if (registry.get(kind)?.abstract) {\n problems.push(`\"${entry.id}\" has abstract kind \"${kind}\"`)\n continue\n }\n let path: string[]\n try {\n path = registry.chain(kind)\n } catch (error) {\n problems.push(`\"${entry.id}\" (${kind}): ${(error as Error).message}`)\n continue\n }\n const resolved = resolveEntry(registry, entry, kindField)\n for (const contract of registry.requires(kind)) {\n const owner = path.find((ancestor) => registry.get(ancestor)?.requires?.includes(contract)) ?? kind\n const checker = byId.get(contract)\n if (!checker) {\n problems.push(`kind \"${kind}\" requires contract \"${contract}\" but no checker is registered`)\n continue\n }\n const prefix = `\"${entry.id}\" (${kind}): `\n for (const problem of checker.check(resolved, { kind, chain: path })) {\n const text = `${prefix}${problem}, required by ${owner}`\n if ((options.allow?.[entry.id] ?? []).some((start) => problem.startsWith(start))) allowed.push(text)\n else problems.push(text)\n }\n }\n }\n return { ok: problems.length === 0, problems: [...new Set(problems)], allowed }\n}\n","import type { ChainDelay, ExplosionChain, PartSpec } from './types'\n\n/** What can set an explosive part off from outside, in the order a hit can carry it. */\nexport type ChainTrigger = 'shot' | 'fire' | 'explosion'\n\n/** Temperature in °C that primes a part with `chain.fire` when its `explodes.atC` is not set. */\nexport const FIRE_PRIME_C = 300\n\n/** Seconds from a trigger to the blast: a number is fixed, `[min, max]` is drawn from the world seed (one draw). */\nexport const drawChainDelay = (delay: ChainDelay, random: () => number): number => {\n if (typeof delay === 'number') return delay\n const [min, max] = delay\n return min + random() * (max - min)\n}\n\n/** The delay `spec` gives for `trigger`, or undefined when the part does not answer to it. */\nexport const chainDelayOf = (spec: PartSpec, trigger: ChainTrigger): ChainDelay | undefined => spec.explodes?.chain?.[trigger]\n\n/** Fraction of the hit points a shot must have taken off before it primes the part. */\nexport const shotDamageFractionOf = (spec: PartSpec): number => spec.explodes?.chain?.shotDamageFraction ?? 0\n\n/** The numbers of an explosive that sits in the world, as `game-weapons` gives them (`ExplosiveDef` fits). */\nexport interface WorldExplosive {\n readonly energy: number\n /** Metres within which the blast reaches other parts (and primes theirs). */\n readonly injuryRadius: number\n readonly chain?: ExplosionChain\n}\n\nexport interface ExplosivePartOptions {\n /** Temperature in °C at which fire primes (or sets off) the part; default `FIRE_PRIME_C` when the explosive answers to fire. */\n readonly atC?: number\n}\n\n/**\n * A part that explodes with the energy and reach of `explosive` and answers to what `explosive.chain` says: a bullet, fire or a blast\n * nearby primes it and it goes off after the delay. `part` is everything else about the part (shape, material, position, fluid inside).\n */\nexport const explosivePart = (explosive: WorldExplosive, part: Omit<PartSpec, 'explodes'>, options: ExplosivePartOptions = {}): PartSpec => ({\n ...part,\n explodes: {\n energy: explosive.energy,\n radius: explosive.injuryRadius,\n ...(options.atC !== undefined ? { atC: options.atC } : {}),\n ...(explosive.chain ? { chain: { ...explosive.chain } } : {}),\n },\n})\n","import type { PartShape, Quat, Vec3 } from './types'\n\nconst EPS = 1e-9\n\n/** Small vector helpers (arrays of three numbers). Pure functions; they allocate a new array. */\nexport const vec = {\n add: (a: Vec3, b: Vec3): Vec3 => [a[0] + b[0], a[1] + b[1], a[2] + b[2]],\n sub: (a: Vec3, b: Vec3): Vec3 => [a[0] - b[0], a[1] - b[1], a[2] - b[2]],\n scale: (a: Vec3, s: number): Vec3 => [a[0] * s, a[1] * s, a[2] * s],\n dot: (a: Vec3, b: Vec3): number => a[0] * b[0] + a[1] * b[1] + a[2] * b[2],\n cross: (a: Vec3, b: Vec3): Vec3 => [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]],\n length: (a: Vec3): number => Math.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2]),\n distance: (a: Vec3, b: Vec3): number => Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]),\n normalize: (a: Vec3, fallback: Vec3 = [0, 1, 0]): Vec3 => {\n const l = Math.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2])\n return l < EPS ? [fallback[0], fallback[1], fallback[2]] : [a[0] / l, a[1] / l, a[2] / l]\n },\n lerp: (a: Vec3, b: Vec3, t: number): Vec3 => [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t, a[2] + (b[2] - a[2]) * t],\n /** `a + b * s` */\n madd: (a: Vec3, b: Vec3, s: number): Vec3 => [a[0] + b[0] * s, a[1] + b[1] * s, a[2] + b[2] * s],\n}\n\nconst IDENTITY: Quat = [0, 0, 0, 1]\n\n/** Quaternion helpers (`[x, y, z, w]`). */\nexport const quat = {\n identity: (): Quat => [IDENTITY[0], IDENTITY[1], IDENTITY[2], IDENTITY[3]],\n /** Hamilton product `a * b` (apply `b` first, then `a`). */\n mul: (a: Quat, b: Quat): Quat => [\n a[3] * b[0] + a[0] * b[3] + a[1] * b[2] - a[2] * b[1],\n a[3] * b[1] - a[0] * b[2] + a[1] * b[3] + a[2] * b[0],\n a[3] * b[2] + a[0] * b[1] - a[1] * b[0] + a[2] * b[3],\n a[3] * b[3] - a[0] * b[0] - a[1] * b[1] - a[2] * b[2],\n ],\n conjugate: (q: Quat): Quat => [-q[0], -q[1], -q[2], q[3]],\n normalize: (q: Quat): Quat => {\n const l = Math.hypot(q[0], q[1], q[2], q[3])\n return l < EPS ? [0, 0, 0, 1] : [q[0] / l, q[1] / l, q[2] / l, q[3] / l]\n },\n /** Rotation of `angle` radians around a unit `axis`. */\n fromAxisAngle: (axis: Vec3, angle: number): Quat => {\n const s = Math.sin(angle / 2)\n return [axis[0] * s, axis[1] * s, axis[2] * s, Math.cos(angle / 2)]\n },\n /** Rotation matrix, row-major 3x3. */\n toMatrix: (q: Quat): number[] => {\n const [x, y, z, w] = q\n const xx = x * x, yy = y * y, zz = z * z, xy = x * y, xz = x * z, yz = y * z, wx = w * x, wy = w * y, wz = w * z\n return [1 - 2 * (yy + zz), 2 * (xy - wz), 2 * (xz + wy), 2 * (xy + wz), 1 - 2 * (xx + zz), 2 * (yz - wx), 2 * (xz - wy), 2 * (yz + wx), 1 - 2 * (xx + yy)]\n },\n /** Quaternion from three orthonormal columns (the images of the x, y and z axes). */\n fromColumns: (cx: Vec3, cy: Vec3, cz: Vec3): Quat => {\n const m00 = cx[0], m10 = cx[1], m20 = cx[2]\n const m01 = cy[0], m11 = cy[1], m21 = cy[2]\n const m02 = cz[0], m12 = cz[1], m22 = cz[2]\n const tr = m00 + m11 + m22\n let q: Quat\n if (tr > 0) {\n const s = Math.sqrt(tr + 1) * 2\n q = [(m21 - m12) / s, (m02 - m20) / s, (m10 - m01) / s, 0.25 * s]\n } else if (m00 > m11 && m00 > m22) {\n const s = Math.sqrt(1 + m00 - m11 - m22) * 2\n q = [0.25 * s, (m01 + m10) / s, (m02 + m20) / s, (m21 - m12) / s]\n } else if (m11 > m22) {\n const s = Math.sqrt(1 + m11 - m00 - m22) * 2\n q = [(m01 + m10) / s, 0.25 * s, (m12 + m21) / s, (m02 - m20) / s]\n } else {\n const s = Math.sqrt(1 + m22 - m00 - m11) * 2\n q = [(m02 + m20) / s, (m12 + m21) / s, 0.25 * s, (m10 - m01) / s]\n }\n return quat.normalize(q)\n },\n}\n\n/** Quaternion from Euler angles in radians, order XYZ (the three.js default). */\nexport const quatFromEuler = (x: number, y: number, z: number): Quat => {\n const c1 = Math.cos(x / 2), c2 = Math.cos(y / 2), c3 = Math.cos(z / 2)\n const s1 = Math.sin(x / 2), s2 = Math.sin(y / 2), s3 = Math.sin(z / 2)\n return [s1 * c2 * c3 + c1 * s2 * s3, c1 * s2 * c3 - s1 * c2 * s3, c1 * c2 * s3 + s1 * s2 * c3, c1 * c2 * c3 - s1 * s2 * s3]\n}\n\n/** Rotate a vector by a quaternion. */\nexport const rotateVec = (q: Quat, v: Vec3): Vec3 => {\n const qx = q[0], qy = q[1], qz = q[2], qw = q[3]\n const tx = 2 * (qy * v[2] - qz * v[1])\n const ty = 2 * (qz * v[0] - qx * v[2])\n const tz = 2 * (qx * v[1] - qy * v[0])\n return [v[0] + qw * tx + (qy * tz - qz * ty), v[1] + qw * ty + (qz * tx - qx * tz), v[2] + qw * tz + (qx * ty - qy * tx)]\n}\n\n/** World point to the local space of a transform (`position`, `rotation`). */\nexport const toLocal = (position: Vec3, rotation: Quat, p: Vec3): Vec3 =>\n rotateVec([-rotation[0], -rotation[1], -rotation[2], rotation[3]], [p[0] - position[0], p[1] - position[1], p[2] - position[2]])\n\n/** Local point of a transform (`position`, `rotation`) to world space. */\nexport const toWorld = (position: Vec3, rotation: Quat, p: Vec3): Vec3 => {\n const r = rotateVec(rotation, p)\n return [r[0] + position[0], r[1] + position[1], r[2] + position[2]]\n}\n\n// ---------------------------------------------------------------------------------------------------------------------------------------------\n// Shapes (part space: centred on the origin, cylinders along +Y)\n// ---------------------------------------------------------------------------------------------------------------------------------------------\n\n/** Dimensions of the bounding box of a shape, in the shape's own axes. */\nexport const shapeDims = (s: PartShape): Vec3 => {\n if (s.kind === 'box') return [s.size[0], s.size[1], s.size[2]]\n if (s.kind === 'cylinder') return [s.radius * 2, s.height, s.radius * 2]\n return [s.radius * 2, s.radius * 2, s.radius * 2]\n}\n\n/** Radius of the sphere that encloses the shape. */\nexport const shapeBound = (s: PartShape): number => {\n if (s.kind === 'box') return 0.5 * Math.hypot(s.size[0], s.size[1], s.size[2])\n if (s.kind === 'cylinder') return Math.hypot(s.radius, s.height / 2)\n return s.radius\n}\n\nexport const shapeArea = (s: PartShape): number => {\n if (s.kind === 'box') return 2 * (s.size[0] * s.size[1] + s.size[1] * s.size[2] + s.size[0] * s.size[2])\n if (s.kind === 'cylinder') return 2 * Math.PI * s.radius * s.height + 2 * Math.PI * s.radius * s.radius\n return 4 * Math.PI * s.radius * s.radius\n}\n\nexport interface ShapeRay {\n /** Entry distance along the ray (negative when the origin is inside). */\n t0: number\n /** Normal at the entry, outward. */\n n0: Vec3\n /** Exit distance. */\n t1: number\n /** Normal at the exit, outward. */\n n1: Vec3\n}\n\n/** Exact ray intersection with a shape in part space. `d` need not be normalised but must be non-zero. */\nexport const rayShape = (s: PartShape, o: Vec3, d: Vec3): ShapeRay | null => {\n if (s.kind === 'box') {\n let tmin = -Infinity, tmax = Infinity\n let a0 = 0, a1 = 0, s0 = 1, s1 = 1\n for (let i = 0; i < 3; i++) {\n const h = s.size[i] / 2\n if (Math.abs(d[i]) < EPS) {\n if (Math.abs(o[i]) > h) return null\n continue\n }\n let ta = (-h - o[i]) / d[i]\n let tb = (h - o[i]) / d[i]\n let sa = -1, sb = 1\n if (ta > tb) {\n const t = ta\n ta = tb\n tb = t\n sa = 1\n sb = -1\n }\n if (ta > tmin) {\n tmin = ta\n a0 = i\n s0 = sa\n }\n if (tb < tmax) {\n tmax = tb\n a1 = i\n s1 = sb\n }\n if (tmin > tmax) return null\n }\n if (tmax < 0 || !Number.isFinite(tmin) || !Number.isFinite(tmax)) return null\n const n0: Vec3 = [0, 0, 0]\n const n1: Vec3 = [0, 0, 0]\n n0[a0] = s0\n n1[a1] = s1\n return { t0: tmin, n0, t1: tmax, n1 }\n }\n if (s.kind === 'sphere') {\n const b = vec.dot(o, d)\n const a = vec.dot(d, d)\n const c = vec.dot(o, o) - s.radius * s.radius\n const disc = b * b - a * c\n if (disc < 0) return null\n const sq = Math.sqrt(disc)\n const t0 = (-b - sq) / a\n const t1 = (-b + sq) / a\n if (t1 < 0) return null\n const p0 = vec.madd(o, d, t0)\n const p1 = vec.madd(o, d, t1)\n return { t0, n0: vec.normalize(p0), t1, n1: vec.normalize(p1) }\n }\n // cylinder along Y: intersection of the infinite cylinder interval and the y slab\n const r = s.radius\n const hh = s.height / 2\n const a = d[0] * d[0] + d[2] * d[2]\n const c = o[0] * o[0] + o[2] * o[2] - r * r\n let tA = -Infinity, tB = Infinity\n if (a > EPS) {\n const b = o[0] * d[0] + o[2] * d[2]\n const disc = b * b - a * c\n if (disc < 0) return null\n const sq = Math.sqrt(disc)\n tA = (-b - sq) / a\n tB = (-b + sq) / a\n } else if (c > 0) return null\n let yA = -Infinity, yB = Infinity\n if (Math.abs(d[1]) > EPS) {\n yA = (-hh - o[1]) / d[1]\n yB = (hh - o[1]) / d[1]\n if (yA > yB) {\n const t = yA\n yA = yB\n yB = t\n }\n } else if (Math.abs(o[1]) > hh) return null\n const t0 = Math.max(tA, yA)\n const t1 = Math.min(tB, yB)\n if (t0 > t1 || t1 < 0 || !Number.isFinite(t0) || !Number.isFinite(t1)) return null\n const normalAt = (t: number, fromSide: boolean, sign: number): Vec3 => {\n if (fromSide) {\n const p = vec.madd(o, d, t)\n return vec.normalize([p[0], 0, p[2]], [1, 0, 0])\n }\n return [0, sign, 0]\n }\n const n0 = normalAt(t0, tA >= yA, d[1] > 0 ? -1 : 1)\n const n1 = normalAt(t1, tB <= yB, d[1] > 0 ? 1 : -1)\n return { t0, n0, t1, n1 }\n}\n\n/** Distance from a part-space point to the shape (0 inside). */\nexport const distanceToShape = (s: PartShape, p: Vec3): number => {\n if (s.kind === 'box') {\n const dx = Math.max(Math.abs(p[0]) - s.size[0] / 2, 0)\n const dy = Math.max(Math.abs(p[1]) - s.size[1] / 2, 0)\n const dz = Math.max(Math.abs(p[2]) - s.size[2] / 2, 0)\n return Math.hypot(dx, dy, dz)\n }\n if (s.kind === 'sphere') return Math.max(0, vec.length(p) - s.radius)\n const dr = Math.max(0, Math.hypot(p[0], p[2]) - s.radius)\n const dy = Math.max(0, Math.abs(p[1]) - s.height / 2)\n return Math.hypot(dr, dy)\n}\n\n/** Nearest point on the surface of a shape to a part-space point, with the outward normal. */\nexport const surfacePoint = (s: PartShape, p: Vec3): { point: Vec3; normal: Vec3 } => {\n if (s.kind === 'box') {\n const h: Vec3 = [s.size[0] / 2, s.size[1] / 2, s.size[2] / 2]\n const inside = Math.abs(p[0]) <= h[0] && Math.abs(p[1]) <= h[1] && Math.abs(p[2]) <= h[2]\n if (!inside) {\n const c: Vec3 = [Math.max(-h[0], Math.min(h[0], p[0])), Math.max(-h[1], Math.min(h[1], p[1])), Math.max(-h[2], Math.min(h[2], p[2]))]\n return { point: c, normal: vec.normalize(vec.sub(p, c)) }\n }\n let axis = 0\n let best = Infinity\n for (let i = 0; i < 3; i++) {\n const g = h[i] - Math.abs(p[i])\n if (g < best) {\n best = g\n axis = i\n }\n }\n const sign = p[axis] >= 0 ? 1 : -1\n const point: Vec3 = [p[0], p[1], p[2]]\n point[axis] = sign * h[axis]\n const normal: Vec3 = [0, 0, 0]\n normal[axis] = sign\n return { point, normal }\n }\n if (s.kind === 'sphere') {\n const n = vec.normalize(p)\n return { point: vec.scale(n, s.radius), normal: n }\n }\n const rho = Math.hypot(p[0], p[2])\n const hh = s.height / 2\n const inside = rho <= s.radius && Math.abs(p[1]) <= hh\n if (!inside) {\n const k = rho > s.radius ? s.radius / rho : 1\n const c: Vec3 = [p[0] * k, Math.max(-hh, Math.min(hh, p[1])), p[2] * k]\n return { point: c, normal: vec.normalize(vec.sub(p, c)) }\n }\n if (s.radius - rho < hh - Math.abs(p[1])) {\n const k = rho < EPS ? 0 : s.radius / rho\n const point: Vec3 = rho < EPS ? [s.radius, p[1], 0] : [p[0] * k, p[1], p[2] * k]\n return { point, normal: vec.normalize([point[0], 0, point[2]], [1, 0, 0]) }\n }\n const sign = p[1] >= 0 ? 1 : -1\n return { point: [p[0], sign * hh, p[2]], normal: [0, sign, 0] }\n}\n\n/** Axis-aligned bounds of a shape with a given centre and orientation. */\nexport const aabbOf = (s: PartShape, center: Vec3, q: Quat): { min: Vec3; max: Vec3 } => {\n let hx: number, hy: number, hz: number\n if (s.kind === 'sphere') {\n hx = hy = hz = s.radius\n } else {\n const m = quat.toMatrix(q)\n if (s.kind === 'box') {\n const a = s.size[0] / 2, b = s.size[1] / 2, c = s.size[2] / 2\n hx = Math.abs(m[0]) * a + Math.abs(m[1]) * b + Math.abs(m[2]) * c\n hy = Math.abs(m[3]) * a + Math.abs(m[4]) * b + Math.abs(m[5]) * c\n hz = Math.abs(m[6]) * a + Math.abs(m[7]) * b + Math.abs(m[8]) * c\n } else {\n const ax = [m[1], m[4], m[7]]\n const hh = s.height / 2\n const e = (i: number) => s.radius * Math.sqrt(Math.max(0, 1 - ax[i] * ax[i])) + hh * Math.abs(ax[i])\n hx = e(0)\n hy = e(1)\n hz = e(2)\n }\n }\n return { min: [center[0] - hx, center[1] - hy, center[2] - hz], max: [center[0] + hx, center[1] + hy, center[2] + hz] }\n}\n\n/** Seeded generator (mulberry32). The state is a single int32, so it round-trips through JSON. */\nexport interface Rng {\n next(): number\n state(): number\n set(state: number): void\n}\n\nexport const createRng = (seed: number): Rng => {\n let s = seed | 0\n return {\n next() {\n s = (s + 0x6d2b79f5) | 0\n let t = Math.imul(s ^ (s >>> 15), 1 | s)\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n },\n state: () => s,\n set(v) {\n s = v | 0\n },\n }\n}\n","import { quat } from './math'\nimport type { Fragment, FractureStyle, Quat, Vec3 } from './types'\n\n/** A fragment in the part's local space (centre, size in the fragment's own axes, orientation relative to the part). */\nexport interface PlannedFragment {\n center: Vec3\n size: Vec3\n q: Quat\n shape: Fragment['shape']\n /** Share of the part's mass (unnormalised). */\n weight: number\n}\n\nexport interface PlanInput {\n style: FractureStyle\n /** Bounding box dimensions in part axes. */\n dims: Vec3\n thickness: number\n /** Index 0..2 of the grain axis, if any. */\n grain?: number\n /** Impact point in part space. */\n hit: Vec3\n fragmentSize: [number, number]\n maxFragments: number\n rnd: () => number\n}\n\ninterface Box {\n c: Vec3\n s: Vec3\n}\n\n/** Split a box into `count` pieces by cutting the largest piece along its longest allowed axis. */\nconst bsp = (root: Box, count: number, axes: number[], rnd: () => number): Box[] => {\n const pieces: Box[] = [root]\n const vol = (b: Box) => axes.reduce((v, a) => v * b.s[a], 1)\n while (pieces.length < count) {\n let bi = 0\n for (let i = 1; i < pieces.length; i++) if (vol(pieces[i]) > vol(pieces[bi])) bi = i\n const b = pieces[bi]\n let ax = axes[0]\n for (const a of axes) if (b.s[a] > b.s[ax]) ax = a\n if (b.s[ax] < 1e-4) break\n const r = 0.3 + 0.4 * rnd()\n const l1 = b.s[ax] * r\n const l2 = b.s[ax] - l1\n const c1: Vec3 = [b.c[0], b.c[1], b.c[2]]\n const c2: Vec3 = [b.c[0], b.c[1], b.c[2]]\n c1[ax] = b.c[ax] - b.s[ax] / 2 + l1 / 2\n c2[ax] = b.c[ax] + b.s[ax] / 2 - l2 / 2\n const s1: Vec3 = [b.s[0], b.s[1], b.s[2]]\n const s2: Vec3 = [b.s[0], b.s[1], b.s[2]]\n s1[ax] = l1\n s2[ax] = l2\n pieces[bi] = { c: c1, s: s1 }\n pieces.push({ c: c2, s: s2 })\n }\n return pieces\n}\n\nconst parity = (p: [number, number, number]): number => {\n let inv = 0\n for (let i = 0; i < 3; i++) for (let j = i + 1; j < 3; j++) if (p[i] > p[j]) inv++\n return inv % 2 === 0 ? 1 : -1\n}\n\n/** Orientation whose x, y, z axes are the part axes `ax`, `ay`, `az`, then rotated by `angle` around its own z. */\nconst frame = (ax: number, ay: number, az: number, angle = 0): Quat => {\n const e = (i: number): Vec3 => [i === 0 ? 1 : 0, i === 1 ? 1 : 0, i === 2 ? 1 : 0]\n const z = e(az)\n const sg = parity([ax, ay, az])\n const q = quat.fromColumns(e(ax), e(ay), [z[0] * sg, z[1] * sg, z[2] * sg])\n return angle === 0 ? q : quat.mul(q, quat.fromAxisAngle([0, 0, 1], angle))\n}\n\nconst clamp = (v: number, a: number, b: number) => Math.max(a, Math.min(b, v))\n\n/** Deterministic fragment layout for a failed part, in part space. */\nexport const planFragments = (inp: PlanInput): PlannedFragment[] => {\n const { style, dims, rnd, maxFragments } = inp\n const [fmin, fmax] = inp.fragmentSize\n const mean = (fmin + fmax) / 2\n const root: Box = { c: [0, 0, 0], s: [dims[0], dims[1], dims[2]] }\n const idq = quat.identity()\n const out: PlannedFragment[] = []\n const sorted = [0, 1, 2].sort((a, b) => dims[a] - dims[b])\n const t = sorted[0]\n const [u, v] = [sorted[1], sorted[2]].sort((a, b) => a - b)\n\n if (style === 'snap') {\n const n = Math.min(maxFragments, 2 + Math.floor(rnd() * 3))\n for (const b of bsp(root, n, [0, 1, 2], rnd)) out.push({ center: b.c, size: b.s, q: idq, shape: 'slab', weight: b.s[0] * b.s[1] * b.s[2] })\n return out\n }\n if (style === 'crumble' || style === 'none') {\n const n = clamp(Math.ceil((dims[0] * dims[1] * dims[2]) / (mean * mean * mean)), 4, maxFragments)\n for (const b of bsp(root, n, [0, 1, 2], rnd)) out.push({ center: b.c, size: b.s, q: idq, shape: 'chunk', weight: b.s[0] * b.s[1] * b.s[2] })\n return out\n }\n if (style === 'splinter') {\n const g = inp.grain ?? [0, 1, 2].sort((a, b) => dims[b] - dims[a])[0]\n const [a, b] = [0, 1, 2].filter((i) => i !== g)\n const w = Math.max(fmin * 1.5, 0.01)\n const c = clamp(Math.round((dims[a] * dims[b]) / (w * w)), 3, Math.max(3, Math.floor(maxFragments / 2)))\n const maxLen = fmax * 4\n const cells = bsp(root, c, [a, b], rnd)\n const pieces: Box[] = []\n for (const cell of cells) {\n let list = [cell]\n const extra = rnd() < 0.4 ? 1 : 0\n const k = Math.max(1, Math.ceil(dims[g] / maxLen)) + extra\n list = bsp(cell, k, [g], rnd)\n for (const p of list) pieces.push(p)\n }\n for (const p of pieces.slice(0, maxFragments)) {\n out.push({ center: p.c, size: [p.s[g], p.s[a], p.s[b]], q: frame(g, a, b), shape: 'splinter', weight: p.s[0] * p.s[1] * p.s[2] })\n }\n return out\n }\n if (style === 'tear') {\n const n = clamp(Math.round((dims[u] * dims[v]) / (mean * mean)), 3, maxFragments)\n const th = Math.min(inp.thickness, dims[t])\n for (const b of bsp(root, n, [u, v], rnd)) {\n out.push({ center: [b.c[0], b.c[1], b.c[2]], size: [b.s[u], b.s[v], th], q: frame(u, v, t), shape: 'scrap', weight: b.s[u] * b.s[v] })\n }\n return out\n }\n // shatter: thin shards radiating from the impact\n const th = Math.min(inp.thickness, dims[t])\n const Hu = dims[u] / 2, Hv = dims[v] / 2\n const hu = clamp(inp.hit[u], -Hu * 0.95, Hu * 0.95)\n const hv = clamp(inp.hit[v], -Hv * 0.95, Hv * 0.95)\n const R = Math.max(Math.hypot(Hu + Math.abs(hu), Hv + Math.abs(hv)), 0.02)\n const n = clamp(Math.round((dims[u] * dims[v]) / (mean * mean)), 6, maxFragments)\n const sectors = clamp(Math.round(Math.sqrt(n * 1.6)), 5, 10)\n const rings = Math.max(1, Math.ceil(n / sectors))\n const radii: number[] = []\n for (let k = 0; k <= rings; k++) radii.push(R * Math.pow(k / rings, 1.3))\n const cap = fmax * 1.5\n for (let j = 0; j < sectors && out.length < maxFragments; j++) {\n const theta = (j + (rnd() - 0.5) * 0.4) * ((Math.PI * 2) / sectors)\n for (let k = 0; k < rings && out.length < maxFragments; k++) {\n const rm = (radii[k] + radii[k + 1]) / 2\n const cu = hu + rm * Math.cos(theta)\n const cv = hv + rm * Math.sin(theta)\n if (Math.abs(cu) > Hu + 0.01 || Math.abs(cv) > Hv + 0.01) continue\n const radial = clamp(radii[k + 1] - radii[k], 0.01, cap)\n const tang = clamp(radii[k + 1] * ((Math.PI * 2) / sectors) * 0.9, 0.01, cap)\n const c: Vec3 = [0, 0, 0]\n c[u] = clamp(cu, -Hu * 0.98, Hu * 0.98)\n c[v] = clamp(cv, -Hv * 0.98, Hv * 0.98)\n c[t] = 0\n out.push({ center: c, size: [radial, tang, th], q: frame(u, v, t, theta), shape: 'shard', weight: radial * tang })\n }\n }\n if (out.length === 0) out.push({ center: [0, 0, 0], size: [dims[u], dims[v], th], q: frame(u, v, t), shape: 'shard', weight: 1 })\n return out\n}\n","import { quat, rotateVec } from './math'\nimport type { FragmentMark, PartUnits, Quat, Vec3 } from './types'\n\n/** One masonry unit (or panel) cut out of a wall, in the part's own axes. */\nexport interface UnitCell {\n center: Vec3\n size: Vec3\n}\n\n/** The two axes a wall spreads along: height is local y unless the part is thin along y (a slab), then x and z. */\nexport const planeAxes = (thin: number): [number, number] => (thin === 1 ? [0, 2] : [thin === 0 ? 2 : 0, 1])\n\n/**\n * Every unit of the wall laid in `bond`: rows along the plane's second axis, running bond shifts odd rows by half a unit, edge units are cut to\n * the wall. More than `cap` units are merged into bigger ones (the same bond) so a whole wall stays a drawable number of fragments.\n */\nexport const unitGrid = (dims: Vec3, thin: number, units: Pick<PartUnits, 'size' | 'bond'>, cap: number): UnitCell[] => {\n const [u, v] = planeAxes(thin)\n let unitU = Math.min(units.size[0], dims[u]), unitV = Math.min(units.size[1], dims[v])\n const rowsFor = (h: number): number => Math.ceil(dims[v] / h - 1e-9)\n const colsFor = (w: number): number => Math.ceil(dims[u] / w - 1e-9) + (units.bond === 'running' ? 1 : 0)\n const merge = Math.ceil(Math.sqrt((rowsFor(unitV) * colsFor(unitU)) / cap))\n if (merge > 1) {\n unitU = Math.min(unitU * merge, dims[u])\n unitV = Math.min(unitV * merge, dims[v])\n }\n const cells: UnitCell[] = []\n for (let row = 0; row < rowsFor(unitV); row++) {\n const v0 = -dims[v] / 2 + row * unitV, v1 = Math.min(v0 + unitV, dims[v] / 2)\n const shift = units.bond === 'running' && row % 2 === 1 ? unitU / 2 : 0\n for (let col = 0; col < colsFor(unitU); col++) {\n const u0 = Math.max(-dims[u] / 2 + col * unitU - shift, -dims[u] / 2), u1 = Math.min(-dims[u] / 2 + (col + 1) * unitU - shift, dims[u] / 2)\n if (u1 - u0 < 0.01) continue\n const center: Vec3 = [0, 0, 0], size: Vec3 = [0, 0, 0]\n center[u] = (u0 + u1) / 2\n center[v] = (v0 + v1) / 2\n size[u] = u1 - u0\n size[v] = v1 - v0\n size[thin] = dims[thin]\n cells.push({ center, size })\n }\n }\n return cells\n}\n\nconst planeDistance = (cell: UnitCell, thin: number, point: Vec3): number => {\n const [u, v] = planeAxes(thin)\n const du = cell.center[u] - point[u], dv = cell.center[v] - point[v]\n return Math.sqrt(du * du + dv * dv)\n}\n\n/** Units whose centre is within `radius` of `point` (part-local) in the wall plane; at least the nearest one. */\nexport const cellsWithin = (cells: readonly UnitCell[], thin: number, point: Vec3, radius: number): UnitCell[] => {\n const inside = cells.filter((c) => planeDistance(c, thin, point) <= radius)\n if (inside.length > 0 || cells.length === 0) return inside\n return [cells.reduce((best, c) => (planeDistance(c, thin, point) < planeDistance(best, thin, point) ? c : best))]\n}\n\nexport const cellsOutside = (cells: readonly UnitCell[], thin: number, point: Vec3, radius: number): UnitCell[] => cells.filter((c) => planeDistance(c, thin, point) > radius)\n\n/** A hole in the part's own axes. */\nexport interface LocalHole {\n point: Vec3\n normal: Vec3\n diameter: number\n}\n\nexport const MAX_MARKS_PER_FRAGMENT = 12\n\n/** The holes that fall inside a fragment box (`rotation` is the fragment's orientation in the part), in the fragment's own axes. */\nexport const marksInBox = (center: Vec3, size: Vec3, rotation: Quat | undefined, holes: readonly LocalHole[]): FragmentMark[] => {\n const inverse = rotation ? quat.conjugate(rotation) : undefined\n const marks: FragmentMark[] = []\n for (const hole of holes) {\n const offset: Vec3 = [hole.point[0] - center[0], hole.point[1] - center[1], hole.point[2] - center[2]]\n const point = inverse ? rotateVec(inverse, offset) : offset\n const inside = point.every((value, k) => Math.abs(value) <= size[k]! / 2 + hole.diameter / 2)\n if (!inside) continue\n marks.push({ point, normal: inverse ? rotateVec(inverse, hole.normal) : hole.normal, diameter: hole.diameter })\n if (marks.length >= MAX_MARKS_PER_FRAGMENT) break\n }\n return marks\n}\n","import type { MaterialDef, SurfaceLayer, Vec3 } from './types'\n\n/** A surface layer with its material resolved; `energy` is what a bullet spends crossing one face's worth of it, in joules. */\nexport interface LayerRT {\n index: number\n def: SurfaceLayer\n mat: MaterialDef\n energy: number\n}\n\n/** `[layer, face (+1 or -1), x, y, z, radius]`: a patch of a layer that came off, in object-local space. Saved with the part. */\nexport type Spall = readonly [number, number, number, number, number, number]\n\nexport const MAX_SPALLS = 64\n\n/** Index of the smallest dimension (the first one on a tie): the axis a wall is thin along. */\nexport const thinAxisOf = (dims: Vec3): number => (dims[0] <= dims[1] && dims[0] <= dims[2] ? 0 : dims[1] <= dims[2] ? 1 : 2)\n\nexport const resolveLayer = (def: SurfaceLayer, index: number, mat: MaterialDef): LayerRT => ({ index, def, mat, energy: mat.penetration * def.thickness * 1000 })\n\nconst onFace = (layer: LayerRT, face: number): boolean => layer.def.faces === 'both' || layer.def.faces === (face > 0 ? '+' : '-')\n\nconst isSpalled = (spalls: readonly Spall[] | undefined, layer: number, face: number, point: Vec3): boolean => {\n for (const s of spalls ?? []) {\n if (s[0] !== layer || s[1] !== face) continue\n const dx = s[2] - point[0], dy = s[3] - point[1], dz = s[4] - point[2]\n if (dx * dx + dy * dy + dz * dz <= s[5] * s[5]) return true\n }\n return false\n}\n\n/** The outermost layer still on `face` at `point` (layers are listed outermost first). */\nexport const outerLayer = (layers: readonly LayerRT[], spalls: readonly Spall[] | undefined, face: number, point: Vec3): LayerRT | undefined =>\n layers.find((l) => onFace(l, face) && !isSpalled(spalls, l.index, face, point))\n\n/** Joules a bullet spends crossing every layer still on `face` at `point`. */\nexport const layersEnergy = (layers: readonly LayerRT[], spalls: readonly Spall[] | undefined, face: number, point: Vec3): number => {\n let sum = 0\n for (const l of layers) if (onFace(l, face) && !isSpalled(spalls, l.index, face, point)) sum += l.energy\n return sum\n}\n\n/** Metres of layer a ray crosses on one face (full thickness, before obliquity). */\nexport const layersThickness = (layers: readonly LayerRT[], face: number): number => {\n let sum = 0\n for (const l of layers) if (onFace(l, face)) sum += l.def.thickness\n return sum\n}\n","import type { Vec3 } from './types'\n\n/** A bar as two end points. */\nexport type Bar = [Vec3, Vec3]\n\nconst COVER = 0.03\nconst MAX_BARS_PER_DIRECTION = 24\nconst MAX_MEMBER_BARS_PER_SIDE = 6\nconst STEEL_DENSITY = 7850\n\n/** Positions centred on 0 with exact `spacing`, as many as fit inside `length - 2 * cover` (at least two, at most `cap`). */\nconst spread = (length: number, cover: number, spacing: number, cap: number): number[] => {\n const room = Math.max(0, length - 2 * cover)\n const count = Math.min(cap, Math.max(2, Math.floor(room / spacing) + 1))\n const step = count > 1 && room / (count - 1) < spacing ? room / (count - 1) : spacing\n return Array.from({ length: count }, (_, i) => (i - (count - 1) / 2) * step)\n}\n\nconst bar = (axis: number, along: number, fixed: Array<[number, number]>): Bar => {\n const a: Vec3 = [0, 0, 0], b: Vec3 = [0, 0, 0]\n for (const [index, value] of fixed) {\n a[index] = value\n b[index] = value\n }\n a[axis] = -along\n b[axis] = along\n return [a, b]\n}\n\n/** Long members (columns, beams): two smaller dimensions close to each other and a much longer third one. */\nexport const isMember = (dims: Vec3): boolean => {\n const [a = 0, b = 0, c = 0] = [...dims].sort((x, y) => x - y)\n return b / a < 3 && c / b >= 3\n}\n\n/** Bars of a long member's perimeter that lie on one face of width `width` (the face's row of the cage). */\nexport const memberBarCount = (width: number, spacing: number): number => spread(width, COVER, spacing, MAX_MEMBER_BARS_PER_SIDE).length\n\n/**\n * Rebar of a box in the part's own axes. Plates (walls, slabs) get a grid along each of the two large axes at mid thickness; long members get\n * bars along their length at the perimeter of the section. `thin` is the axis the part is thinnest along.\n */\nexport const rebarBars = (dims: Vec3, thin: number, spacing: number): Bar[] => {\n const out: Bar[] = []\n if (isMember(dims)) {\n const long = dims.indexOf(Math.max(...dims))\n const [u = 0, v = 0] = [0, 1, 2].filter((i) => i !== long)\n const us = spread(dims[u], COVER, spacing, MAX_MEMBER_BARS_PER_SIDE)\n const vs = spread(dims[v], COVER, spacing, MAX_MEMBER_BARS_PER_SIDE)\n us.forEach((x, i) => vs.forEach((y, j) => {\n if (i === 0 || j === 0 || i === us.length - 1 || j === vs.length - 1) out.push(bar(long, dims[long] / 2 - 0.02, [[u, x], [v, y]]))\n }))\n return out\n }\n const [u = 0, v = 0] = [0, 1, 2].filter((i) => i !== thin)\n for (const y of spread(dims[v], COVER, spacing, MAX_BARS_PER_DIRECTION)) out.push(bar(u, dims[u] / 2 - 0.02, [[v, y], [thin, 0]]))\n for (const x of spread(dims[u], COVER, spacing, MAX_BARS_PER_DIRECTION)) out.push(bar(v, dims[v] / 2 - 0.02, [[u, x], [thin, 0]]))\n return out\n}\n\n/** The part of each bar that lies within `radius` of `center` in the plane of axes `u` and `v` (bars that miss the disc are dropped). */\nexport const clipBarsToDisc = (bars: readonly Bar[], u: number, v: number, center: [number, number], radius: number): Bar[] => {\n const out: Bar[] = []\n for (const [a, b] of bars) {\n const axis = a[u] !== b[u] ? u : v\n const other = axis === u ? v : u\n const off = a[other] - center[other === u ? 0 : 1]\n if (Math.abs(off) >= radius) continue\n const half = Math.sqrt(radius * radius - off * off)\n const mid = center[axis === u ? 0 : 1]\n const lo = Math.max(Math.min(a[axis], b[axis]), mid - half), hi = Math.min(Math.max(a[axis], b[axis]), mid + half)\n if (hi - lo < 1e-6) continue\n const p: Vec3 = [a[0], a[1], a[2]], q: Vec3 = [b[0], b[1], b[2]]\n p[axis] = lo\n q[axis] = hi\n out.push([p, q])\n }\n return out\n}\n\n/**\n * How many bars of `rebarBars` run up the part (along its vertical axis), counted without the cap that keeps the drawn cage light: the steel that holds a\n * wall or a column in tension is all the bars its spacing puts in, not the 24 that are drawn. A long member lying on its side has none.\n */\nexport const verticalBarCount = (dims: Vec3, thin: number, spacing: number): number => {\n if (isMember(dims)) {\n if (dims.indexOf(Math.max(...dims)) !== 1) return 0\n const us = spread(dims[0], COVER, spacing, Infinity).length, vs = spread(dims[2], COVER, spacing, Infinity).length\n return 2 * us + 2 * Math.max(0, vs - 2)\n }\n const [u = 0, v = 0] = [0, 1, 2].filter((i) => i !== thin)\n if (u === 1) return spread(dims[v], COVER, spacing, Infinity).length\n if (v === 1) return spread(dims[u], COVER, spacing, Infinity).length\n return 0\n}\n\n/** Steel mass in kg of bars of `diameter` metres. */\nexport const rebarMass = (bars: readonly Bar[], diameter: number, density = STEEL_DENSITY): number => {\n let length = 0\n for (const [a, b] of bars) length += Math.abs(a[0] - b[0]) + Math.abs(a[1] - b[1]) + Math.abs(a[2] - b[2])\n return Math.PI * (diameter / 2) * (diameter / 2) * length * density\n}\n","import { planeAxes } from './breach'\nimport { thinAxisOf } from './layers'\nimport { quat, quatFromEuler, rotateVec, shapeDims } from './math'\nimport { isMember, memberBarCount } from './rebar'\nimport type { FlexureOptions, MasonryOptions, MaterialDef, PartSpec, StructureRole, Vec3 } from './types'\n\n/**\n * Real structural engineering of beams, slabs, walls and pillars: bending (the tension face cracks, the steel carries the pull, a member without\n * steel snaps) and crushing of slender bearing walls. Pure formulas in SI units (N, m, Pa, J); the world calls them with the parts' geometry.\n */\n\n/** Standard gravity, m/s². A physical constant. */\nexport const GRAVITY = 9.81\nconst MPA = 1e6\n\nexport const FLEXURE_DEFAULTS: Required<FlexureOptions> = {\n enabled: true,\n roles: ['beam', 'slab', 'roof', 'stair'],\n scope: 'rebar',\n crackFactor: 1.5,\n rebarYieldMPa: 500,\n cover: 0.03,\n neutralAxisLimit: 0.45,\n failRotationDeg: 10,\n loadFactor: 0.64,\n massFactor: 0.5,\n tntJoules: 4.184e6,\n impulse: 200,\n reflection: 2,\n reflectionNear: 4,\n nearScaled: 0.5,\n}\n\nexport const MASONRY_DEFAULTS: Required<MasonryOptions> = { minEccentricity: 0.05, slendernessLimit: 40, concreteFactor: 0.85 }\n\nexport const resolveFlexure = (o?: FlexureOptions): Required<FlexureOptions> => ({ ...FLEXURE_DEFAULTS, ...definedOf(o) })\nexport const resolveMasonry = (o?: MasonryOptions): Required<MasonryOptions> => ({ ...MASONRY_DEFAULTS, ...definedOf(o) })\nconst definedOf = <T extends object>(o?: T): Partial<T> => Object.fromEntries(Object.entries(o ?? {}).filter(([, v]) => v !== undefined)) as Partial<T>\n\n/** Bar diameter assumed for a `structure.rebar` ratio (it only sets where the bar centre is): 10 mm. */\nconst RATIO_BAR = 0.01\n\n/** Cracking moment of a rectangular section in N m: `alpha * fct * b * h^2 / 6` (NBR 6118 17.3.1). */\nexport const crackingMoment = (tensileMPa: number, b: number, h: number, alpha = FLEXURE_DEFAULTS.crackFactor): number => alpha * tensileMPa * MPA * (b * h * h) / 6\n\n/**\n * Moment the tension steel gives in N m, with the rectangular stress block of NBR 6118 17.2.2 (`0.85 * fck` over `0.8 x`): the steel pulls\n * `T = As * fy`, the block takes it at depth `x = T / (0.68 * fck * b)`, and `M = T * (d - 0.4 x)`. Past the ductility limit `x = limit * d` the\n * concrete would crush first, so the steel beyond what balances the block is taken as paired with compression steel (double reinforcement, NBR 6118\n * 17.2.4): it adds `T2 * (d - d')`, `d'` being the cover to the compression bars.\n */\nexport const steelMoment = (\n area: number, yieldMPa: number, d: number, b: number, compressiveMPa: number, options: Pick<FlexureOptions, 'neutralAxisLimit' | 'cover'> = {},\n): number => {\n if (area <= 0 || d <= 0 || b <= 0) return 0\n const T = area * yieldMPa * MPA\n const block = 0.68 * compressiveMPa * MPA * b\n const x = T / block\n const xl = (options.neutralAxisLimit ?? FLEXURE_DEFAULTS.neutralAxisLimit) * d\n if (x <= xl) return T * (d - 0.4 * x)\n const top = Math.min(d / 2, (options.cover ?? FLEXURE_DEFAULTS.cover) + RATIO_BAR / 2)\n return block * xl * (d - 0.4 * xl) + (T - block * xl) * (d - top)\n}\n\n/** Stiffness in N/m of a simply supported span under uniform load, at mid-span: `384 E I / (5 L^3)`. */\nexport const spanStiffness = (EI: number, span: number): number => (384 * EI) / (5 * span ** 3)\n\n/**\n * Strain energy in J of the equivalent one-degree-of-freedom system of a span whose peak moment is `M` (uniform load: `R = 8 M / L`): `KL * R^2 / (2 k)`.\n */\nexport const elasticEnergy = (moment: number, span: number, EI: number, loadFactor = FLEXURE_DEFAULTS.loadFactor): number => {\n const R = (8 * moment) / span\n return (loadFactor * R * R) / (2 * spanStiffness(EI, span))\n}\n\n/** Inverse of `elasticEnergy`: the peak moment in N m a span reaches when it takes `energy` J elastically. */\nexport const momentOfEnergy = (energy: number, span: number, EI: number, loadFactor = FLEXURE_DEFAULTS.loadFactor): number =>\n (span / 8) * Math.sqrt((2 * Math.max(0, energy) * spanStiffness(EI, span)) / loadFactor)\n\n/** Kinetic energy in J an impulse `I` (N s) gives the equivalent system of a span of mass `m` (kg): `(KL I)^2 / (2 KM m)` (Biggs 1964). */\nexport const impulseEnergy = (impulse: number, mass: number, options: Pick<FlexureOptions, 'loadFactor' | 'massFactor'> = {}): number => {\n const KL = options.loadFactor ?? FLEXURE_DEFAULTS.loadFactor\n const KM = options.massFactor ?? FLEXURE_DEFAULTS.massFactor\n return mass > 0 ? (KL * impulse) ** 2 / (2 * KM * mass) : 0\n}\n\n/**\n * Reflected impulse per area in Pa s of a charge of `tnt` kg at `distance` m on a face that looks at it. The incident impulse is Sadovsky's\n * `impulse * W^(2/3) / R`; the face reflects it by `reflection + reflectionNear / Z` (`Z = R / W^(1/3)`, m/kg^(1/3)): about 2 far away, 4 to 6 at\n * one or two metres per cube root kilogram, as the reflected-impulse curves of UFC 3-340-02 (fig. 2-7) rise towards the charge. Below `nearScaled`\n * the distance is held at that scaled distance.\n */\nexport const blastImpulse = (\n tnt: number, distance: number, options: Pick<FlexureOptions, 'impulse' | 'reflection' | 'reflectionNear' | 'nearScaled'> = {},\n): number => {\n if (tnt <= 0) return 0\n const o = { ...FLEXURE_DEFAULTS, ...definedOf(options) }\n const cube = Math.cbrt(tnt)\n const r = Math.max(distance, o.nearScaled * cube)\n return (o.reflection + o.reflectionNear / (r / cube)) * ((o.impulse * cube * cube) / r)\n}\n\n/**\n * Share of the compressive strength a wall or pillar of height `h` and thickness `t` keeps: the unavoidable eccentricity `(1 - 2 e)` times the\n * slenderness reduction `1 - (h / t / limit)^3` (NBR 16868-1), never below 0.\n */\nexport const slendernessFactor = (h: number, t: number, options: MasonryOptions = {}): number => {\n const o = resolveMasonry(options)\n const lambda = h / Math.max(t, 1e-3)\n return Math.max(0, (1 - 2 * o.minEccentricity) * (1 - (lambda / o.slendernessLimit) ** 3))\n}\n\n/** The part is reinforced for bending: a `reinforcement` cage or a `structure.rebar` ratio. */\nexport const isReinforced = (part: PartSpec): boolean => !!part.reinforcement || (part.structure?.rebar?.ratio ?? 0) > 0\n\n/** The part's material is slender masonry or plain concrete (`strength.slender`, default: tagged `masonry` and not reinforced). */\nexport const isSlender = (part: PartSpec, material: MaterialDef): boolean =>\n material.strength?.slender ?? (!!material.tags?.includes('masonry') && !isReinforced(part))\n\n/** The part takes part in the bending model. */\nexport const isFlexural = (part: PartSpec, material: MaterialDef, options: Required<FlexureOptions>): boolean =>\n options.enabled && material.strength?.tensileMPa !== undefined && !!part.structure && options.roles.includes(part.structure.role) &&\n (part.structure.rebar !== undefined || options.scope === 'all' || (options.scope === 'reinforced' && !!part.reinforcement))\n\n/** A bending section: width `b`, depth `h` (along the bending), in metres. */\nexport interface BendSection {\n b: number\n h: number\n}\n\n/** Tension steel of a section: area in m², effective depth in m, yield in MPa. */\nexport interface TensionSteel {\n area: number\n d: number\n yieldMPa: number\n}\n\n/**\n * Tension steel of the part for a section of width `b` and depth `h`: from `structure.rebar` (`ratio * b * d`), else from the `reinforcement` cage\n * (a plate's grid: one bar every `spacing` across `b`; a long member: the bars of the perimeter on the tension face). Zero for plain concrete.\n */\nexport const tensionSteel = (part: PartSpec, dims: Vec3, section: BendSection, options: Required<FlexureOptions>): TensionSteel => {\n const rebar = part.structure?.rebar\n const cage = part.reinforcement\n const bar = rebar ? RATIO_BAR : cage?.diameter ?? RATIO_BAR\n const d = Math.max(0.01, section.h - (rebar?.cover ?? options.cover) - bar / 2)\n const yieldMPa = rebar?.yieldMPa ?? options.rebarYieldMPa\n if (rebar && rebar.ratio > 0) return { area: rebar.ratio * section.b * d, d, yieldMPa }\n if (!cage) return { area: 0, d, yieldMPa }\n const one = (Math.PI * cage.diameter * cage.diameter) / 4\n const count = isMember(dims) ? memberBarCount(section.b, cage.spacing) : section.b / cage.spacing\n return { area: one * count, d, yieldMPa }\n}\n\n/**\n * Moments of a section in N m: `cracking` (the concrete's), `steel` (what the tension steel gives once the concrete has cracked; 0 for plain\n * concrete), `ultimate` (what the uncracked section holds: the larger of the two) and `reinforced` (it has steel: when it fails it hinges and its bars\n * keep it in one piece; without steel it snaps).\n */\nexport interface SectionMoments {\n cracking: number\n steel: number\n ultimate: number\n reinforced: boolean\n}\n\nexport const sectionMoments = (material: MaterialDef, section: BendSection, steel: TensionSteel, options: Required<FlexureOptions>): SectionMoments => {\n const s = material.strength!\n const cracking = crackingMoment(s.tensileMPa ?? 0, section.b, section.h, options.crackFactor)\n const steelM = steelMoment(steel.area, steel.yieldMPa, steel.d, section.b, s.compressiveMPa, options)\n return { cracking, steel: steelM, ultimate: Math.max(cracking, steelM), reinforced: steelM > 0 }\n}\n\n/** Static moment in N m at mid-span of a span `L` under a uniform load `w` (N/m): `w L^2 / 8`. */\nexport const spanMoment = (w: number, span: number): number => (w * span * span) / 8\n\n/**\n * How a box part bends, in its own axes. A long member (beam) spans along `long` and bends about either cross axis; a plate (slab) spans in the plane\n * of `plane` and bends across its thickness `thin`. `gravity` is the axis the weight bends it along (the local axis closest to the vertical among those\n * it can bend along, when it is within 45 degrees of it; -1 for a plate standing on edge). `up` is the world vertical in the part's axes.\n */\nexport interface BendGeometry {\n dims: Vec3\n member: boolean\n /** Axes the span is measured along: `[long]` for a member, the two plane axes for a plate. */\n spanAxes: number[]\n /** Axes the part can bend along (its depth): the two cross axes of a member, the thickness of a plate. */\n depthAxes: number[]\n gravity: number\n up: Vec3\n}\n\nexport const bendGeometry = (part: PartSpec): BendGeometry => {\n const dims = shapeDims(part.shape)\n const member = isMember(dims)\n const q = quatFromEuler(...(part.rotation ?? [0, 0, 0]))\n const up = rotateVec(quat.conjugate(q), [0, 1, 0])\n let spanAxes: number[]\n let depthAxes: number[]\n if (member) {\n const long = dims.indexOf(Math.max(...dims))\n spanAxes = [long]\n depthAxes = [0, 1, 2].filter((i) => i !== long)\n } else {\n const thin = thinAxisOf(dims)\n spanAxes = [...planeAxes(thin)]\n depthAxes = [thin]\n }\n let gravity = -1\n for (const a of depthAxes) if (Math.abs(up[a]) > Math.SQRT1_2 && (gravity < 0 || Math.abs(up[a]) > Math.abs(up[gravity]))) gravity = a\n return { dims, member, spanAxes, depthAxes, gravity, up }\n}\n\n/** Width of the section that bends along `axis`: the other cross axis of a member, a strip of 1 m of a plate. */\nexport const sectionWidth = (g: BendGeometry, axis: number): number => (g.member ? g.dims[g.depthAxes.find((a) => a !== axis) ?? axis] : 1)\n\n/**\n * Uniform load in N per metre of span of the bending section when the part carries `load` kg: per metre of a member's length, per metre-wide strip\n * of a plate (its load per square metre times 1 m).\n */\nexport const lineLoad = (g: BendGeometry, load: number): number => {\n const area = g.member ? g.dims[g.spanAxes[0]!] : g.dims[g.spanAxes[0]!] * g.dims[g.spanAxes[1]!]\n return (load * GRAVITY) / Math.max(area, 1e-6)\n}\n\n/**\n * Span in metres from the regions the part rests on (`contacts`: boxes `[min, max]` in the part's axes): twice the farthest any point of the part\n * is from its nearest support, measured along the span axes as the largest of the per-axis gaps. Two walls 4 m apart give 4 m, four columns at the\n * corners of a 5 x 4 m panel give 5 m (the long way), a cantilever of 1.5 m gives 3 m (the same moment, `w c^2 / 2`). 0 without contacts.\n */\nexport const spanOf = (g: BendGeometry, contacts: ReadonlyArray<readonly [Vec3, Vec3]>, samples = 9): number => {\n if (contacts.length === 0) return 0\n const axes = g.spanAxes\n const steps = (a: number) => Array.from({ length: samples }, (_, i) => (i / (samples - 1) - 0.5) * g.dims[a])\n const us = steps(axes[0]!)\n const vs = axes.length > 1 ? steps(axes[1]!) : [0]\n let far = 0\n for (const u of us) for (const v of vs) {\n let near = Infinity\n for (const [lo, hi] of contacts) {\n let gap = 0\n const x = [u, v]\n axes.forEach((a, k) => (gap = Math.max(gap, lo[a] - x[k]!, x[k]! - hi[a], 0)))\n if (gap < near) near = gap\n }\n if (near > far) far = near\n }\n return 2 * far\n}\n\n/** Roles that carry bending by default. */\nexport const FLEXURAL_ROLES: readonly StructureRole[] = FLEXURE_DEFAULTS.roles\n\nexport interface BearingWallOptions {\n /** Storeys the wall carries, the ground floor included. */\n storeys: number\n /** Height of one storey in metres. */\n storeyHeight: number\n /** Load each floor puts on one metre of wall, in N/m (dead and live load of the floor's share). */\n floorLoad: number\n /** Material of the wall (default the built-in `brick`): `strength.compressiveMPa` and `density`. */\n material: Pick<MaterialDef, 'density' | 'strength'>\n /** Load factor (1.4: NBR 8681, permanent and variable loads). */\n loadFactor?: number\n /** Material factor (2.0: NBR 16868-1, masonry). */\n materialFactor?: number\n /** Thinnest bearing wall in metres (0.14: NBR 16868-1). */\n minThickness?: number\n /** Thicknesses are rounded up to this many metres (0.01). */\n step?: number\n masonry?: MasonryOptions\n}\n\n/**\n * Thickness of a bearing masonry wall storey by storey, ground floor first, as a designer sizes it: the load from the top down (every floor plus the\n * walls above, times `loadFactor`) within `fk / materialFactor` times the slenderness factor of each storey's wall. `Infinity` when a storey cannot be\n * carried at any thickness (the wall's own weight per storey already uses up the strength).\n */\nexport const bearingWallThickness = (options: BearingWallOptions): number[] => {\n const gf = options.loadFactor ?? 1.4\n const gm = options.materialFactor ?? 2\n const min = options.minThickness ?? 0.14\n const step = options.step ?? 0.01\n const fd = ((options.material.strength?.compressiveMPa ?? 0) * MPA) / gm\n const own = options.material.density * GRAVITY * options.storeyHeight\n const out: number[] = []\n let above = 0\n for (let i = 0; i < options.storeys; i++) {\n const n = above + options.floorLoad\n let t = min\n for (let k = 0; k < 60; k++) {\n const room = fd * slendernessFactor(options.storeyHeight, t, options.masonry) - gf * own\n if (room <= 0) {\n // too slender (or too weak) at this thickness: try a thicker wall, give up past 20 m\n t *= 1.25\n if (t > 20) {\n t = Infinity\n break\n }\n continue\n }\n const next = Math.max(min, (gf * n) / room)\n if (Math.abs(next - t) < 1e-5) break\n t = next\n }\n t = Number.isFinite(t) ? Math.ceil(t / step - 1e-9) * step : Infinity\n out.push(t)\n above = n + own * (Number.isFinite(t) ? t : 0)\n }\n return out.reverse()\n}\n","[\n { \"id\": \"rock\", \"kind\": \"rock\", \"allowableKPa\": 3000, \"spt\": 50, \"elasticMPa\": 10000, \"poisson\": 0.2, \"pile\": { \"tipKPa\": 9000, \"skinKPa\": 500 } },\n { \"id\": \"rock_fractured\", \"kind\": \"rock\", \"allowableKPa\": 1500, \"spt\": 50, \"elasticMPa\": 2000, \"poisson\": 0.25, \"pile\": { \"tipKPa\": 4500, \"skinKPa\": 300 } },\n { \"id\": \"gravel_dense\", \"kind\": \"gravel\", \"allowableKPa\": 600, \"spt\": 40, \"elasticMPa\": 132, \"poisson\": 0.3 },\n { \"id\": \"gravel_loose\", \"kind\": \"gravel\", \"allowableKPa\": 300, \"spt\": 8, \"elasticMPa\": 26, \"poisson\": 0.3 },\n { \"id\": \"sand_very_dense\", \"kind\": \"sand\", \"allowableKPa\": 500, \"spt\": 45, \"elasticMPa\": 120, \"poisson\": 0.3 },\n { \"id\": \"sand_dense\", \"kind\": \"sand\", \"allowableKPa\": 400, \"spt\": 25, \"elasticMPa\": 68, \"poisson\": 0.3 },\n { \"id\": \"sand_medium\", \"kind\": \"sand\", \"allowableKPa\": 200, \"spt\": 12, \"elasticMPa\": 32, \"poisson\": 0.3 },\n { \"id\": \"sand_loose\", \"kind\": \"sand\", \"allowableKPa\": 50, \"spt\": 3, \"elasticMPa\": 8, \"poisson\": 0.3 },\n { \"id\": \"silt_hard\", \"kind\": \"silt\", \"allowableKPa\": 300, \"spt\": 25, \"elasticMPa\": 44, \"poisson\": 0.35 },\n { \"id\": \"silt_stiff\", \"kind\": \"silt\", \"allowableKPa\": 200, \"spt\": 15, \"elasticMPa\": 26, \"poisson\": 0.35 },\n { \"id\": \"silt_medium\", \"kind\": \"silt\", \"allowableKPa\": 100, \"spt\": 8, \"elasticMPa\": 14, \"poisson\": 0.35 },\n { \"id\": \"clay_hard\", \"kind\": \"clay\", \"allowableKPa\": 300, \"spt\": 25, \"elasticMPa\": 35, \"poisson\": 0.4 },\n { \"id\": \"clay_stiff\", \"kind\": \"clay\", \"allowableKPa\": 200, \"spt\": 15, \"elasticMPa\": 21, \"poisson\": 0.4 },\n { \"id\": \"clay_medium\", \"kind\": \"clay\", \"allowableKPa\": 100, \"spt\": 8, \"elasticMPa\": 11, \"poisson\": 0.4 },\n { \"id\": \"clay_soft\", \"kind\": \"clay\", \"allowableKPa\": 30, \"spt\": 3, \"elasticMPa\": 4.2, \"poisson\": 0.4 },\n { \"id\": \"clay_very_soft\", \"kind\": \"clay\", \"allowableKPa\": 15, \"spt\": 1, \"elasticMPa\": 1.4, \"poisson\": 0.4 }\n]\n","import soilsJson from './data/soils.json'\nimport type { PileSpec, SoilDef, SoilKind, SoilOptions, SoilProfile } from './types'\n\n/**\n * Soil and foundations. A footing bears on the soil under it as a bed of springs (the subgrade modulus of the elastic settlement of a rigid footing)\n * that give way at the soil's bearing capacity; a pile carries its load by end bearing and skin friction (Décourt-Quaresma) and gives way when the\n * load passes them. The whole object rests on those springs as a rigid body: it settles, leans with the out-of-plumb of the building and with its\n * own weight moving over as it leans (P-delta), and, when the springs cannot hold it, it keeps sinking and leaning until its centre of mass passes\n * the edge of its foundations and it tips over.\n */\n\n/** Built-in soil classes (data in `src/data/soils.json`): NBR 6122 basic pressures, SPT N, moduli from Teixeira & Godoy. */\nexport const SOILS: readonly SoilDef[] = soilsJson as SoilDef[]\n\nexport const SOIL_DEFAULTS = {\n safety: 3,\n pileSafety: 2,\n rigidity: 0.82,\n influence: 2,\n imperfection: 1 / 200,\n cells: 4,\n sinkRate: 0.05,\n tiltRate: 1.5,\n pileElasticGPa: 25,\n footingWidth: 0.6,\n} as const\n\nexport type ResolvedSoil = Required<Omit<SoilOptions, 'soils' | 'site'>> & { site?: string | SoilProfile; byId: Map<string, SoilDef> }\n\nexport const resolveSoil = (o: SoilOptions = {}): ResolvedSoil => {\n const byId = new Map(SOILS.map((s) => [s.id, s]))\n for (const s of o.soils ?? []) byId.set(s.id, s)\n const { soils: _soils, site, ...rest } = o\n return { ...SOIL_DEFAULTS, ...rest, ...(site !== undefined ? { site } : {}), byId }\n}\n\n/** A profile from a soil class id or a profile. */\nexport const profileOf = (soil: string | SoilProfile): SoilProfile => (typeof soil === 'string' ? { layers: [{ soil }] } : soil)\n\n/** The layers of a profile that lie between two depths (metres below the surface), with the thickness of each inside that range. */\nexport const layersBetween = (profile: SoilProfile, top: number, bottom: number, soils: ReadonlyMap<string, SoilDef>): Array<{ soil: SoilDef; thickness: number; top: number }> => {\n const out: Array<{ soil: SoilDef; thickness: number; top: number }> = []\n let z = 0\n const layers = profile.layers\n for (let i = 0; i < layers.length; i++) {\n const def = soils.get(layers[i].soil)\n if (!def) throw new Error(`unknown soil \"${layers[i].soil}\"`)\n const last = i === layers.length - 1\n const end = last ? Infinity : z + Math.max(0, layers[i].thickness ?? 0)\n const a = Math.max(z, top), b = Math.min(end, bottom)\n if (b > a) out.push({ soil: def, thickness: b - a, top: a })\n z = end\n if (z >= bottom) break\n }\n return out\n}\n\n/** The soil class at a depth (metres below the surface). */\nexport const soilAt = (profile: SoilProfile, depth: number, soils: ReadonlyMap<string, SoilDef>): SoilDef => {\n let z = 0\n for (let i = 0; i < profile.layers.length; i++) {\n const def = soils.get(profile.layers[i].soil)\n if (!def) throw new Error(`unknown soil \"${profile.layers[i].soil}\"`)\n z += Math.max(0, profile.layers[i].thickness ?? 0)\n if (i === profile.layers.length - 1 || depth < z) return def\n }\n throw new Error('a soil profile needs at least one layer')\n}\n\n/** The soil a footing of width `width` at `depth` bears on: the weakest allowable pressure and the mean modulus over `influence` widths below it. */\nexport const footingSoil = (profile: SoilProfile, depth: number, width: number, soils: ReadonlyMap<string, SoilDef>, influence: number = SOIL_DEFAULTS.influence) => {\n const zone = layersBetween(profile, depth, depth + Math.max(0.01, influence * width), soils)\n let allowable = Infinity, e = 0, nu = 0, t = 0\n for (const l of zone) {\n allowable = Math.min(allowable, l.soil.allowableKPa)\n e += l.soil.elasticMPa * l.thickness\n nu += l.soil.poisson * l.thickness\n t += l.thickness\n }\n if (t <= 0) {\n const l = soilAt(profile, depth, soils)\n return { allowableKPa: l.allowableKPa, elasticMPa: l.elasticMPa, poisson: l.poisson }\n }\n return { allowableKPa: allowable, elasticMPa: e / t, poisson: nu / t }\n}\n\n/** Décourt-Quaresma coefficient C of the end bearing in kPa per blow (clay 120, silt 200, sand and gravel 400). */\nconst DQ_C: Record<SoilKind, number> = { clay: 120, silt: 200, sand: 400, gravel: 400, rock: 400 }\n/** Décourt (1996) factors of a bored pile on the end bearing (alpha) and the skin friction (beta); a driven pile has 1 and 1. */\nconst BORED: Record<SoilKind, { alpha: number; beta: number }> = {\n clay: { alpha: 0.85, beta: 0.8 },\n silt: { alpha: 0.6, beta: 0.65 },\n sand: { alpha: 0.5, beta: 0.5 },\n gravel: { alpha: 0.5, beta: 0.5 },\n rock: { alpha: 1, beta: 1 },\n}\nconst clampN = (n: number) => Math.min(50, Math.max(3, n))\n\n/**\n * Ultimate resistance of one pile in newtons, by Décourt-Quaresma: end bearing `alpha C N A` at the tip and skin friction `beta 10 (N/3 + 1)` kPa\n * along the shaft in each layer (N limited to 3..50). Rock with `pile` resistances uses those instead. `top` is the depth of the pile head.\n */\nexport const pileCapacity = (profile: SoilProfile, pile: PileSpec, top: number, soils: ReadonlyMap<string, SoilDef>) => {\n const d = pile.diameter\n const area = (Math.PI * d * d) / 4\n const perimeter = Math.PI * d\n const driven = pile.method === 'driven'\n let skin = 0\n for (const l of layersBetween(profile, top, top + pile.length, soils)) {\n const f = driven ? 1 : BORED[l.soil.kind].beta\n const kPa = l.soil.pile?.skinKPa ?? f * 10 * (clampN(l.soil.spt) / 3 + 1)\n skin += kPa * 1000 * perimeter * l.thickness\n }\n const tipDepth = top + pile.length\n const tipSoil = soilAt(profile, tipDepth, soils)\n const alpha = driven ? 1 : BORED[tipSoil.kind].alpha\n const tipKPa = tipSoil.pile?.tipKPa ?? alpha * DQ_C[tipSoil.kind] * clampN(tipSoil.spt)\n const tip = tipKPa * 1000 * area\n return { tip, skin, ultimate: tip + skin, tipSoil }\n}\n\n/**\n * The shortest pile (to `step` metres) whose ultimate resistance over `safety` carries `load` newtons, going down from `top`; `maxLength` if none.\n * This is how a designer takes a pile down to firm ground.\n */\nexport const pileLength = (profile: SoilProfile, o: { load: number; diameter: number; top?: number; method?: PileSpec['method']; safety?: number; step?: number; maxLength?: number; soils?: ReadonlyMap<string, SoilDef> }): number => {\n const soils = o.soils ?? resolveSoil().byId\n const safety = o.safety ?? SOIL_DEFAULTS.pileSafety\n const step = o.step ?? 0.5\n const max = o.maxLength ?? 60\n for (let L = step; L <= max + 1e-9; L += step) {\n if (pileCapacity(profile, { length: L, diameter: o.diameter, ...(o.method ? { method: o.method } : {}) }, o.top ?? 0, soils).ultimate / safety >= o.load) return Math.round(L / step) * step\n }\n return max\n}\n\n/** Stiffness of one pile in N/m: the shaft shortens under the mean of its force (`L / (2 E A)`) in series with the tip as a rigid plate (`E d / (1 - nu^2)`). */\nexport const pileStiffness = (pile: PileSpec, pileElasticGPa: number, tipElasticMPa: number, tipPoisson: number): number => {\n const area = (Math.PI * pile.diameter * pile.diameter) / 4\n const shaft = pile.length / (2 * pileElasticGPa * 1e9 * area)\n const tip = (1 - tipPoisson * tipPoisson) / (tipElasticMPa * 1e6 * pile.diameter)\n return 1 / (shaft + tip)\n}\n\n/** Subgrade modulus in Pa/m of a rigid footing of width `width`: `E / (B (1 - nu^2) Iw)`, the elastic settlement of the footing as springs. */\nexport const subgradeModulus = (elasticMPa: number, poisson: number, width: number, rigidity: number = SOIL_DEFAULTS.rigidity): number =>\n (elasticMPa * 1e6) / (Math.max(0.05, width) * (1 - poisson * poisson) * rigidity)\n\n/**\n * Thickness-free design check of a shallow footing: the area a load of `load` newtons needs on `soil` (allowable pressure), as a designer sizes it.\n */\nexport const footingArea = (load: number, allowableKPa: number): number => load / (allowableKPa * 1000)\n\n/** One support of the object on the ground: a footing cell or a pile, at object-local `x, z`, `hx`/`hz` half its size. */\nexport interface SoilSpring {\n x: number\n z: number\n hx: number\n hz: number\n /** N/m. */\n k: number\n /** Newtons it carries before it gives way. */\n cap: number\n /** Permanent settlement of the soil under it from yielding, metres: it pushes back only past this (default 0). */\n set?: number\n}\n\n/** The springs' permanent settlement after the base moved to `(s, a, b)`: a spring pushed past its capacity keeps the extra (return mapping). */\nexport const yieldSprings = (springs: readonly SoilSpring[], s: number, a: number, b: number): number[] => {\n const [x0, z0] = stiffnessCentre(springs)\n return springs.map((sp) => {\n const set = sp.set ?? 0\n const w = s + a * (sp.x - x0) + b * (sp.z - z0)\n return sp.k * (w - set) > sp.cap ? w - sp.cap / sp.k : set\n })\n}\n\nexport interface FoundationSolve {\n /** Settlement at the centre of stiffness, metres. */\n s: number\n /** Slopes of the base: the foundations go down `a` per metre of x and `b` per metre of z. */\n a: number\n b: number\n /** An equilibrium was found and it is stable. */\n stable: boolean\n /** Some spring is at its capacity in that equilibrium. */\n yielded: boolean\n /** Weight over the sum of the capacities. */\n bearing: number\n /** Largest force over capacity of a spring, 0..1. */\n edge: number\n /** Residual of the vertical force and moments at the end, to tell which way an unstable object moves. */\n residual: [number, number, number]\n}\n\n/** Centre of stiffness of the springs. */\nexport const stiffnessCentre = (springs: readonly SoilSpring[]): [number, number] => {\n let k = 0, x = 0, z = 0\n for (const s of springs) {\n k += s.k\n x += s.k * s.x\n z += s.k * s.z\n }\n return k > 0 ? [x / k, z / k] : [0, 0]\n}\n\n/** Solves `J d = r` for a symmetric 3x3 by Cholesky; null when `J` is not positive definite. */\nconst cholesky3 = (J: number[][], r: number[]): number[] | null => {\n const L = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]\n for (let i = 0; i < 3; i++) {\n for (let j = 0; j <= i; j++) {\n let sum = J[i][j]\n for (let k = 0; k < j; k++) sum -= L[i][k] * L[j][k]\n if (i === j) {\n if (!(sum > 1e-9 * Math.max(1, Math.abs(J[i][i])))) return null\n L[i][i] = Math.sqrt(sum)\n } else L[i][j] = sum / L[j][j]\n }\n }\n const y = [0, 0, 0]\n for (let i = 0; i < 3; i++) {\n let sum = r[i]\n for (let k = 0; k < i; k++) sum -= L[i][k] * y[k]\n y[i] = sum / L[i][i]\n }\n const x = [0, 0, 0]\n for (let i = 2; i >= 0; i--) {\n let sum = y[i]\n for (let k = i + 1; k < 3; k++) sum -= L[k][i] * x[k]\n x[i] = sum / L[i][i]\n }\n return x\n}\n\n/**\n * Equilibrium of a rigid object of weight `weight` (N) on elastic-perfectly-plastic springs that carry no tension, with its centre of mass at\n * `(xg, zg)` and `height` metres above the base, leaning `imperfection` (radians, x and z) before any load and moving over as it leans (P-delta).\n * Newton iterations from `start`; where the tangent is not positive definite the elastic stiffness of the springs in contact is used instead.\n */\nexport const solveFoundation = (\n springs: readonly SoilSpring[],\n weight: number,\n xg: number,\n zg: number,\n height: number,\n imperfection: readonly [number, number],\n start: { s: number; a: number; b: number } = { s: 0, a: 0, b: 0 },\n): FoundationSolve => {\n const [x0, z0] = stiffnessCentre(springs)\n const capSum = springs.reduce((sum, s) => sum + s.cap, 0)\n const span = Math.max(1, ...springs.map((s) => Math.max(Math.abs(s.x - x0) + s.hx, Math.abs(s.z - z0) + s.hz)))\n let s = start.s, a = start.a, b = start.b\n // from a base that touches nothing, start at the elastic settlement of the whole bed\n if (springs.every((sp) => s + a * (sp.x - x0) + b * (sp.z - z0) - (sp.set ?? 0) <= 0)) {\n s = weight / Math.max(1e-9, springs.reduce((sum, sp) => sum + sp.k, 0))\n a = b = 0\n }\n const Wh = weight * height\n const evaluate = () => {\n let F = 0, Mx = 0, Mz = 0, edge = 0, yielded = false\n const Jt = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]\n const Je = [[0, 0, 0], [0, 0, 0], [0, 0, 0]]\n const add = (J: number[][], k: number, dx: number, dz: number) => {\n J[0][0] += k; J[0][1] += k * dx; J[0][2] += k * dz\n J[1][1] += k * dx * dx; J[1][2] += k * dx * dz; J[2][2] += k * dz * dz\n }\n for (const sp of springs) {\n const dx = sp.x - x0, dz = sp.z - z0\n const w = s + a * dx + b * dz - (sp.set ?? 0)\n if (w <= 0) continue\n const f = sp.k * w\n add(Je, sp.k, dx, dz)\n let force = f\n if (f >= sp.cap) {\n force = sp.cap\n yielded = true\n } else add(Jt, sp.k, dx, dz)\n edge = Math.max(edge, force / sp.cap)\n F += force\n Mx += force * dx\n Mz += force * dz\n }\n for (const J of [Jt, Je]) {\n J[1][0] = J[0][1]; J[2][0] = J[0][2]; J[2][1] = J[1][2]\n J[1][1] -= Wh; J[2][2] -= Wh\n }\n const r = [weight - F, weight * (xg - x0 + height * (a + imperfection[0])) - Mx, weight * (zg - z0 + height * (b + imperfection[1])) - Mz]\n return { r, Jt, Je, edge, yielded }\n }\n let ev = evaluate()\n let converged = false\n const tol = 1e-7 * weight\n for (let it = 0; it < 120; it++) {\n if (Math.abs(ev.r[0]) < tol && Math.abs(ev.r[1]) < tol * span && Math.abs(ev.r[2]) < tol * span) {\n converged = true\n break\n }\n const d = cholesky3(ev.Jt, ev.r) ?? cholesky3(ev.Je, ev.r)\n if (!d) break\n s += d[0]\n a += d[1]\n b += d[2]\n if (!Number.isFinite(s + a + b) || Math.abs(a) > 2 || Math.abs(b) > 2) break\n ev = evaluate()\n }\n // a stable equilibrium keeps a positive definite tangent: with every spring under one side yielding the object has nothing left to stop it\n const stable = converged && cholesky3(ev.Jt, [0, 0, 0]) !== null\n return { s, a, b, stable, yielded: ev.yielded, bearing: capSum > 0 ? weight / capSum : Infinity, edge: ev.edge, residual: [ev.r[0], ev.r[1], ev.r[2]] }\n}\n","[\n { \"id\": \"I\", \"zg\": 250, \"b\": { \"A\": 1.1, \"B\": 1.11, \"C\": 1.12 }, \"p\": { \"A\": 0.06, \"B\": 0.065, \"C\": 0.07 }, \"z0\": 0.005 },\n { \"id\": \"II\", \"zg\": 300, \"b\": { \"A\": 1.0, \"B\": 1.0, \"C\": 1.0 }, \"p\": { \"A\": 0.085, \"B\": 0.09, \"C\": 0.1 }, \"z0\": 0.05 },\n { \"id\": \"III\", \"zg\": 350, \"b\": { \"A\": 0.94, \"B\": 0.94, \"C\": 0.93 }, \"p\": { \"A\": 0.1, \"B\": 0.105, \"C\": 0.115 }, \"z0\": 0.3 },\n { \"id\": \"IV\", \"zg\": 420, \"b\": { \"A\": 0.86, \"B\": 0.85, \"C\": 0.84 }, \"p\": { \"A\": 0.12, \"B\": 0.125, \"C\": 0.135 }, \"z0\": 1.0 },\n { \"id\": \"V\", \"zg\": 500, \"b\": { \"A\": 0.74, \"B\": 0.73, \"C\": 0.71 }, \"p\": { \"A\": 0.15, \"B\": 0.16, \"C\": 0.175 }, \"z0\": 2.5 }\n]\n","import windTerrainJson from './data/wind-terrain.json'\nimport { GRAVITY } from './flexure'\nimport { createRng } from './math'\nimport { thinAxisOf } from './layers'\nimport { verticalBarCount } from './rebar'\nimport type { Vec3, WindExposure, WindOptions, WindTerrainDef } from './types'\n\n/**\n * Wind on a building. The wind pressure grows with the height (NBR 6123), the building is cut into storey-high bands, each band takes the force of\n * its area, and the structure that resists it is the walls (a cantilever of composite section) working with the frame (storey shear stiffness) as\n * the wall-frame interaction of Heidebrecht & Stafford Smith. The same stiffness gives the first mode (Rayleigh), and a gust series moves the top\n * against it, with a tuned mass damper if there is one. Pure formulas in SI units (N, m, Pa, s); the world calls them with the parts' boxes.\n */\n\n/** Built-in terrain categories (data in `src/data/wind-terrain.json`): NBR 6123 table 1 and the roughness lengths. */\nexport const WIND_TERRAIN: readonly WindTerrainDef[] = windTerrainJson as WindTerrainDef[]\n\nexport const WIND_DEFAULTS = {\n speed: 40,\n direction: [1, 0, 0] as Vec3,\n terrain: 'III' as NonNullable<WindExposure['terrain']>,\n class: 'auto' as NonNullable<WindExposure['class']>,\n topography: 1,\n statistical: 1,\n drag: 1.3,\n damping: 0.016,\n airDensity: 1.226,\n minHeight: 5,\n bandHeight: 3,\n stiffnessFactor: 0.8,\n beamFactor: 0.4,\n flange: 0.1,\n driftLimit: 1 / 500,\n loadFactor: 1.4,\n chord: false,\n meanRatio: 0.69,\n gustFactor: { A: 1, B: 0.98, C: 0.95 },\n gust: { components: 400, maxHz: 2, scale: 1200, seed: 1 },\n peakDecay: 60,\n tuning: 'den-hartog' as NonNullable<WindOptions['tuning']>,\n} as const\n\nexport type ResolvedWind = Required<Omit<WindOptions, 'terrains' | 'gustFactor' | 'gust' | 'direction'>> & {\n direction: Vec3\n gustFactor: { A: number; B: number; C: number }\n gust: { components: number; maxHz: number; scale: number; seed: number }\n terrains: Map<string, WindTerrainDef>\n}\n\nconst definedOf = <T extends object>(o?: T): Partial<T> => Object.fromEntries(Object.entries(o ?? {}).filter(([, v]) => v !== undefined)) as Partial<T>\n\nexport const resolveWind = (o: WindOptions = {}): ResolvedWind => {\n const terrains = new Map(WIND_TERRAIN.map((t) => [t.id, t]))\n for (const t of o.terrains ?? []) terrains.set(t.id, t)\n const { terrains: _terrains, gustFactor, gust, ...rest } = o\n return {\n ...WIND_DEFAULTS,\n ...definedOf(rest),\n direction: o.direction ?? WIND_DEFAULTS.direction,\n gustFactor: { ...WIND_DEFAULTS.gustFactor, ...definedOf(gustFactor) },\n gust: { ...WIND_DEFAULTS.gust, ...definedOf(gust) },\n terrains,\n }\n}\n\n/** The world's wind with one object's `DestructibleSpec.wind` over it. */\nexport const exposureOf = (w: ResolvedWind, spec?: WindExposure | false): ResolvedWind => (spec ? { ...w, ...definedOf(spec) } : w)\n\n// ---------------------------------------------------------------------------------------------------------------------------------------------\n// Pressure and profile\n// ---------------------------------------------------------------------------------------------------------------------------------------------\n\n/** Dynamic pressure in N/m² of a wind of `speed` m/s: `q = rho V^2 / 2`, which is `0.613 V^2` for the air at 15 °C (NBR 6123 4.2). */\nexport const windPressure = (speed: number, density: number = WIND_DEFAULTS.airDensity): number => 0.5 * density * speed * speed\n\n/** Class of a building by its largest dimension (NBR 6123 table 1): `A` up to 20 m, `B` up to 50 m, `C` above. */\nexport const windClass = (largest: number): 'A' | 'B' | 'C' => (largest <= 20 ? 'A' : largest <= 50 ? 'B' : 'C')\n\n/**\n * Height factor of the gust `S2 = b * Fr * (z / 10)^p` (NBR 6123 5.3), `z` in metres above the ground: at least `minHeight` and at most the gradient\n * height of the category.\n */\nexport const heightFactor = (z: number, terrain: WindTerrainDef, cls: 'A' | 'B' | 'C', o: { gustFactor?: { A: number; B: number; C: number }; minHeight?: number } = {}): number => {\n const zz = Math.min(terrain.zg, Math.max(o.minHeight ?? WIND_DEFAULTS.minHeight, z))\n return terrain.b[cls] * (o.gustFactor ?? WIND_DEFAULTS.gustFactor)[cls] * (zz / 10) ** terrain.p[cls]\n}\n\n/** The same profile for the 10-minute mean wind: no gust factor, times `meanRatio` (the share of the gust the mean is). */\nexport const meanHeightFactor = (z: number, terrain: WindTerrainDef, cls: 'A' | 'B' | 'C', o: { meanRatio?: number; minHeight?: number } = {}): number =>\n (o.meanRatio ?? WIND_DEFAULTS.meanRatio) * heightFactor(z, terrain, cls, { gustFactor: { A: 1, B: 1, C: 1 }, ...(o.minHeight !== undefined ? { minHeight: o.minHeight } : {}) })\n\n/** Turbulence intensity at `z` over terrain of roughness length `z0`: `1 / ln(z / z0)` (EN 1991-1-4 4.4), no more than 0.5. */\nexport const turbulenceIntensity = (z: number, z0: number): number => Math.min(0.5, 1 / Math.log(Math.max(z, 1.5 * z0) / z0))\n\n// ---------------------------------------------------------------------------------------------------------------------------------------------\n// Wall-frame cantilever\n// ---------------------------------------------------------------------------------------------------------------------------------------------\n\nexport interface WallFrameSolution {\n /** Rotation `w'` at the n + 1 nodes. */\n psi: number[]\n /** Deflection at the nodes (0 at the base). */\n w: number[]\n}\n\n/**\n * A cantilever with bending stiffness `ei[j]` (N m²) and shear stiffness `ga[j]` (N) in each band of height `hb[j]`, loaded by the shear `V` at the\n * n + 1 nodes (from the base up; `V[n]` is the shear at the top, 0 when nothing hangs there). The wall and the frame share the load as\n * `-(EI psi')' + GA psi = V`, `psi(0) = 0` (as far as there is a wall), zero moment at the top: linear elements, one per band, a tridiagonal system. Without the frame\n * (`ga` 0) it is the bending cantilever (`w = w H^4 / (8 EI)` for a uniform load), without the wall (`ei` 0) the shear beam (`w' = V / GA`).\n */\nexport const solveWallFrame = (hb: readonly number[], ei: readonly number[], ga: readonly number[], V: readonly number[]): WallFrameSolution => {\n const n = hb.length\n const diag = new Array<number>(n + 1).fill(0)\n const off = new Array<number>(n).fill(0)\n const rhs = new Array<number>(n + 1).fill(0)\n for (let j = 0; j < n; j++) {\n const h = hb[j], e = ei[j], g = ga[j]\n diag[j] += e / h + (g * h) / 3\n diag[j + 1] += e / h + (g * h) / 3\n off[j] = -e / h + (g * h) / 6\n rhs[j] += (h / 6) * (2 * V[j] + V[j + 1])\n rhs[j + 1] += (h / 6) * (V[j] + 2 * V[j + 1])\n }\n // the wall is clamped at the base (psi = 0) as far as there is a wall: a stiff spring on the base node whose weight is the wall's share of the\n // stiffness over one band, so a frame alone is not held back by a boundary layer that no band resolves\n const wall = ei[0] / (ei[0] + ga[0] * hb[0] * hb[0])\n diag[0] += 1e6 * (ei[0] / hb[0] + ga[0] * hb[0]) * wall\n // Thomas algorithm on the nodes 0..n\n const c = new Array<number>(n + 1).fill(0)\n const d = new Array<number>(n + 1).fill(0)\n const psi = new Array<number>(n + 1).fill(0)\n c[0] = off[0] / diag[0]\n d[0] = rhs[0] / diag[0]\n for (let i = 1; i <= n; i++) {\n const m = diag[i] - off[i - 1] * c[i - 1]\n c[i] = i < n ? off[i] / m : 0\n d[i] = (rhs[i] - off[i - 1] * d[i - 1]) / m\n }\n psi[n] = d[n]\n for (let i = n - 1; i >= 0; i--) psi[i] = d[i] - c[i] * psi[i + 1]\n const w = new Array<number>(n + 1).fill(0)\n for (let j = 0; j < n; j++) w[j + 1] = w[j] + (hb[j] * (psi[j] + psi[j + 1])) / 2\n return { psi, w }\n}\n\n/** Shear at the n + 1 nodes of loads `f[j]` spread over each band (the load of the bands above, from the top). */\nexport const shearNodes = (f: readonly number[]): number[] => {\n const V = new Array<number>(f.length + 1).fill(0)\n for (let j = f.length - 1; j >= 0; j--) V[j] = V[j + 1] + f[j]\n return V\n}\n\n/** Moment at the n + 1 nodes from the shear at the nodes (linear inside each band, so the trapezoid is exact). */\nexport const momentNodes = (hb: readonly number[], V: readonly number[]): number[] => {\n const M = new Array<number>(V.length).fill(0)\n for (let j = hb.length - 1; j >= 0; j--) M[j] = M[j + 1] + (hb[j] * (V[j] + V[j + 1])) / 2\n return M\n}\n\n// ---------------------------------------------------------------------------------------------------------------------------------------------\n// Analysis of a building\n// ---------------------------------------------------------------------------------------------------------------------------------------------\n\n/** Factor on the stiffness of the bands above the lateral system, which move as a rigid body with its top. */\nconst RIGID = 1e3\n\nexport interface WindPartInput {\n /** Object-local box of the part (`aabbOf`). */\n min: Vec3\n max: Vec3\n /** `wall` and `column` resist, `beam` frames into the columns, `foundation` is the footprint, `other` only weighs and shows area. */\n kind: 'wall' | 'column' | 'beam' | 'foundation' | 'other'\n /** Young's modulus in Pa (walls, columns, beams). */\n elasticPa?: number\n /** Mass in kg (what rests on it is counted by the parts that rest). */\n mass: number\n /** A tuned mass damper: weighs, but is not part of the modal mass of the building. */\n damper?: boolean\n /** Indices of the beams that frame into this column (closed joints). */\n beams?: readonly number[]\n /** Thickness of the slab that rests on this beam and works with it as a T section (0: none). */\n slab?: number\n}\n\n/** Everything `analyzeWind` needs once it is resolved for one building (`ResolvedWind` with its terrain and direction). */\nexport interface WindCase {\n speed: number\n /** Horizontal unit vector the wind blows towards, object-local `[x, z]`. */\n direction: readonly [number, number]\n terrain: WindTerrainDef\n cls: 'auto' | 'A' | 'B' | 'C'\n topography: number\n statistical: number\n drag: number\n damping: number\n airDensity: number\n minHeight: number\n bandHeight: number\n stiffnessFactor: number\n beamFactor: number\n flange: number\n loadFactor: number\n chord: boolean\n meanRatio: number\n gustFactor: { A: number; B: number; C: number }\n}\n\nexport interface WindAnalysis {\n /** Height of the top above the ground and the class used. */\n height: number\n cls: 'A' | 'B' | 'C'\n /** Largest width across the wind. */\n width: number\n /** Band heights and the height of the middle of each above the ground. */\n bands: number[]\n mid: number[]\n /** Design force on each band, N, and the force of the 10-minute mean wind. */\n forces: number[]\n meanForces: number[]\n /** Design pressure at the top, N/m². */\n pressure: number\n /** Design base shear (N) and overturning moment (N m). */\n shear: number\n moment: number\n /** Top deflection under the design wind (m), over the height, and under the mean wind. */\n deflection: number\n drift: number\n lean: number\n /** Weight, N, and the overturning moment (factored) over the stabilizing moment `W e`. */\n weight: number\n overturn: number\n /** Share of the base moment the walls carry (the rest is the frame's couple). */\n wallShare: number\n /** Bending and shear stiffness of each band (cracked). */\n ei: number[]\n ga: number[]\n /** First mode (Rayleigh): frequency in Hz, angular frequency, modal mass and stiffness, shape at the nodes. */\n frequency: number\n omega: number\n modalMass: number\n modalStiffness: number\n shape: { z: number[]; phi: number[] }\n /** Modal force of the mean wind, N; turbulence intensity for the gust. */\n modalForce: number\n intensity: number\n /** Axial force the design wind adds to each input part, N (compression positive), without the load factor. */\n axial: number[]\n}\n\n/**\n * Second moment of area of a beam of web `bw` and depth `h` with a slab flange of width `bf` and thickness `tf` on top (a T section, about its own\n * centroid); the web alone when there is no flange.\n */\nexport const tBeamInertia = (bw: number, h: number, bf: number, tf: number): number => {\n const web = bw * h\n const fl = Math.max(0, bf - bw) * Math.min(tf, h)\n const t = Math.min(tf, h)\n const yc = (web * (h / 2) + fl * (h - t / 2)) / (web + fl)\n return (bw * h ** 3) / 12 + web * (h / 2 - yc) ** 2 + (Math.max(0, bf - bw) * t ** 3) / 12 + fl * (h - t / 2 - yc) ** 2\n}\n\n/** The shape of the first mode at height `z` above the ground (linear between the nodes). */\nexport const shapeAt = (a: Pick<WindAnalysis, 'shape'>, z: number): number => {\n const { z: zs, phi } = a.shape\n if (z <= zs[0]) return phi[0]\n for (let i = 1; i < zs.length; i++) if (z <= zs[i]) return phi[i - 1] + ((phi[i] - phi[i - 1]) * (z - zs[i - 1])) / (zs[i] - zs[i - 1])\n return phi[phi.length - 1]\n}\n\n/**\n * Wind on a building of `parts` standing on the ground at `ground` (the y of the top of the foundations). Null when it has no wall or column.\n * Bands of `bandHeight`; a part gives to a band the share of itself that lies inside it.\n */\nexport const analyzeWind = (parts: readonly WindPartInput[], c: WindCase, ground: number): WindAnalysis | null => {\n const [dx, dz] = c.direction\n const along = (p: WindPartInput) => {\n const cx = (p.min[0] + p.max[0]) / 2, cz = (p.min[2] + p.max[2]) / 2\n const hx = (p.max[0] - p.min[0]) / 2, hz = (p.max[2] - p.min[2]) / 2\n return {\n u: cx * dx + cz * dz, v: -cx * dz + cz * dx,\n du: 2 * (Math.abs(dx) * hx + Math.abs(dz) * hz), dv: 2 * (Math.abs(dz) * hx + Math.abs(dx) * hz),\n }\n }\n const g = parts.map(along)\n let topY = ground\n let resists = false\n for (const p of parts) {\n if (p.kind === 'foundation') continue\n topY = Math.max(topY, p.max[1])\n if ((p.kind === 'wall' || p.kind === 'column') && p.elasticPa) resists = true\n }\n const height = topY - ground\n if (!(height > 0) || !resists) return null\n const n = Math.max(1, Math.ceil(height / c.bandHeight - 1e-9))\n const bands = Array.from({ length: n }, (_, j) => Math.min(c.bandHeight, height - j * c.bandHeight))\n const z0 = Array.from({ length: n }, (_, j) => j * c.bandHeight)\n const mid = bands.map((h, j) => z0[j] + h / 2)\n const share = (p: WindPartInput, j: number): number => {\n const a = Math.max(p.min[1] - ground, z0[j]), b = Math.min(p.max[1] - ground, z0[j] + bands[j])\n return Math.max(0, b - a)\n }\n\n // the building across the wind, the weight and the section of walls and columns\n const vmin = new Array<number>(n).fill(Infinity), vmax = new Array<number>(n).fill(-Infinity)\n const mass = new Array<number>(n).fill(0)\n let weight = 0, wu = 0\n let footEnd = -Infinity\n let anyFoundation = false\n for (let i = 0; i < parts.length; i++) {\n const p = parts[i]\n weight += p.mass * GRAVITY\n wu += p.mass * g[i].u\n if (p.kind === 'foundation') {\n anyFoundation = true\n footEnd = Math.max(footEnd, g[i].u + g[i].du / 2)\n continue\n }\n const full = Math.max(1e-6, p.max[1] - p.min[1])\n for (let j = 0; j < n; j++) {\n const ov = share(p, j)\n if (ov <= 0) continue\n vmin[j] = Math.min(vmin[j], g[i].v - g[i].dv / 2)\n vmax[j] = Math.max(vmax[j], g[i].v + g[i].dv / 2)\n if (!p.damper) mass[j] += (p.mass * ov) / full\n }\n }\n if (!anyFoundation) for (let i = 0; i < parts.length; i++) if (parts[i].min[1] - ground < 0.1) footEnd = Math.max(footEnd, g[i].u + g[i].du / 2)\n const totalMass = weight / GRAVITY\n const uCg = totalMass > 0 ? wu / totalMass : 0\n const width = vmax.map((hi, j) => (hi > vmin[j] ? hi - vmin[j] : 0))\n const widest = Math.max(...width)\n const cls = c.cls === 'auto' ? windClass(Math.max(height, widest)) : c.cls\n\n // forces on the bands\n const k0 = c.speed * c.topography * c.statistical\n const pressure = mid.map((z) => windPressure(k0 * heightFactor(z, c.terrain, cls, { gustFactor: c.gustFactor, minHeight: c.minHeight }), c.airDensity))\n const meanPressure = mid.map((z) => windPressure(k0 * meanHeightFactor(z, c.terrain, cls, { meanRatio: c.meanRatio, minHeight: c.minHeight }), c.airDensity))\n const forces = bands.map((h, j) => pressure[j] * c.drag * width[j] * h)\n const meanForces = bands.map((h, j) => meanPressure[j] * c.drag * width[j] * h)\n const V = shearNodes(forces)\n const M = momentNodes(bands, V)\n\n // the lateral system: walls as one section, columns as a shear frame\n const ea = new Array<number>(n).fill(0), eau = new Array<number>(n).fill(0)\n const vertical: number[] = []\n for (let i = 0; i < parts.length; i++) {\n const p = parts[i]\n if ((p.kind !== 'wall' && !(p.kind === 'column' && c.chord)) || !p.elasticPa) continue\n vertical.push(i)\n const area = g[i].du * g[i].dv\n const e = p.elasticPa * c.stiffnessFactor\n for (let j = 0; j < n; j++) {\n const w = share(p, j) / bands[j]\n if (w <= 0) continue\n ea[j] += e * area * w\n eau[j] += e * area * g[i].u * w\n }\n }\n const centre = ea.map((v, j) => (v > 0 ? eau[j] / v : 0))\n const ei = new Array<number>(n).fill(0)\n const ga = new Array<number>(n).fill(0)\n for (const i of vertical) {\n const p = parts[i]\n const e = p.elasticPa! * c.stiffnessFactor\n for (let j = 0; j < n; j++) {\n const w = share(p, j) / bands[j]\n if (w <= 0) continue\n ei[j] += e * ((g[i].du ** 3 * g[i].dv) / 12 + g[i].du * g[i].dv * (g[i].u - centre[j]) ** 2) * w\n }\n }\n for (let i = 0; i < parts.length; i++) {\n const p = parts[i]\n if (p.kind !== 'column' || !p.elasticPa) continue\n const h = Math.max(1e-6, p.max[1] - p.min[1])\n const kc = (p.elasticPa * c.stiffnessFactor * (g[i].du ** 3 * g[i].dv) / 12) / h\n let beams = 0\n for (const b of p.beams ?? []) {\n const q = parts[b]\n if (!q?.elasticPa) continue\n const hx = q.max[0] - q.min[0], hz = q.max[2] - q.min[2]\n const long = Math.max(hx, hz), short = Math.min(hx, hz)\n const cos = hx >= hz ? Math.abs(dx) : Math.abs(dz)\n const depth = q.max[1] - q.min[1]\n const inertia = tBeamInertia(short, depth, short + 2 * c.flange * long, q.slab ?? 0)\n beams += (cos * cos * q.elasticPa * c.beamFactor * inertia) / Math.max(long, 1e-6)\n }\n const k = beams / kc\n const base = p.min[1] - ground < 0.05\n const a = base ? (0.5 + k) / (2 + k) : k / (2 + k)\n const stiffness = (a * 12 * (p.elasticPa * c.stiffnessFactor) * ((g[i].du ** 3 * g[i].dv) / 12)) / (h * h)\n for (let j = 0; j < n; j++) ga[j] += (stiffness * share(p, j)) / bands[j]\n }\n // what stands above the highest wall or column (a roof, its trusses) is carried by them and moves with their top: nothing bends there\n let last = -1\n for (let j = 0; j < n; j++) if (ei[j] > 0 || ga[j] > 0) last = j\n for (let j = last + 1; j < n && last >= 0; j++) {\n ei[j] = ei[last] * RIGID\n ga[j] = ga[last] * RIGID\n }\n const tiny = 1\n const eiS = ei.map((v) => Math.max(v, tiny))\n const gaS = ga.map((v) => Math.max(v, tiny))\n const sol = solveWallFrame(bands, eiS, gaS, V)\n const deflection = sol.w[n]\n const lean = solveWallFrame(bands, eiS, gaS, shearNodes(meanForces)).w[n]\n\n // what the walls and the frame each carry\n const kappa = bands.map((h, j) => (sol.psi[j + 1] - sol.psi[j]) / h)\n const Mmid = bands.map((h, j) => M[j + 1] + (h / 2) * (V[j + 1] + (V[j] + V[j + 1]) / 2) / 2)\n const Mwall = ei.map((v, j) => Math.min(Mmid[j], Math.max(0, v * kappa[j])))\n const axial = new Array<number>(parts.length).fill(0)\n for (const i of vertical) {\n const p = parts[i]\n let sum = 0, tot = 0\n for (let j = 0; j < n; j++) {\n const w = share(p, j)\n if (w <= 0) continue\n sum += w * p.elasticPa! * c.stiffnessFactor * kappa[j] * g[i].du * g[i].dv * (g[i].u - centre[j])\n tot += w\n }\n axial[i] = tot > 0 ? sum / tot : 0\n }\n if (!c.chord) {\n // the frame carries the rest of the moment as a couple of the columns: forces in proportion to `A d` from their centroid\n const colA = new Array<number>(n).fill(0), colAu = new Array<number>(n).fill(0)\n const cols: number[] = []\n for (let i = 0; i < parts.length; i++) {\n if (parts[i].kind !== 'column') continue\n cols.push(i)\n for (let j = 0; j < n; j++) {\n const w = share(parts[i], j) / bands[j]\n colA[j] += g[i].du * g[i].dv * w\n colAu[j] += g[i].du * g[i].dv * g[i].u * w\n }\n }\n const colC = colA.map((a, j) => (a > 0 ? colAu[j] / a : 0))\n const colI = new Array<number>(n).fill(0)\n for (const i of cols) for (let j = 0; j < n; j++) colI[j] += (g[i].du * g[i].dv * (g[i].u - colC[j]) ** 2 * share(parts[i], j)) / bands[j]\n for (const i of cols) {\n let sum = 0, tot = 0\n for (let j = 0; j < n; j++) {\n const w = share(parts[i], j)\n if (w <= 0 || colI[j] <= 0) continue\n sum += w * (Math.max(0, Mmid[j] - Mwall[j]) * g[i].du * g[i].dv * (g[i].u - colC[j])) / colI[j]\n tot += w\n }\n axial[i] = tot > 0 ? sum / tot : 0\n }\n }\n\n // stability: overturning moment against the weight over the leeward edge of the foundations\n const arm = footEnd - uCg\n const overturn = arm > 0 ? (c.loadFactor * M[0]) / (weight * arm) : Infinity\n\n // first mode, Rayleigh: the shape under a load equal to the mass of each band\n const mode = solveWallFrame(bands, eiS, gaS, shearNodes(mass))\n const top = mode.w[n]\n const um = bands.map((_, j) => (mode.w[j] + mode.w[j + 1]) / 2)\n let mu = 0, muu = 0\n mass.forEach((m, j) => {\n mu += m * um[j]\n muu += m * um[j] * um[j]\n })\n const omega = muu > 0 ? Math.sqrt(mu / muu) : 0\n const phi = um.map((u) => (top > 0 ? u / top : 0))\n const modalMass = mass.reduce((s, m, j) => s + m * phi[j] * phi[j], 0)\n const modalForce = meanForces.reduce((s, f, j) => s + f * phi[j], 0)\n const z = [0, ...bands.map((_, j) => z0[j] + bands[j])]\n const intensity = turbulenceIntensity(Math.max(0.6 * height, c.minHeight), c.terrain.z0)\n\n return {\n height, cls, width: widest, bands, mid, forces, meanForces, pressure: pressure[n - 1], shear: V[0], moment: M[0], deflection, drift: deflection / height, lean,\n weight, overturn, wallShare: M[0] > 0 ? Mwall[0] / M[0] : 0, ei, ga, frequency: omega / (2 * Math.PI), omega, modalMass, modalStiffness: omega * omega * modalMass,\n shape: { z, phi: mode.w.map((w) => (top > 0 ? w / top : 0)) }, modalForce, intensity, axial,\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------------------------------\n// Tuned mass damper\n// ---------------------------------------------------------------------------------------------------------------------------------------------\n\n/**\n * Optimal tuning of a damper of mass ratio `mu` (damper mass over the modal mass): its frequency over the building's and its damping ratio.\n * `den-hartog` (1956): `1 / (1 + mu)` and `sqrt(3 mu / (8 (1 + mu)^3))`, for a harmonic force on an undamped structure. `warburton` (1982): for a random\n * force, `sqrt(1 - mu / 2) / (1 + mu)` and `sqrt(mu (1 - mu / 4) / (4 (1 + mu) (1 - mu / 2)))`.\n */\nexport const damperTuning = (mu: number, kind: 'den-hartog' | 'warburton' = 'den-hartog'): { frequency: number; damping: number } =>\n kind === 'warburton'\n ? { frequency: Math.sqrt(1 - mu / 2) / (1 + mu), damping: Math.sqrt((mu * (1 - mu / 4)) / (4 * (1 + mu) * (1 - mu / 2))) }\n : { frequency: 1 / (1 + mu), damping: Math.sqrt((3 * mu) / (8 * (1 + mu) ** 3)) }\n\n/**\n * Amplitude of the structure under a harmonic force over its static deflection, with a damper: `r` the forcing frequency over the structure's,\n * `mu` the mass ratio, `g` the damper's frequency over the structure's, `damper` and `structure` the damping ratios. Solves\n * `[(1 - r^2 + 2 i zs r) - mu A r^2 / (A - r^2)] X = 1` with `A = g^2 + 2 i zd g r`. `mu` 0 is the structure alone (`1 / (2 zs)` at resonance).\n */\nexport const damperAmplification = (r: number, mu: number, g: number, damper: number, structure = 0): number => {\n // complex arithmetic by hand: numbers as [re, im]\n const mul = (a: [number, number], b: [number, number]): [number, number] => [a[0] * b[0] - a[1] * b[1], a[0] * b[1] + a[1] * b[0]]\n const div = (a: [number, number], b: [number, number]): [number, number] => {\n const d = b[0] * b[0] + b[1] * b[1]\n return [(a[0] * b[0] + a[1] * b[1]) / d, (a[1] * b[0] - a[0] * b[1]) / d]\n }\n const A: [number, number] = [g * g, 2 * damper * g * r]\n const main: [number, number] = [1 - r * r, 2 * structure * r]\n const coupling = mu > 0 ? mul([mu * r * r, 0], div(A, [A[0] - r * r, A[1]])) : ([0, 0] as [number, number])\n const total: [number, number] = [main[0] - coupling[0], main[1] - coupling[1]]\n return 1 / Math.hypot(total[0], total[1])\n}\n\n// ---------------------------------------------------------------------------------------------------------------------------------------------\n// Gust and sway\n// ---------------------------------------------------------------------------------------------------------------------------------------------\n\n/** A gust series: sines of equal frequency spacing whose amplitudes follow the Davenport spectrum, normalized to unit variance. */\nexport interface Gust {\n freq: number[]\n amp: number[]\n phase: number[]\n}\n\n/**\n * The turbulence at the 10 m mean speed `v10`: `components` sines up to `maxHz`, amplitudes from the Davenport spectrum `f S(f) / u*^2 = 4 x^2 / (1 + x^2)^(4/3)`,\n * `x = scale f / v10` (NBR 6123 chapter 9, Simiu & Scanlan), phases from the seed.\n */\nexport const makeGust = (v10: number, o: { components: number; maxHz: number; scale: number; seed: number }): Gust => {\n const rng = createRng(o.seed)\n const n = Math.max(1, Math.floor(o.components))\n const df = o.maxHz / n\n const freq = Array.from({ length: n }, (_, k) => (k + 0.5) * df)\n const weight = freq.map((f) => {\n const x = (o.scale * f) / Math.max(v10, 1e-6)\n return ((4 * x * x) / (1 + x * x) ** (4 / 3) / f) * df\n })\n const sum = weight.reduce((s, w) => s + w, 0)\n return { freq, amp: weight.map((w) => Math.sqrt((2 * w) / sum)), phase: freq.map(() => rng.next() * 2 * Math.PI) }\n}\n\n/** The gust at time `t`: zero mean, unit variance. */\nexport const gustAt = (gust: Gust, t: number): number => {\n let s = 0\n for (let k = 0; k < gust.freq.length; k++) s += gust.amp[k] * Math.cos(2 * Math.PI * gust.freq[k] * t + gust.phase[k])\n return s\n}\n\n/** The first mode of a building with an optional tuned mass damper: modal mass, stiffness and damping, and the damper's mass, stiffness and dashpot. */\nexport interface SwaySystem {\n M: number\n K: number\n C: number\n damper?: { m: number; k: number; c: number }\n}\n\n/** Displacement and velocity of the top, and of the damper's mass (absolute). */\nexport interface SwayState {\n x: number\n v: number\n y: number\n w: number\n}\n\n/** Advances `s` by `dt` seconds under the force `force(t)` (N, on the modal mass), RK4 with steps no longer than `maxStep`. */\nexport const stepSway = (s: SwayState, sys: SwaySystem, t: number, dt: number, force: (t: number) => number, maxStep = Infinity): void => {\n const steps = Math.max(1, Math.ceil(dt / maxStep - 1e-9))\n const h = dt / steps\n const d = sys.damper\n const f = (x: number, v: number, y: number, w: number, tt: number): [number, number, number, number] => {\n const fd = d ? d.k * (y - x) + d.c * (w - v) : 0\n return [v, (force(tt) - sys.K * x - sys.C * v + fd) / sys.M, d ? w : 0, d ? -fd / d.m : 0]\n }\n for (let i = 0; i < steps; i++) {\n const tt = t + i * h\n const k1 = f(s.x, s.v, s.y, s.w, tt)\n const k2 = f(s.x + (h / 2) * k1[0], s.v + (h / 2) * k1[1], s.y + (h / 2) * k1[2], s.w + (h / 2) * k1[3], tt + h / 2)\n const k3 = f(s.x + (h / 2) * k2[0], s.v + (h / 2) * k2[1], s.y + (h / 2) * k2[2], s.w + (h / 2) * k2[3], tt + h / 2)\n const k4 = f(s.x + h * k3[0], s.v + h * k3[1], s.y + h * k3[2], s.w + h * k3[3], tt + h)\n s.x += (h / 6) * (k1[0] + 2 * k2[0] + 2 * k3[0] + k4[0])\n s.v += (h / 6) * (k1[1] + 2 * k2[1] + 2 * k3[1] + k4[1])\n s.y += (h / 6) * (k1[2] + 2 * k2[2] + 2 * k3[2] + k4[2])\n s.w += (h / 6) * (k1[3] + 2 * k2[3] + 2 * k3[3] + k4[3])\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------------------------------\n// Tension of walls and columns\n// ---------------------------------------------------------------------------------------------------------------------------------------------\n\n/**\n * Force in newtons a wall or column holds in tension: its vertical rebar at yield (`reinforcement` bars, or `ratio` of the section) when it has any,\n * else the tensile strength of its material times the section, else nothing (a masonry wall does not pull).\n */\nexport const tensionCapacity = (\n dims: Vec3, o: { reinforcement?: { spacing: number; diameter: number }; ratio?: number; yieldMPa: number; tensileMPa?: number },\n): number => {\n const section = dims[0] * dims[2]\n if (o.reinforcement) {\n const bars = verticalBarCount(dims, thinAxisOf(dims), o.reinforcement.spacing)\n return bars * Math.PI * (o.reinforcement.diameter / 2) ** 2 * o.yieldMPa * 1e6\n }\n if (o.ratio) return o.ratio * section * o.yieldMPa * 1e6\n return (o.tensileMPa ?? 0) * 1e6 * section\n}\n","[\n {\n \"id\": \"steel\",\n \"density\": 7850,\n \"hpPerKg\": 400,\n \"penetration\": 110,\n \"penetrationClass\": \"steel\",\n \"penetrationScale\": 1.3,\n \"ductility\": 0.9,\n \"fracture\": \"none\",\n \"damageScale\": {\n \"slash\": 0.1,\n \"blunt\": 0.8\n },\n \"hitDebris\": \"sparks\",\n \"breakDebris\": \"sparks\",\n \"ricochetDeg\": 20,\n \"thermal\": {\n \"meltC\": 1450,\n \"meltRate\": 0.05,\n \"conductivity\": 0.5,\n \"heatCapacity\": 3\n },\n \"visual\": {\n \"glows\": true\n },\n \"tags\": [\n \"metal\",\n \"conductive\"\n ],\n \"compressive\": 2000000\n },\n {\n \"id\": \"cast_iron\",\n \"density\": 7200,\n \"hpPerKg\": 150,\n \"penetration\": 160,\n \"penetrationClass\": \"steel\",\n \"penetrationScale\": 1.0,\n \"ductility\": 0.2,\n \"fracture\": \"snap\",\n \"fragmentSize\": [\n 0.08,\n 0.3\n ],\n \"damageScale\": {\n \"slash\": 0.1,\n \"blunt\": 1.2\n },\n \"hitDebris\": \"sparks\",\n \"breakDebris\": \"chips\",\n \"ricochetDeg\": 15,\n \"thermal\": {\n \"meltC\": 1200,\n \"meltRate\": 0.05,\n \"conductivity\": 0.45,\n \"heatCapacity\": 3\n },\n \"visual\": {\n \"glows\": true\n },\n \"tags\": [\n \"metal\",\n \"conductive\"\n ],\n \"compressive\": 1500000\n },\n {\n \"id\": \"aluminium\",\n \"density\": 2700,\n \"hpPerKg\": 250,\n \"penetration\": 60,\n \"penetrationClass\": \"steel\",\n \"penetrationScale\": 3,\n \"ductility\": 0.85,\n \"fracture\": \"none\",\n \"damageScale\": {\n \"slash\": 0.2\n },\n \"hitDebris\": \"sparks\",\n \"breakDebris\": \"sparks\",\n \"ricochetDeg\": 15,\n \"thermal\": {\n \"meltC\": 660,\n \"meltRate\": 0.06,\n \"conductivity\": 0.8,\n \"heatCapacity\": 1.5\n },\n \"visual\": {\n \"glows\": true\n },\n \"tags\": [\n \"metal\",\n \"conductive\"\n ],\n \"compressive\": 800000\n },\n {\n \"id\": \"copper\",\n \"density\": 8960,\n \"hpPerKg\": 300,\n \"penetration\": 70,\n \"penetrationClass\": \"steel\",\n \"penetrationScale\": 1.5,\n \"ductility\": 0.95,\n \"fracture\": \"none\",\n \"damageScale\": {\n \"slash\": 0.2\n },\n \"hitDebris\": \"sparks\",\n \"breakDebris\": \"sparks\",\n \"ricochetDeg\": 15,\n \"thermal\": {\n \"meltC\": 1085,\n \"meltRate\": 0.05,\n \"conductivity\": 1,\n \"heatCapacity\": 2.5\n },\n \"visual\": {\n \"glows\": true\n },\n \"tags\": [\n \"metal\",\n \"conductive\"\n ],\n \"compressive\": 1000000\n },\n {\n \"id\": \"wood_soft\",\n \"density\": 500,\n \"hpPerKg\": 90,\n \"penetration\": 9,\n \"penetrationClass\": \"wood\",\n \"penetrationScale\": 1.5,\n \"ductility\": 0.35,\n \"fracture\": \"splinter\",\n \"fragmentSize\": [\n 0.03,\n 0.15\n ],\n \"damageScale\": {\n \"blunt\": 1.2,\n \"slash\": 1.5\n },\n \"hitDebris\": \"splinters\",\n \"breakDebris\": \"splinters\",\n \"thermal\": {\n \"ignitionC\": 300,\n \"flameC\": 800,\n \"fuelFraction\": 0.9,\n \"burnRate\": 0.012,\n \"conductivity\": 0.05,\n \"heatCapacity\": 1.2,\n \"smoke\": \"grey\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"wood\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 100000\n },\n {\n \"id\": \"wood_hard\",\n \"density\": 750,\n \"hpPerKg\": 140,\n \"penetration\": 14,\n \"penetrationClass\": \"wood\",\n \"penetrationScale\": 1,\n \"ductility\": 0.3,\n \"fracture\": \"splinter\",\n \"fragmentSize\": [\n 0.03,\n 0.2\n ],\n \"damageScale\": {\n \"slash\": 1.2\n },\n \"hitDebris\": \"splinters\",\n \"breakDebris\": \"splinters\",\n \"thermal\": {\n \"ignitionC\": 330,\n \"flameC\": 800,\n \"fuelFraction\": 0.9,\n \"burnRate\": 0.01,\n \"conductivity\": 0.06,\n \"heatCapacity\": 1.4,\n \"smoke\": \"grey\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"wood\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 150000\n },\n {\n \"id\": \"plywood\",\n \"density\": 600,\n \"hpPerKg\": 70,\n \"penetration\": 7,\n \"penetrationClass\": \"wood\",\n \"penetrationScale\": 2,\n \"ductility\": 0.3,\n \"fracture\": \"snap\",\n \"fragmentSize\": [\n 0.1,\n 0.4\n ],\n \"damageScale\": {\n \"slash\": 1.3\n },\n \"hitDebris\": \"splinters\",\n \"breakDebris\": \"splinters\",\n \"thermal\": {\n \"ignitionC\": 300,\n \"flameC\": 800,\n \"fuelFraction\": 0.85,\n \"burnRate\": 0.013,\n \"conductivity\": 0.05,\n \"heatCapacity\": 1.2,\n \"smoke\": \"grey\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"wood\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 60000\n },\n {\n \"id\": \"mdf\",\n \"density\": 750,\n \"hpPerKg\": 45,\n \"penetration\": 6,\n \"penetrationClass\": \"wood\",\n \"penetrationScale\": 2.5,\n \"ductility\": 0.15,\n \"fracture\": \"snap\",\n \"fragmentSize\": [\n 0.08,\n 0.35\n ],\n \"hitDebris\": \"chips\",\n \"breakDebris\": \"dust\",\n \"thermal\": {\n \"ignitionC\": 290,\n \"flameC\": 750,\n \"fuelFraction\": 0.85,\n \"burnRate\": 0.014,\n \"conductivity\": 0.05,\n \"heatCapacity\": 1.2,\n \"smoke\": \"grey\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"wood\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 30000\n },\n {\n \"id\": \"glass\",\n \"density\": 2500,\n \"hpPerKg\": 12,\n \"penetration\": 6,\n \"ductility\": 0.02,\n \"fracture\": \"shatter\",\n \"fragmentSize\": [\n 0.05,\n 0.25\n ],\n \"damageScale\": {\n \"blunt\": 1.5,\n \"shelter\": 3\n },\n \"hitDebris\": \"shards\",\n \"breakDebris\": \"shards\",\n \"ricochetDeg\": 8,\n \"thermal\": {\n \"meltC\": 1400,\n \"meltRate\": 0.03,\n \"conductivity\": 0.1,\n \"heatCapacity\": 1.5,\n \"thermalShockC\": 150\n },\n \"visual\": {\n \"glows\": true,\n \"transparent\": true\n },\n \"tags\": [\n \"glass\",\n \"brittle\"\n ],\n \"compressive\": 100000\n },\n {\n \"id\": \"tempered_glass\",\n \"density\": 2500,\n \"hpPerKg\": 30,\n \"penetration\": 9,\n \"ductility\": 0.02,\n \"fracture\": \"crumble\",\n \"fragmentSize\": [\n 0.006,\n 0.02\n ],\n \"hitDebris\": \"shards\",\n \"breakDebris\": \"shards\",\n \"ricochetDeg\": 8,\n \"thermal\": {\n \"meltC\": 1400,\n \"meltRate\": 0.03,\n \"conductivity\": 0.1,\n \"heatCapacity\": 1.5,\n \"thermalShockC\": 250\n },\n \"visual\": {\n \"glows\": true,\n \"transparent\": true\n },\n \"tags\": [\n \"glass\",\n \"brittle\"\n ],\n \"compressive\": 200000,\n \"damageScale\": {\n \"shelter\": 3\n }\n },\n {\n \"id\": \"ceramic\",\n \"density\": 2400,\n \"hpPerKg\": 25,\n \"penetration\": 12,\n \"ductility\": 0.02,\n \"fracture\": \"shatter\",\n \"fragmentSize\": [\n 0.03,\n 0.12\n ],\n \"damageScale\": {\n \"blunt\": 1.3\n },\n \"hitDebris\": \"chips\",\n \"breakDebris\": \"shards\",\n \"thermal\": {\n \"conductivity\": 0.1,\n \"heatCapacity\": 1.5,\n \"thermalShockC\": 200\n },\n \"tags\": [\n \"ceramic\",\n \"brittle\"\n ],\n \"compressive\": 150000\n },\n {\n \"id\": \"concrete\",\n \"density\": 2300,\n \"hpPerKg\": 14,\n \"penetration\": 18,\n \"penetrationClass\": \"concrete\",\n \"penetrationScale\": 1,\n \"ductility\": 0.03,\n \"fracture\": \"crumble\",\n \"fragmentSize\": [\n 0.05,\n 0.25\n ],\n \"damageScale\": {\n \"explosive\": 1.2\n },\n \"hitDebris\": \"chips\",\n \"breakDebris\": \"dust\",\n \"thermal\": {\n \"conductivity\": 0.15,\n \"heatCapacity\": 2.5\n },\n \"tags\": [\n \"masonry\",\n \"brittle\"\n ],\n \"compressive\": 444000,\n \"strength\": {\n \"compressiveMPa\": 25,\n \"tensileMPa\": 2.56,\n \"elasticGPa\": 28\n }\n },\n {\n \"id\": \"brick\",\n \"density\": 1900,\n \"hpPerKg\": 12,\n \"penetration\": 14,\n \"penetrationClass\": \"brick\",\n \"penetrationScale\": 1,\n \"ductility\": 0.05,\n \"fracture\": \"crumble\",\n \"fragmentSize\": [\n 0.04,\n 0.12\n ],\n \"hitDebris\": \"chips\",\n \"breakDebris\": \"dust\",\n \"thermal\": {\n \"conductivity\": 0.15,\n \"heatCapacity\": 2.5\n },\n \"tags\": [\n \"masonry\",\n \"brittle\"\n ],\n \"compressive\": 40000,\n \"strength\": {\n \"compressiveMPa\": 2.35,\n \"tensileMPa\": 0.1,\n \"elasticGPa\": 2.35\n }\n },\n {\n \"id\": \"plaster\",\n \"density\": 850,\n \"hpPerKg\": 18,\n \"penetration\": 3,\n \"penetrationClass\": \"brick\",\n \"penetrationScale\": 3,\n \"ductility\": 0.05,\n \"fracture\": \"crumble\",\n \"fragmentSize\": [\n 0.05,\n 0.3\n ],\n \"hitDebris\": \"dust\",\n \"breakDebris\": \"dust\",\n \"thermal\": {\n \"conductivity\": 0.1,\n \"heatCapacity\": 1.5\n },\n \"tags\": [\n \"masonry\",\n \"brittle\"\n ],\n \"compressive\": 8000\n },\n {\n \"id\": \"stone\",\n \"density\": 2700,\n \"hpPerKg\": 25,\n \"penetration\": 25,\n \"penetrationClass\": \"concrete\",\n \"penetrationScale\": 0.9,\n \"ductility\": 0.03,\n \"fracture\": \"crumble\",\n \"fragmentSize\": [\n 0.06,\n 0.3\n ],\n \"hitDebris\": \"chips\",\n \"breakDebris\": \"dust\",\n \"thermal\": {\n \"conductivity\": 0.2,\n \"heatCapacity\": 2.5\n },\n \"tags\": [\n \"masonry\",\n \"brittle\"\n ],\n \"compressive\": 300000\n },\n {\n \"id\": \"plastic\",\n \"density\": 1100,\n \"hpPerKg\": 60,\n \"penetration\": 8,\n \"ductility\": 0.5,\n \"fracture\": \"snap\",\n \"fragmentSize\": [\n 0.05,\n 0.3\n ],\n \"hitDebris\": \"chips\",\n \"breakDebris\": \"chips\",\n \"thermal\": {\n \"ignitionC\": 400,\n \"flameC\": 700,\n \"fuelFraction\": 0.8,\n \"burnRate\": 0.02,\n \"meltC\": 200,\n \"meltRate\": 0.06,\n \"conductivity\": 0.05,\n \"heatCapacity\": 1,\n \"smoke\": \"black\"\n },\n \"visual\": {\n \"charColor\": 855309\n },\n \"tags\": [\n \"plastic\",\n \"flammable\"\n ],\n \"compressive\": 40000\n },\n {\n \"id\": \"rubber\",\n \"density\": 1100,\n \"hpPerKg\": 80,\n \"penetration\": 12,\n \"ductility\": 0.9,\n \"fracture\": \"tear\",\n \"fragmentSize\": [\n 0.05,\n 0.2\n ],\n \"hitDebris\": \"chips\",\n \"breakDebris\": \"fibers\",\n \"thermal\": {\n \"ignitionC\": 350,\n \"flameC\": 750,\n \"fuelFraction\": 0.6,\n \"burnRate\": 0.015,\n \"conductivity\": 0.05,\n \"heatCapacity\": 1.2,\n \"smoke\": \"black\"\n },\n \"visual\": {\n \"charColor\": 855309\n },\n \"tags\": [\n \"rubber\",\n \"flammable\"\n ],\n \"compressive\": 20000\n },\n {\n \"id\": \"fabric\",\n \"density\": 400,\n \"hpPerKg\": 20,\n \"penetration\": 0.8,\n \"ductility\": 0.8,\n \"fracture\": \"tear\",\n \"fragmentSize\": [\n 0.05,\n 0.25\n ],\n \"damageScale\": {\n \"slash\": 4,\n \"ballistic\": 0.5\n },\n \"hitDebris\": \"fibers\",\n \"breakDebris\": \"fibers\",\n \"thermal\": {\n \"ignitionC\": 230,\n \"flameC\": 600,\n \"fuelFraction\": 1,\n \"burnRate\": 0.05,\n \"conductivity\": 0.03,\n \"heatCapacity\": 0.6,\n \"smoke\": \"grey\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"fabric\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 500\n },\n {\n \"id\": \"foam\",\n \"density\": 30,\n \"hpPerKg\": 15,\n \"penetration\": 0.5,\n \"ductility\": 0.7,\n \"fracture\": \"tear\",\n \"fragmentSize\": [\n 0.03,\n 0.15\n ],\n \"damageScale\": {\n \"slash\": 2,\n \"ballistic\": 0.4\n },\n \"hitDebris\": \"fibers\",\n \"breakDebris\": \"fibers\",\n \"thermal\": {\n \"ignitionC\": 250,\n \"flameC\": 900,\n \"fuelFraction\": 0.95,\n \"burnRate\": 0.09,\n \"conductivity\": 0.02,\n \"heatCapacity\": 0.5,\n \"smoke\": \"black\"\n },\n \"visual\": {\n \"charColor\": 855309\n },\n \"tags\": [\n \"fabric\",\n \"flammable\"\n ],\n \"compressive\": 100\n },\n {\n \"id\": \"leather\",\n \"density\": 900,\n \"hpPerKg\": 50,\n \"penetration\": 4,\n \"ductility\": 0.8,\n \"fracture\": \"tear\",\n \"fragmentSize\": [\n 0.05,\n 0.25\n ],\n \"damageScale\": {\n \"slash\": 2\n },\n \"hitDebris\": \"fibers\",\n \"breakDebris\": \"fibers\",\n \"thermal\": {\n \"ignitionC\": 320,\n \"flameC\": 650,\n \"fuelFraction\": 0.7,\n \"burnRate\": 0.01,\n \"conductivity\": 0.05,\n \"heatCapacity\": 1,\n \"smoke\": \"grey\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"fabric\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 2000\n },\n {\n \"id\": \"paper\",\n \"density\": 700,\n \"hpPerKg\": 8,\n \"penetration\": 0.3,\n \"ductility\": 0.5,\n \"fracture\": \"tear\",\n \"fragmentSize\": [\n 0.03,\n 0.15\n ],\n \"damageScale\": {\n \"slash\": 3\n },\n \"hitDebris\": \"fibers\",\n \"breakDebris\": \"fibers\",\n \"thermal\": {\n \"ignitionC\": 230,\n \"flameC\": 600,\n \"fuelFraction\": 1,\n \"burnRate\": 0.06,\n \"conductivity\": 0.03,\n \"heatCapacity\": 0.5,\n \"smoke\": \"grey\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"fabric\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 500\n },\n {\n \"id\": \"foliage\",\n \"density\": 150,\n \"hpPerKg\": 20,\n \"penetration\": 0.5,\n \"ductility\": 0.6,\n \"fracture\": \"tear\",\n \"fragmentSize\": [\n 0.03,\n 0.1\n ],\n \"damageScale\": {\n \"slash\": 4\n },\n \"hitDebris\": \"leaves\",\n \"breakDebris\": \"leaves\",\n \"thermal\": {\n \"ignitionC\": 300,\n \"flameC\": 700,\n \"fuelFraction\": 0.8,\n \"burnRate\": 0.08,\n \"conductivity\": 0.03,\n \"heatCapacity\": 0.8,\n \"smoke\": \"white\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"plant\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 500\n },\n {\n \"id\": \"green_wood\",\n \"density\": 650,\n \"hpPerKg\": 5,\n \"penetration\": 10,\n \"penetrationClass\": \"wood\",\n \"penetrationScale\": 1.2,\n \"ductility\": 0.5,\n \"fracture\": \"splinter\",\n \"fragmentSize\": [\n 0.03,\n 0.2\n ],\n \"damageScale\": {\n \"slash\": 1.3,\n \"ballistic\": 0.1\n },\n \"hitDebris\": \"splinters\",\n \"breakDebris\": \"leaves\",\n \"thermal\": {\n \"ignitionC\": 400,\n \"flameC\": 700,\n \"fuelFraction\": 0.8,\n \"burnRate\": 0.006,\n \"conductivity\": 0.06,\n \"heatCapacity\": 2,\n \"smoke\": \"white\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"plant\",\n \"wood\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 60000\n },\n {\n \"id\": \"cactus\",\n \"density\": 900,\n \"hpPerKg\": 30,\n \"penetration\": 2,\n \"ductility\": 0.6,\n \"fracture\": \"tear\",\n \"fragmentSize\": [\n 0.04,\n 0.15\n ],\n \"damageScale\": {\n \"slash\": 3\n },\n \"hitDebris\": \"fibers\",\n \"breakDebris\": \"fibers\",\n \"thermal\": {\n \"ignitionC\": 450,\n \"flameC\": 650,\n \"fuelFraction\": 0.3,\n \"burnRate\": 0.01,\n \"conductivity\": 0.05,\n \"heatCapacity\": 3,\n \"smoke\": \"white\"\n },\n \"visual\": {\n \"charColor\": 1709072\n },\n \"tags\": [\n \"plant\",\n \"organic\",\n \"flammable\"\n ],\n \"compressive\": 5000\n },\n {\n \"id\": \"flesh_fruit\",\n \"density\": 950,\n \"hpPerKg\": 15,\n \"penetration\": 1.5,\n \"ductility\": 0.7,\n \"fracture\": \"tear\",\n \"fragmentSize\": [\n 0.02,\n 0.08\n ],\n \"damageScale\": {\n \"slash\": 2\n },\n \"hitDebris\": \"drips\",\n \"breakDebris\": \"drips\",\n \"thermal\": {\n \"conductivity\": 0.05,\n \"heatCapacity\": 3\n },\n \"tags\": [\n \"plant\",\n \"organic\"\n ],\n \"compressive\": 1000\n },\n {\n \"id\": \"wax\",\n \"density\": 900,\n \"hpPerKg\": 30,\n \"penetration\": 3,\n \"ductility\": 0.5,\n \"fracture\": \"snap\",\n \"fragmentSize\": [\n 0.05,\n 0.2\n ],\n \"hitDebris\": \"chips\",\n \"breakDebris\": \"chips\",\n \"thermal\": {\n \"ignitionC\": 230,\n \"flameC\": 700,\n \"fuelFraction\": 0.9,\n \"burnRate\": 0.02,\n \"meltC\": 60,\n \"meltRate\": 0.2,\n \"conductivity\": 0.05,\n \"heatCapacity\": 0.8,\n \"smoke\": \"grey\"\n },\n \"tags\": [\n \"wax\",\n \"flammable\"\n ],\n \"compressive\": 5000\n },\n {\n \"id\": \"soil\",\n \"density\": 1300,\n \"hpPerKg\": 3,\n \"penetration\": 5,\n \"ductility\": 0.3,\n \"fracture\": \"crumble\",\n \"fragmentSize\": [\n 0.03,\n 0.12\n ],\n \"hitDebris\": \"dust\",\n \"breakDebris\": \"dust\",\n \"thermal\": {\n \"conductivity\": 0.1,\n \"heatCapacity\": 2.5\n },\n \"tags\": [\n \"soil\",\n \"masonry\"\n ],\n \"compressive\": 20000\n }\n]\n","{\n \"cast iron\": \"cast_iron\",\n \"cast_iron\": \"cast_iron\",\n \"castiron\": \"cast_iron\",\n \"metal\": \"steel\",\n \"steel\": \"steel\",\n \"iron\": \"steel\",\n \"chrome\": \"steel\",\n \"alumin\": \"aluminium\",\n \"alu_\": \"aluminium\",\n \"alu-\": \"aluminium\",\n \"alu \": \"aluminium\",\n \"copper\": \"copper\",\n \"brass\": \"copper\",\n \"bronze\": \"copper\",\n \"wood\": \"wood_soft\",\n \"timber\": \"wood_soft\",\n \"plank\": \"wood_soft\",\n \"lumber\": \"wood_soft\",\n \"pine\": \"wood_soft\",\n \"hardwood\": \"wood_hard\",\n \"oak\": \"wood_hard\",\n \"plywood\": \"plywood\",\n \"mdf\": \"mdf\",\n \"chipboard\": \"mdf\",\n \"glass\": \"glass\",\n \"window\": \"glass\",\n \"mirror\": \"glass\",\n \"tempered\": \"tempered_glass\",\n \"windshield\": \"tempered_glass\",\n \"fabric\": \"fabric\",\n \"cloth\": \"fabric\",\n \"cushion\": \"fabric\",\n \"sofa\": \"fabric\",\n \"curtain\": \"fabric\",\n \"carpet\": \"fabric\",\n \"textile\": \"fabric\",\n \"canvas\": \"fabric\",\n \"foam\": \"foam\",\n \"sponge\": \"foam\",\n \"mattress\": \"foam\",\n \"leather\": \"leather\",\n \"paper\": \"paper\",\n \"cardboard\": \"paper\",\n \"leaf\": \"foliage\",\n \"leaves\": \"foliage\",\n \"foliage\": \"foliage\",\n \"bush\": \"foliage\",\n \"grass\": \"foliage\",\n \"trunk\": \"green_wood\",\n \"branch\": \"green_wood\",\n \"twig\": \"green_wood\",\n \"cactus\": \"cactus\",\n \"fruit\": \"flesh_fruit\",\n \"apple\": \"flesh_fruit\",\n \"melon\": \"flesh_fruit\",\n \"wax\": \"wax\",\n \"candle\": \"wax\",\n \"concrete\": \"concrete\",\n \"cement\": \"concrete\",\n \"brick\": \"brick\",\n \"tile\": \"ceramic\",\n \"ceramic\": \"ceramic\",\n \"porcelain\": \"ceramic\",\n \"stone\": \"stone\",\n \"rock\": \"stone\",\n \"marble\": \"stone\",\n \"plaster\": \"plaster\",\n \"drywall\": \"plaster\",\n \"gypsum\": \"plaster\",\n \"plastic\": \"plastic\",\n \"pvc\": \"plastic\",\n \"acrylic\": \"plastic\",\n \"rubber\": \"rubber\",\n \"tire\": \"rubber\",\n \"tyre\": \"rubber\",\n \"soil\": \"soil\",\n \"dirt\": \"soil\",\n \"potting\": \"soil\",\n \"mud\": \"soil\"\n}","import materialsJson from './data/materials.json'\nimport hintsJson from './data/material-hints.json'\nimport { aabbOf, quatFromEuler, shapeDims } from './math'\nimport { GRAVITY, isSlender, resolveFlexure, resolveMasonry, slendernessFactor } from './flexure'\nimport { thinAxisOf } from './layers'\nimport { rebarBars } from './rebar'\nimport type { FlexureOptions, JointKind, JointSpec, MasonryOptions, MaterialDef, MaterialId, PartShape, PartSpec, ToolKind } from './types'\n\n/** Built-in materials (data in `src/data/materials.json`). Override or extend with the `materials` option of `createDestruction`. */\nexport const MATERIALS: MaterialDef[] = materialsJson as unknown as MaterialDef[]\n\n/** Default joint strength (joint hit points), tools that undo it and seconds of tool work. */\nexport const JOINT_DEFAULTS: Record<JointKind, { strength: number; tools: ToolKind[]; seconds: number }> = {\n screw: { strength: 80, tools: ['screwdriver'], seconds: 2.5 },\n bolt: { strength: 200, tools: ['wrench'], seconds: 4 },\n nail: { strength: 60, tools: ['pry_bar', 'hammer'], seconds: 2 },\n weld: { strength: 600, tools: ['cutting_torch', 'saw'], seconds: 8 },\n glue: { strength: 50, tools: ['pry_bar', 'knife'], seconds: 3 },\n hinge: { strength: 120, tools: ['screwdriver'], seconds: 3 },\n clip: { strength: 20, tools: ['hand'], seconds: 0.6 },\n tie: { strength: 15, tools: ['knife', 'hand'], seconds: 1 },\n mortar: { strength: 400, tools: ['hammer'], seconds: 6 },\n fused: { strength: 1000, tools: [], seconds: 0 },\n stem: { strength: 40, tools: ['knife', 'saw', 'hand'], seconds: 1.5 },\n rebar: { strength: 1500, tools: ['cutting_torch', 'saw'], seconds: 20 },\n resting: { strength: 30, tools: ['hand'], seconds: 1 },\n}\n\nconst has = (m: MaterialDef, tag: string) => !!m.tags && m.tags.includes(tag)\n\n/**\n * The joint kind that fits two materials: glass is glued (clipped to plastic), soft things are tied, plants share a stem, masonry gets mortar,\n * metal is welded, wood is screwed, plastic clips. `inferJoints` refines weld to bolt for thick metal and screw to nail for thin wood.\n */\nexport const JOINT_BY_MATERIALS = (a: MaterialDef, b: MaterialDef): JointKind => {\n const any = (tag: string) => has(a, tag) || has(b, tag)\n const both = (tag: string) => has(a, tag) && has(b, tag)\n if (any('glass')) return any('plastic') ? 'clip' : 'glue'\n if (any('fabric')) return 'tie'\n if (both('plant')) return 'stem'\n if (any('plant')) return 'tie'\n if (both('masonry')) return 'mortar'\n if (any('masonry') && any('metal')) return 'bolt'\n if (both('metal')) return 'weld'\n if (any('plastic')) return 'clip'\n if (any('rubber') || any('wax')) return 'glue'\n return 'screw'\n}\n\nconst MATERIAL_MAP: ReadonlyMap<MaterialId, MaterialDef> = new Map(MATERIALS.map((m) => [m.id, m]))\n\nconst HINTS = Object.entries(hintsJson as Record<string, string>).sort((x, y) => y[0].length - x[0].length)\n\n/** Guess a material id from a mesh or node name (case-insensitive substring; the longest keyword wins). */\nexport const guessMaterial = (name: string): MaterialId | undefined => {\n const n = name.toLowerCase()\n for (const [key, id] of HINTS) if (n.includes(key)) return id\n return undefined\n}\n\n/** Volume of a shape in m³. */\nexport const partVolume = (shape: PartShape): number => {\n if (shape.kind === 'box') return shape.size[0] * shape.size[1] * shape.size[2]\n if (shape.kind === 'cylinder') return Math.PI * shape.radius * shape.radius * shape.height\n return (4 / 3) * Math.PI * shape.radius ** 3\n}\n\n/** Mass of a part in kg: its `mass`, or density × volume × fill. */\nexport const partMass = (part: PartSpec, material: MaterialDef): number => part.mass ?? material.density * partVolume(part.shape) * (part.fill ?? 1)\n\n/** Wall thickness of a part in metres (see `PartSpec.thickness`). */\nexport const partThickness = (part: PartSpec): number => {\n const dims = shapeDims(part.shape)\n const min = Math.min(dims[0], dims[1], dims[2])\n return Math.max(1e-4, Math.min(part.thickness ?? min * (part.fill ?? 1), min))\n}\n\n/**\n * Joints for touching parts. Two parts touch when their axis-aligned bounds (after rotation), grown by `tolerance` metres, overlap. The kind comes\n * from `JOINT_BY_MATERIALS`; thick metal pairs (smallest dimension of both >= 2 cm) get a `bolt` instead of a `weld`, and thin wood pairs (either\n * under 2 cm) a `nail` instead of a `screw`.\n */\nexport const inferJoints = (parts: PartSpec[], tolerance = 0.01, materials: ReadonlyMap<string, MaterialDef> = MATERIAL_MAP): JointSpec[] => {\n const boxes = parts.map((p) => aabbOf(p.shape, p.position, quatFromEuler(...(p.rotation ?? [0, 0, 0]))))\n const out: JointSpec[] = []\n for (let i = 0; i < parts.length; i++) {\n for (let j = i + 1; j < parts.length; j++) {\n const a = boxes[i], b = boxes[j]\n let touch = true\n for (let k = 0; k < 3 && touch; k++) if (a.min[k] - tolerance > b.max[k] || b.min[k] - tolerance > a.max[k]) touch = false\n if (!touch) continue\n const ma = materials.get(parts[i].material)\n const mb = materials.get(parts[j].material)\n let kind: JointKind = ma && mb ? JOINT_BY_MATERIALS(ma, mb) : 'screw'\n const thin = Math.min(partThickness(parts[i]), partThickness(parts[j]))\n if (kind === 'weld' && thin >= 0.02) kind = 'bolt'\n if (kind === 'screw' && ma && mb && has(ma, 'wood') && has(mb, 'wood') && thin < 0.02) kind = 'nail'\n out.push({ id: `${parts[i].id}~${parts[j].id}`, a: parts[i].id, b: parts[j].id, kind })\n }\n }\n return out\n}\n\n/**\n * Load in kg a structural part carries before it fails in compression: `structure.capacity`, else the section times the material's strength. The\n * section is the product of the two smallest dimensions (thickness times longest dimension for slabs; thickness times horizontal length for walls);\n * foundations get x10. With `material.strength` (real values) the strength is `compressiveMPa`: a slender masonry or plain concrete wall or pillar keeps\n * `slendernessFactor` of it (the unavoidable eccentricity and its height over thickness), a reinforced pillar carries `0.85 * fck * Ac + As * fy`\n * (NBR 6118). Without it, the game-tuned `material.compressive` (default 20 000 kg/m²).\n */\nexport const partCapacity = (part: PartSpec, material: MaterialDef, options: { masonry?: MasonryOptions; flexure?: FlexureOptions } = {}): number => {\n if (part.structure?.capacity !== undefined) return part.structure.capacity\n const d = shapeDims(part.shape).sort((a, b) => a - b)\n const role = part.structure?.role\n const sh = shapeDims(part.shape)\n const section = role === 'wall' || role === 'partition' ? Math.min(sh[0], sh[2]) * Math.max(sh[0], sh[2]) : role === 'slab' ? d[0] * d[2] : d[0] * d[1]\n const foundation = role === 'foundation' ? 10 : 1\n const strength = material.strength\n if (!strength) return Math.max(1, section * (material.compressive ?? 20000) * foundation)\n const fc = strength.compressiveMPa * 1e6\n let newtons = fc * section\n const upright = role === 'wall' || role === 'partition' || role === 'column'\n if (upright && isSlender(part, material)) newtons *= slendernessFactor(sh[1], Math.min(sh[0], sh[2]), options.masonry)\n else if (role === 'column' && part.reinforcement) {\n const m = resolveMasonry(options.masonry)\n const bars = rebarBars(sh, thinAxisOf(sh), part.reinforcement.spacing).length\n const steel = bars * Math.PI * (part.reinforcement.diameter / 2) ** 2\n newtons = m.concreteFactor * fc * section + steel * resolveFlexure(options.flexure).rebarYieldMPa * 1e6\n }\n return Math.max(1, (newtons / GRAVITY) * foundation)\n}\n\n\n/**\n * Multiplier of blunt damage on brittle parts (ductility < 0.3): up to x4.7 for fully brittle materials (glass, ceramic, stone), times a thinness\n * term that follows bending stress (1 / thickness squared, x1 at 2 cm or more, at most x25). A 3 mm glass bottle breaks from a 1.5 m drop; a\n * concrete block (thick) is only ever x4.4.\n */\nexport const fragility = (ductility: number, thickness: number): number => {\n if (ductility >= 0.3) return 1\n return (1 + (4 * (0.3 - ductility)) / 0.3) * Math.min(25, Math.max(1, (0.02 / Math.max(thickness, 1e-4)) ** 2))\n}\n","import { chainDelayOf, drawChainDelay, FIRE_PRIME_C, shotDamageFractionOf } from './chain'\nimport type { ChainTrigger } from './chain'\nimport { planFragments } from './fracture'\nimport type { PlannedFragment } from './fracture'\nimport { cellsOutside, cellsWithin, marksInBox, planeAxes, unitGrid } from './breach'\nimport type { LocalHole, UnitCell } from './breach'\nimport { layersEnergy, layersThickness, MAX_SPALLS, outerLayer, resolveLayer, thinAxisOf } from './layers'\nimport type { LayerRT } from './layers'\nimport { clipBarsToDisc, rebarBars, rebarMass } from './rebar'\nimport {\n GRAVITY, bendGeometry, blastImpulse, isReinforced, elasticEnergy, impulseEnergy, isFlexural, lineLoad, momentOfEnergy, resolveFlexure, resolveMasonry, sectionMoments, sectionWidth,\n spanMoment, spanOf, tensionSteel,\n} from './flexure'\nimport type { BendGeometry } from './flexure'\nimport { footingSoil, pileCapacity, pileStiffness, profileOf, resolveSoil, soilAt, solveFoundation, stiffnessCentre, subgradeModulus, yieldSprings } from './soil'\nimport type { SoilSpring } from './soil'\nimport { analyzeWind, damperTuning, exposureOf, gustAt, makeGust, meanHeightFactor, resolveWind, shapeAt, stepSway, tensionCapacity } from './wind'\nimport type { Gust, ResolvedWind, SwayState, SwaySystem, WindAnalysis, WindCase, WindPartInput } from './wind'\nimport { JOINT_DEFAULTS, inferJoints, MATERIALS, partCapacity, partMass, partThickness, partVolume, fragility } from './materials'\nimport { aabbOf, createRng, distanceToShape, quat, quatFromEuler, rayShape, rotateVec, shapeArea, shapeBound, shapeDims, surfacePoint, toLocal, toWorld, vec } from './math'\nimport type { DestructibleImpl } from './contracts'\nimport type {\n AddOptions, Crack, DamageType, DebrisKind, DestructibleSpec, Dent, DestructionEvent, DestructionEventType, DestructionOptions, DestructionSnapshot,\n DamageStage, DestructionWorld, Fragment, FractureStyle, Hit, HitResult, Hole, JointSpec, JointState, MaterialDef, MaterialId, ObjectRuntime, ObjectState, PartRuntime, PartSpec,\n PartState, Quat, RayHit, ToolKind, Vec3, SoilProfile, SoilState, WindOptions, WindState,\n BlastOptions, BlastReport, ConfinementOptions, FragmentHitOptions, ShelterOptions,\n BallisticExtras,\n} from './types'\nimport { ignitionChance, resolveIgnitionRules, sparkTargetFactor } from '@adatechnology/game-contracts'\n\n/** Hit points removed per joule (before the material's `damageScale`). */\n/** Metres: a ductile part this thin or thinner dishes around a bullet hole. */\nconst THIN_SHEET_DISHING = 0.005\nconst DMG_PER_J = 0.02\n/** Fraction of a blast's energy that reaches a part at distance 0. */\nconst BLAST_COUPLING = 0.1\n/**\n * Blast options (all off until asked for). Shelter: a part the line from the blast to the target crosses lets through `exp(-r / k)`, `r` being the\n * hit points of the slab it crosses per square metre (`hpPerKg * density * path * damageScale.shelter`). Fragment hits: up to 24 fragments, half their\n * kinetic energy lands as a blunt hit, thrown at most 6 m (and `speed * 0.4 s`) within 10 degrees of their aim. Confinement: 26 rays reaching\n * `1.5 * radius`, multiplier `1 + 1.5 * closedShare^2 * clamp(radius / meanDistance, 0, 2)` up to 3.\n */\nexport const SHELTER_DEFAULTS: Required<ShelterOptions> = { k: 2800, brokenTransmission: 0.5, minPath: 0.005 }\nexport const FRAGMENT_HIT_DEFAULTS: Required<FragmentHitOptions> = { max: 24, energyFactor: 0.5, hitType: 'blunt', range: 6, flightTime: 0.4, spread: 10, aim: 40 }\nexport const CONFINEMENT_DEFAULTS: Required<ConfinementOptions> = { rays: 26, reach: 1.5, gain: 1.5, power: 2, max: 3 }\nconst FLAMMABLE_FLUIDS = ['gas', 'fuel']\n/** Diameter in metres of the opening `vent` makes when none is given: a cylinder valve (about 8 mm). */\nconst VENT_DIAMETER = 0.008\n/** A flame lights a flammable leak when it reaches this temperature (the auto-ignition of propane in air is about 470 °C; a lighter flame is above 1000 °C). */\nconst FLAME_LIGHTS_LEAK_C = 470\n/** Staged parts: default breach radius (m), blast multiplier on the breach area, area a part must lose to open (m²), and the share of capacity the bare cage keeps. */\nconst BREACH_RADIUS = 0.55\nconst BREACH_BLAST_FACTOR = 6\nconst BREACH_AREA = 0.25\n/** Metres of reach per cube root of kilojoule for a blast to open a breach. */\nconst BREACH_BLAST_REACH = 0.12\nconst RESIDUAL_CAPACITY = 0.15\n/** Metres two parts may be apart and still rest on each other, for the span of a beam or a slab. */\nconst SUPPORT_TOLERANCE = 0.05\n/** Unit-sized fragments of a whole wall: at most this many times `maxFragments`. A breach picks its units from a grid of up to `BREACH_GRID_CAP`. */\nconst UNIT_FRAGMENT_FACTOR = 4\nconst BREACH_GRID_CAP = 4096\n\n/** A cut only goes through a slice of the part, so a part longer than `CUT_SLICE` costs no more to cut than a 1 m piece of the same section. */\nconst CUT_SLICE = 1\nconst cutFactorOf = (shape: PartSpec['shape']): number => clamp(Math.max(...shapeDims(shape)) / CUT_SLICE, 1, 50)\n\ninterface PartRT {\n spec: PartSpec\n mat: MaterialDef\n st: PartState\n q: Quat\n /** Current object-local position (the spec's, unless moved by `setPartPose`). */\n pos: Vec3\n mass0: number\n fuel0: number\n area: number\n thickness: number\n /** Slash damage multiplier: longest dimension / 1 m (1..50). */\n cutFactor: number\n dims: Vec3\n bound: number\n rt: PartRuntime\n /** Structural role other than `none`. */\n structural: boolean\n anchored: boolean\n cap: number\n /** Structural part that never had a support path (the spec itself leaves it floating): it is held by its joints like a non-structural part and does not collapse by itself. */\n orphan: boolean\n /** The part has layers, units, reinforcement or a breach: it goes through damage stages. */\n staged: boolean\n /** Axis the part is thinnest along (the wall's depth). */\n thin: number\n layers: LayerRT[]\n /** Bending geometry, for parts in the bending model (`structure.flexure`). */\n bend?: BendGeometry\n /** Span in metres between the supports it rests on now (0: it rests along its whole length, or on nothing). */\n span: number\n /** Supports the span was measured for (indices joined), to measure it again only when they change. */\n spanKey: string\n /** Moment at rest in N m of the section that bends under its weight. */\n restMoment: number\n /** Load in kg that bends it: its own mass and what rests on it away from its supports. */\n bendLoad: number\n /** Overloaded in bending without steel that holds: when it fails it snaps in two instead of crumbling. */\n snap: boolean\n}\n\ninterface JointRT {\n spec: Required<JointSpec>\n st: JointState\n ia: number\n ib: number\n bears: boolean | 'a_on_b' | 'b_on_a'\n /** Object-local position. */\n pos: Vec3\n step: number\n}\n\ninterface ObjRT {\n id: string\n spec: DestructibleSpec\n st: ObjectState\n parts: PartRT[]\n byId: Map<string, PartRT>\n idx: Map<string, number>\n joints: JointRT[]\n jointMap: Map<string, JointRT>\n byPart: Map<string, JointRT[]>\n /** Local bounding sphere. */\n bc: Vec3\n br: number\n active: boolean\n tmp: number[]\n hasStructure: boolean\n /** Set only while `build` solves the structure for the first time. */\n seeding?: boolean\n dirty: boolean\n maxStress: number\n collapsed: Set<string>\n /** Structural parts with no support path to an anchored part (they fall). */\n unsup: boolean[]\n anyAnchor: boolean\n /** Creation order of the object in this world: breaks ties between parts that go off at the same time. */\n order: number\n /** The pose the host gave (`add`, `setTransform`); `st.position`/`st.rotation` are this with the soil's settlement and tilt on top. */\n base: { pos: Vec3; rot: Quat }\n /** The ground under the object (`DestructibleSpec.soil`), when it has foundations on it. */\n soil?: SoilRT\n /** The wind on the object (`DestructionOptions.wind`), when the world has wind and the object is a structure. */\n wind?: WindRT\n}\n\ninterface WindRT {\n /** The wind of the world with this object's `DestructibleSpec.wind` over it, as of the last analysis. */\n cfg: ResolvedWind\n gust: Gust\n /** What the gust was made for (speed, terrain), to make it again when the wind changes. */\n gustKey: string\n analysis: WindAnalysis | null\n /** Parts of the object that went into the analysis, by input index. */\n parts: number[]\n sys: SwaySystem | null\n /** Mass ratio of the damper and its modal weight in the system (0 without one). */\n mu: number\n dyn: SwayState & { peak: number }\n /** Tension capacity of each wall and column, by part index. */\n tension: Map<number, number>\n /** Time and values of the last `sway` event. */\n emitted: { t: number; peak: number; status: WindState['status'] }\n}\n\ninterface SoilRT {\n profile: SoilProfile\n s: number\n a: number\n b: number\n /** Out-of-plumb of the building, as slopes along x and z. */\n imp: [number, number]\n /** Pivot of the tilt: the centre of stiffness at the level of the base, object-local. */\n pivot: Vec3\n /** The structure changed since the soil was last solved. */\n dirty: boolean\n /** Permanent settlement of the soil under each spring (by `SoilSpring` key) from yielding. */\n sets: Map<string, number>\n /** Time and values of the last `settle` event. */\n emitted: { t: number; s: number; tilt: number; status: SoilState['status'] }\n}\n\ninterface Carry {\n parts: Map<string, { st: PartState; rt: PartRuntime }>\n joints: Map<string, { st: JointState; step: number }>\n collapsed?: string[]\n soil?: SoilState\n soilSets?: Record<string, number>\n wind?: [number, number, number, number, number]\n}\n\n\ninterface Loc {\n p: PartRT\n point: Vec3\n normal: Vec3\n dir: Vec3\n pathLen: number\n}\n\ninterface ImplRT {\n impl: DestructibleImpl\n position: Vec3\n rotation: Quat\n /** Part pose overrides set by `setPartPose` (object-local). */\n poses: Map<string, { pos: Vec3; q: Quat }>\n}\n\ninterface Blast {\n point: Vec3\n energy: number\n radius: number\n lethalRadius?: number\n source?: string\n}\n\nconst clamp = (v: number, a: number, b: number) => Math.max(a, Math.min(b, v))\n/** Millimetres of this material a round goes through: the entry of `Hit.penetration` for its `penetrationClass` (else its id) times the material's `penetrationScale`; undefined when the round has none. */\nconst penetrationOf = (mat: MaterialDef, table: Readonly<Record<string, number>> | undefined): number | undefined => {\n if (!table) return undefined\n const v = table[mat.penetrationClass ?? mat.id] ?? table[mat.id]\n return v === undefined ? undefined : v * (mat.penetrationScale ?? 1)\n}\n/** Share of its capacity a structural part still has: a bare rebar cage keeps the reinforcement's residual, a breached part loses what left it. */\nconst capacityScale = (p: PartRT): number => {\n if (p.st.stripped) return p.spec.reinforcement?.residualCapacity ?? RESIDUAL_CAPACITY\n return p.rt.removed ? Math.max(0.05, 1 - p.rt.removed / p.mass0) : 1\n}\nconst isLost = (p: PartRT) => p.st.status === 'broken' || p.st.status === 'melted' || p.st.status === 'ashes'\nconst clone = <T>(v: T): T => structuredClone(v)\n/**\n * Fraction of a structural part's hit points lost per second while its stress is above 1. A floor of 0.12 makes even a barely overloaded part\n * give way in about 8 s (a rate proportional to the excess alone never finishes: stress 1.02 would take two minutes), then it grows with the\n * excess and tops out at 0.6: stress 1.1 fails in ~4.5 s, 1.5 in ~1.9 s and anything above 1.7 in ~1.7 s. Deterministic: depends only on stress.\n */\nconst overloadRate = (stress: number) => Math.min(0.6, 0.12 + 0.8 * (stress - 1))\nconst updateBound = (o: ObjRT) => {\n if (!o.parts.length) return\n const c: Vec3 = [0, 0, 0]\n for (const p of o.parts) for (let k = 0; k < 3; k++) c[k] += p.pos[k] / o.parts.length\n let r = 0\n for (const p of o.parts) r = Math.max(r, vec.distance(c, p.pos) + p.bound)\n o.bc = c\n o.br = r\n}\nconst AXIS = { x: 0, y: 1, z: 2 } as const\n\nexport const createDestruction = (options: DestructionOptions = {}): DestructionWorld => {\n const materials = new Map<MaterialId, MaterialDef>()\n for (const m of MATERIALS) materials.set(m.id, m)\n for (const m of options.materials ?? []) materials.set(m.id, m)\n const ambient = options.ambientC ?? 20\n const maxFragments = options.maxFragments ?? 24\n const maxDents = options.maxDents ?? 24\n const maxHoles = options.maxHoles ?? 32\n const fireSpread = options.fireSpread ?? 0.6\n const breachRadius = options.breach?.radius ?? BREACH_RADIUS\n const structureSafety = options.structure?.safetyFactor ?? 1\n const flexure = resolveFlexure(options.structure?.flexure)\n const masonry = resolveMasonry(options.structure?.masonry)\n const soilCfg = resolveSoil(options.soil)\n let windOpts: WindOptions | undefined = options.wind\n let windCfg: ResolvedWind | null = windOpts ? resolveWind(windOpts) : null\n const ignitionRules = resolveIgnitionRules(options.ignition)\n const breachBlastFactor = options.breach?.blastFactor ?? BREACH_BLAST_FACTOR\n const rng = createRng(options.seed ?? 1)\n const rnd = () => rng.next()\n\n let time = 0\n let counter = 0\n const objects = new Map<string, ObjRT>()\n const listeners = new Map<string, Set<(e: DestructionEvent) => void>>()\n let cur: DestructionEvent[] = []\n const blasts: Blast[] = []\n /** Glass the blast front has not reached yet: the damage lands when it does (`blastFrontSpeed`). */\n const frontQueue: Array<{ o: ObjRT; p: PartRT; due: number; amount: number; fragEnergy: number; point: Vec3; src?: string }> = []\n const blastFrontSpeed = options.blastFrontSpeed ?? 0\n /** Explosive parts that were primed and wait for their delay. */\n const primed = new Map<PartRT, ObjRT>()\n let orderCounter = 0\n const impls = new Map<string, ImplRT>()\n const taken = (id: string) => objects.has(id) || impls.has(id)\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Events\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n const emit = (e: DestructionEvent) => {\n cur.push(e)\n options.onEvent?.(e)\n const all = listeners.get('*')\n if (all) for (const fn of [...all]) fn(e)\n const typed = listeners.get(e.type)\n if (typed) for (const fn of [...typed]) fn(e)\n }\n const base = (o: ObjRT, source?: string): { object: string; time: number; source?: string } =>\n source === undefined ? { object: o.id, time } : { object: o.id, time, source }\n\n const pendingCollapse = new Map<ObjRT, string | undefined>()\n let runDepth = 0\n\n /** Blasts queued by parts that exploded; each can prime or set off more parts. It ends: a part goes off once and is primed once, so the queue only grows by parts not yet lost. */\n const drainBlasts = () => {\n for (let blast = blasts.shift(); blast; blast = blasts.shift()) blastWorld(blast.point, blast.energy, blast.radius, blast.source, undefined, undefined, blast.lethalRadius)\n }\n\n const run = <T>(fn: () => T): { value: T; events: DestructionEvent[] } => {\n const prev = cur\n const mine: DestructionEvent[] = []\n cur = mine\n runDepth++\n try {\n const value = fn()\n drainBlasts()\n if (runDepth === 1) flushCollapse()\n return { value, events: mine }\n } finally {\n runDepth--\n cur = prev\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Building objects\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n const nextId = () => {\n let id: string\n do id = `obj_${++counter}`\n while (taken(id))\n return id\n }\n\n const freshRuntime = (): PartRuntime => ({ meltEmitted: 0, dripT: 0, prevTemp: ambient, shockT: 0, jet: false })\n\n const resolveSpec = (spec: DestructibleSpec): DestructibleSpec => {\n const out = clone(spec)\n const joints = out.joints ?? inferJoints(out.parts, 0.01, materials)\n const structural = (id: string) => {\n const role = out.parts.find((p) => p.id === id)?.structure?.role\n return role !== undefined && role !== 'none'\n }\n out.joints = joints.map((j) => {\n const def = JOINT_DEFAULTS[j.kind]\n return {\n id: j.id ?? `${j.a}~${j.b}`, a: j.a, b: j.b, kind: j.kind, strength: j.strength ?? def.strength, tools: j.tools ?? [...def.tools], seconds: j.seconds ?? def.seconds,\n bears: j.bears ?? (structural(j.a) && structural(j.b)),\n }\n })\n return out\n }\n\n const build = (spec: DestructibleSpec, id: string, pos: Vec3, rot: Quat, carry?: Carry): ObjRT => {\n const st: ObjectState = { id, position: [pos[0], pos[1], pos[2]], rotation: [rot[0], rot[1], rot[2], rot[3]], parts: [], joints: [], groups: [], destroyed: false }\n if (spec.name !== undefined) st.name = spec.name\n const o: ObjRT = {\n id, spec, st, parts: [], byId: new Map(), idx: new Map(), joints: [], jointMap: new Map(), byPart: new Map(), bc: [0, 0, 0], br: 0, active: false, tmp: [], hasStructure: false, dirty: false, maxStress: 0, collapsed: new Set(carry?.collapsed ?? []), unsup: [], anyAnchor: false, order: ++orderCounter,\n base: { pos: [pos[0], pos[1], pos[2]], rot: [rot[0], rot[1], rot[2], rot[3]] },\n }\n for (const ps of spec.parts) {\n if (o.byId.has(ps.id)) throw new Error(`duplicate part id \"${ps.id}\"`)\n const mat = materials.get(ps.material)\n if (!mat) throw new Error(`unknown material \"${ps.material}\" on part \"${ps.id}\"`)\n const mass0 = partMass(ps, mat)\n const maxHp = Math.max(1, ps.hp ?? mass0 * mat.hpPerKg)\n const fuel0 = mat.thermal.ignitionC !== undefined ? mass0 * (mat.thermal.fuelFraction ?? 0) : 0\n const c = carry?.parts.get(ps.id)\n const staged = !!(ps.layers?.length || ps.reinforcement || ps.units || ps.breach)\n const layers = (ps.layers ?? []).map((l, i) => {\n const lm = materials.get(l.material)\n if (!lm) throw new Error(`unknown material \"${l.material}\" on layer ${i} of part \"${ps.id}\"`)\n return resolveLayer(l, i, lm)\n })\n if (ps.reinforcement && !materials.has(ps.reinforcement.material)) throw new Error(`unknown material \"${ps.reinforcement.material}\" on the reinforcement of part \"${ps.id}\"`)\n const pst: PartState = c?.st ?? {\n id: ps.id, material: ps.material, status: 'intact', hp: maxHp, maxHp, mass: mass0, temperature: ambient, burning: false, fuel: fuel0, char: 0, melt: 0,\n dents: [], holes: [], cracks: [], group: 0, ...(staged ? { stage: 0 as DamageStage } : {}),\n }\n if (!c && ps.contains) pst.liters = ps.contains.liters\n const p: PartRT = {\n spec: ps, mat, st: pst, q: quatFromEuler(...(ps.rotation ?? [0, 0, 0])), pos: [ps.position[0], ps.position[1], ps.position[2]], mass0, fuel0, area: shapeArea(ps.shape), thickness: partThickness(ps), cutFactor: cutFactorOf(ps.shape),\n dims: shapeDims(ps.shape), bound: shapeBound(ps.shape), rt: c?.rt ?? { ...freshRuntime(), prevTemp: pst.temperature },\n structural: !!ps.structure && ps.structure.role !== 'none', anchored: !!ps.anchored || ps.structure?.role === 'foundation', cap: ps.structure ? partCapacity(ps, mat, { masonry, flexure }) : 0, orphan: false,\n staged, thin: thinAxisOf(shapeDims(ps.shape)), layers, span: 0, spanKey: '', restMoment: 0, bendLoad: 0, snap: false,\n ...(ps.shape.kind === 'box' && isFlexural(ps, mat, flexure) ? { bend: bendGeometry(ps) } : {}),\n }\n if (p.structural) o.hasStructure = true\n if (p.rt.chainDue !== undefined && !isLost(p)) primed.set(p, o)\n o.idx.set(ps.id, o.parts.length)\n o.parts.push(p)\n o.byId.set(ps.id, p)\n o.st.parts.push(pst)\n o.byPart.set(ps.id, [])\n }\n for (const js of spec.joints ?? []) {\n const r = js as Required<JointSpec>\n const ia = o.idx.get(r.a), ib = o.idx.get(r.b)\n if (ia === undefined || ib === undefined) throw new Error(`joint \"${r.id}\" references an unknown part`)\n if (o.jointMap.has(r.id)) throw new Error(`duplicate joint id \"${r.id}\"`)\n const pa = o.parts[ia], pb = o.parts[ib]\n const A = aabbOf(pa.spec.shape, pa.spec.position, pa.q)\n const B = aabbOf(pb.spec.shape, pb.spec.position, pb.q)\n const pos: Vec3 = [0, 0, 0]\n for (let k = 0; k < 3; k++) pos[k] = (Math.max(A.min[k], B.min[k]) + Math.min(A.max[k], B.max[k])) / 2\n const bears: JointRT['bears'] = r.bears ?? (pa.structural && pb.structural)\n const c = carry?.joints.get(r.id)\n const jst: JointState = c?.st ?? { id: r.id, a: r.a, b: r.b, kind: r.kind, hp: r.strength, maxHp: r.strength, progress: 0, open: false }\n const j: JointRT = { spec: r, st: jst, ia, ib, bears, pos, step: c?.step ?? 0 }\n o.joints.push(j)\n o.jointMap.set(r.id, j)\n o.byPart.get(r.a)!.push(j)\n o.byPart.get(r.b)!.push(j)\n o.st.joints.push(jst)\n }\n // open joints whose parts are no longer both here (left behind by `splitGroup`) stay listed, inert, so callers still see them open\n for (const [jid, c] of carry?.joints ?? []) if (c.st.open && !o.jointMap.has(jid)) o.st.joints.push(c.st)\n updateBound(o)\n o.anyAnchor = o.parts.some((p) => p.anchored)\n o.unsup = o.parts.map(() => false)\n if (windCfg && o.hasStructure && spec.wind !== false) o.wind = newWind(o, carry?.wind)\n const ground = spec.soil ?? soilCfg.site\n if (ground !== undefined && o.parts.some((p) => p.spec.structure?.role === 'foundation')) initSoil(o, profileOf(ground), carry?.soil, carry?.soilSets)\n o.seeding = true\n solveStructure(o)\n o.seeding = false\n if (o.soil && !carry?.soil) settleSoil(o, 0)\n if (o.soil) o.soil.dirty = false\n recomputeGroups(o)\n o.st.destroyed = o.parts.length > 0 && o.parts.every(isLost)\n o.active = o.maxStress > 0.8 || o.parts.some((p) => p.st.burning || p.st.temperature > ambient + 0.5 || (p.st.liters ?? 0) > 0)\n return o\n }\n\n const recomputeGroups = (o: ObjRT) => {\n const n = o.parts.length\n const parent = Array.from({ length: n }, (_, i) => i)\n const find = (i: number): number => {\n while (parent[i] !== i) {\n parent[i] = parent[parent[i]]\n i = parent[i]\n }\n return i\n }\n const union = (a: number, b: number) => {\n parent[find(a)] = find(b)\n }\n const live = (j: JointRT) => !j.st.open && !isLost(o.parts[j.ia]) && !isLost(o.parts[j.ib])\n if (o.unsup.some(Boolean)) {\n // parts that lost every support fall: cut them from the supported pieces; loose non-structural parts follow the part they hang on\n for (const j of o.joints) if (live(j) && !o.unsup[j.ia] && !o.unsup[j.ib]) union(j.ia, j.ib)\n const supported = new Set<number>()\n for (let i = 0; i < n; i++) if (!isLost(o.parts[i]) && !o.unsup[i] && (o.parts[i].structural || o.parts[i].anchored)) supported.add(find(i))\n for (const j of o.joints) {\n if (!live(j) || !(o.unsup[j.ia] || o.unsup[j.ib])) continue\n if (o.unsup[j.ia] && o.unsup[j.ib]) union(j.ia, j.ib)\n else {\n const u = o.unsup[j.ia] ? j.ia : j.ib\n const other = u === j.ia ? j.ib : j.ia\n if (!o.parts[other].structural && !supported.has(find(other))) union(u, other)\n }\n }\n } else for (const j of o.joints) if (live(j)) union(j.ia, j.ib)\n const comps = new Map<number, number[]>()\n for (let i = 0; i < n; i++) {\n if (isLost(o.parts[i])) continue\n const r = find(i)\n const l = comps.get(r)\n if (l) l.push(i)\n else comps.set(r, [i])\n }\n const list = [...comps.values()].map((ix) => ({\n ix,\n anchored: ix.some((i) => o.parts[i].anchored),\n mass: ix.reduce((s, i) => s + o.parts[i].st.mass, 0),\n }))\n list.sort((a, b) => (a.anchored === b.anchored ? (b.mass - a.mass) || (a.ix[0] - b.ix[0]) : a.anchored ? -1 : 1))\n o.st.groups = list.map((g) => g.ix.map((i) => o.parts[i].spec.id))\n for (const p of o.parts) if (isLost(p)) p.st.group = -1\n list.forEach((g, gi) => g.ix.forEach((i) => (o.parts[i].st.group = gi)))\n }\n\n /**\n * Which part `r` rests on over joint `j` (index), or -1 when the joint does not let `r` rest on its other end. A `tie` is a rope: it only pulls,\n * so it holds `r` up only when `r` hangs below the part it is tied to (a lamp from a ceiling), never when that part is beside or under it\n * (a guy rope to a stake in the ground).\n */\n const restsOn = (o: ObjRT, j: JointRT, r: number): number => {\n const b = j.bears\n if (!b) return -1\n const k = b === true ? (j.ia === r ? j.ib : j.ia) : b === 'a_on_b' ? (j.ia === r ? j.ib : -1) : j.ib === r ? j.ia : -1\n if (k < 0 || j.spec.kind !== 'tie') return k\n return partXf(o, o.parts[k]).c[1] > partXf(o, o.parts[r]).c[1] + 1e-6 ? k : -1\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Bending (`structure.flexure`): span from the supports, moment at rest, blast impulse on the span\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n /** Where `p` touches `support`, as a box in `p`'s own axes. */\n const contactBox = (p: PartRT, support: PartRT): [Vec3, Vec3] => {\n const A = aabbOf(p.spec.shape, p.pos, p.q), B = aabbOf(support.spec.shape, support.pos, support.q)\n const lo: Vec3 = [0, 0, 0], hi: Vec3 = [0, 0, 0]\n for (let k = 0; k < 3; k++) {\n const a = Math.max(A.min[k], B.min[k]) - SUPPORT_TOLERANCE, b = Math.min(A.max[k], B.max[k]) + SUPPORT_TOLERANCE\n lo[k] = Math.min(a, b)\n hi[k] = Math.max(a, b)\n }\n const out: [Vec3, Vec3] = [[Infinity, Infinity, Infinity], [-Infinity, -Infinity, -Infinity]]\n for (let c = 0; c < 8; c++) {\n const l = toLocal(p.pos, p.q, [c & 1 ? hi[0] : lo[0], c & 2 ? hi[1] : lo[1], c & 4 ? hi[2] : lo[2]])\n for (let k = 0; k < 3; k++) {\n out[0][k] = Math.min(out[0][k], l[k])\n out[1][k] = Math.max(out[1][k], l[k])\n }\n }\n return out\n }\n\n /** The centre of where `above` touches `p`, in object space. */\n const contactCentre = (p: PartRT, above: PartRT): Vec3 => {\n const [lo, hi] = contactBox(p, above)\n return toWorld(p.pos, p.q, [(lo[0] + hi[0]) / 2, (lo[1] + hi[1]) / 2, (lo[2] + hi[2]) / 2])\n }\n\n /**\n * The support of `p` (index into the object's parts, among `lower`) that a load standing at `at` (object space) is over: within one depth of `p` of\n * where `p` rests on it, so the load goes straight down by a strut instead of bending `p` (a load that near a support is not carried in bending,\n * EN 1992-1-1 6.2.2(6)). -1 when it is over none.\n */\n const overSupportAt = (o: ObjRT, p: PartRT, at: Vec3, lower: readonly number[]): number => {\n const g = p.bend!\n const local = toLocal(p.pos, p.q, at)\n const depth = g.gravity >= 0 ? g.dims[g.gravity] : Math.min(...g.depthAxes.map((a) => g.dims[a]))\n let best = -1\n let bestGap = depth\n for (const k of lower) {\n const [a, b] = contactBox(p, o.parts[k])\n let gap = 0\n for (const ax of g.spanAxes) gap = Math.max(gap, a[ax] - local[ax], local[ax] - b[ax])\n if (gap <= bestGap) {\n best = k\n bestGap = gap - 1e-9\n }\n }\n return best\n }\n\n /** The section of `p` that bends along `axis`, with its tension steel and moments (a bare cage keeps only the steel's residual). */\n const sectionOf = (p: PartRT, axis: number) => {\n const g = p.bend!\n const section = { b: sectionWidth(g, axis), h: g.dims[axis] }\n const rebar = tensionSteel(p.spec, g.dims, section, flexure)\n return { section, rebar, ...sectionMoments(p.mat, section, rebar, flexure) }\n }\n\n /** Moment at rest over the moment the section holds, for the supports `lower` (indices) `p` rests on now. Sets `p.span` and `p.restMoment`. */\n const restFlexure = (o: ObjRT, p: PartRT, lower: readonly number[]): number => {\n const g = p.bend!\n const key = lower.join(',')\n if (key !== p.spanKey) {\n p.spanKey = key\n p.span = spanOf(g, lower.map((k) => contactBox(p, o.parts[k])))\n }\n p.restMoment = 0\n if (g.gravity < 0 || p.span <= 0) return 0\n const sec = sectionOf(p, g.gravity)\n p.restMoment = spanMoment(lineLoad(g, p.bendLoad) * Math.abs(g.up[g.gravity]), p.span)\n // once the tension face has cracked only the steel holds; a bare cage keeps its residual share\n const holds = (p.st.cracked ? sec.steel : sec.ultimate) * capacityScale(p)\n return (p.restMoment * structureSafety) / Math.max(holds, 1)\n }\n\n /**\n * A blast bends a beam or a slab: the reflected impulse over the span (`blastImpulse`, averaged over points of the face that takes it) gives the\n * span kinetic energy (`impulseEnergy`), which it takes as strain energy up to a peak moment (`momentOfEnergy`), added to or taken from the moment at\n * rest when the blast pushes along the weight. Past the cracking moment the tension face cracks; a section whose steel does not hold more than that\n * snaps; a reinforced one yields and fails when its plastic rotation (`(U(M) - U(Mu)) / (2 Mu)` per blast, added up) reaches `failRotationDeg`.\n */\n const bendByBlast = (o: ObjRT, p: PartRT, point: Vec3, energy: number, radius: number, reach: number, src?: string) => {\n const g = p.bend\n if (!g || p.span <= 0 || isLost(p) || p.st.stripped || reach <= 0) return\n const s = p.mat.strength!\n if (!s.elasticGPa) return\n const { c, q } = partXf(o, p)\n const near = surfacePoint(p.spec.shape, toLocal(c, q, point))\n const local = toLocal(c, q, point)\n const away = vec.normalize(vec.sub(near.point, local), vec.scale(near.normal, -1))\n let axis = g.depthAxes[0]!\n for (const a of g.depthAxes) if (Math.abs(away[a]) > Math.abs(away[axis])) axis = a\n const cos = Math.abs(away[axis])\n if (cos < 1e-3) return\n const tnt = energy / flexure.tntJoules\n const L = p.span\n const offsets = g.member ? [[-0.5], [-0.25], [0], [0.25], [0.5]] : [[0, 0], [-0.25, 0], [0.25, 0], [0, -0.25], [0, 0.25]]\n const face = -Math.sign(away[axis]) * g.dims[axis] / 2\n let sum = 0\n for (const off of offsets) {\n const sp: Vec3 = [near.point[0], near.point[1], near.point[2]]\n g.spanAxes.forEach((a, k) => (sp[a] = Math.max(-g.dims[a] / 2, Math.min(g.dims[a] / 2, sp[a] + off[k]! * L))))\n sp[axis] = face\n const r = vec.distance(toWorld(c, q, sp), point)\n if (r < radius) sum += blastImpulse(tnt, r, flexure)\n }\n const width = sectionWidth(g, axis)\n const impulse = (sum / offsets.length) * cos * reach * width * L\n const weight = axis === g.gravity ? p.bendLoad : p.st.mass\n const kinetic = impulseEnergy(impulse, (lineLoad(g, weight) / GRAVITY) * L, flexure)\n const sec = sectionOf(p, axis)\n const EI = (s.elasticGPa * 1e9 * sec.section.b * sec.section.h ** 3) / 12\n const along = axis === g.gravity ? -Math.sign(away[axis] * g.up[axis]) : 0\n const dynamic = momentOfEnergy(kinetic, L, EI, flexure.loadFactor)\n const peak = Math.abs(dynamic + along * p.restMoment)\n if (peak <= sec.cracking) return\n if (!p.st.cracked) {\n p.st.cracked = true\n const tension: Vec3 = [near.point[0], near.point[1], near.point[2]]\n tension[axis] = dynamic + along * p.restMoment >= 0 ? -face : face\n const n: Vec3 = [0, 0, 0]\n n[axis] = Math.sign(tension[axis]) || 1\n addCrack(o, p, toWorld(c, q, tension), rotateVec(q, n), sec.section.b, src)\n }\n if (!sec.reinforced) {\n p.snap = true\n failPart(o, p, point, away, kinetic, 12, src, 'snap')\n return\n }\n // a lightly reinforced section (its steel holds less than the concrete did) now carries only what the steel gives\n solveStructure(o)\n if (peak <= sec.steel) return\n const rotation = (elasticEnergy(peak, L, EI, flexure.loadFactor) - elasticEnergy(sec.steel, L, EI, flexure.loadFactor)) / (2 * sec.steel)\n p.rt.hinge = (p.rt.hinge ?? 0) + rotation\n markDamaged(p)\n if (p.rt.hinge >= (flexure.failRotationDeg * Math.PI) / 180) hingeDrop(o, p, src)\n }\n\n /** Distribute own mass plus carried load down the bearing graph to the anchored parts; mark parts without any support path. */\n const solveStructure = (o: ObjRT) => {\n o.maxStress = 0\n if (!o.hasStructure) return\n const parts = o.parts\n const n = parts.length\n const dist = new Array<number>(n).fill(-1)\n const queue: number[] = []\n const ok = (i: number) => parts[i].structural && !isLost(parts[i])\n const isPartition = (i: number) => parts[i].spec.structure?.role === 'partition'\n for (let i = 0; i < n; i++) if (ok(i) && parts[i].anchored) {\n dist[i] = 0\n queue.push(i)\n }\n for (let h = 0; h < queue.length; h++) {\n const s = queue[h]\n if (isPartition(s)) continue\n for (const j of o.byPart.get(parts[s].spec.id)!) {\n if (j.st.open || !j.bears) continue\n const r = j.ia === s ? j.ib : j.ia\n if (dist[r] >= 0 || !ok(r) || restsOn(o, j, r) !== s) continue\n dist[r] = dist[s] + 1\n queue.push(r)\n }\n }\n const incoming = new Array<number>(n).fill(0)\n const lowerOf = new Map<number, number[]>()\n for (const i of queue) {\n const lower: number[] = []\n for (const j of o.byPart.get(parts[i].spec.id)!) {\n if (j.st.open || !j.bears) continue\n const k = restsOn(o, j, i)\n if (k >= 0 && dist[k] >= 0 && dist[k] < dist[i] && !isPartition(k)) lower.push(k)\n }\n lowerOf.set(i, lower)\n }\n // the part of the load that bends a beam or a slab: what rests on it away from its supports. A load that stands over a support (a column\n // standing on a slab right over the beam below, a wall right over the wall below) goes straight down to that support with where it stands,\n // and bends that one only if it is away from its own supports\n const bending = new Array<number>(n).fill(0)\n const through: Array<Array<{ at: Vec3; mass: number; over: number }>> = parts.map(() => [])\n const pass = (k: number, at: Vec3, mass: number) => {\n const over = overSupportAt(o, parts[k], at, lowerOf.get(k) ?? [])\n if (over < 0) bending[k] += mass\n else through[k].push({ at, mass, over })\n }\n for (let h = queue.length - 1; h >= 0; h--) {\n const i = queue[h]\n const total = parts[i].st.mass + incoming[i]\n parts[i].st.load = total\n const lower = lowerOf.get(i)!\n for (const k of lower) incoming[k] += total / lower.length\n if (lower.length === 0) continue\n const bulk = parts[i].bend ? parts[i].st.mass + bending[i] : total\n for (const k of lower) if (parts[k].bend) pass(k, contactCentre(parts[k], parts[i]), bulk / lower.length)\n if (parts[i].bend) for (const item of through[i]) if (parts[item.over]?.bend) pass(item.over, item.at, item.mass)\n }\n for (let i = 0; i < n; i++) {\n const p = parts[i]\n o.unsup[i] = false\n if (!p.structural) continue\n if (dist[i] < 0 || isLost(p)) {\n p.st.load = p.st.mass\n p.st.stress = 0\n if (o.seeding && !p.anchored && !isLost(p) && p.st.status !== 'collapsed' && !o.collapsed.has(p.spec.id)) p.orphan = true\n o.unsup[i] = o.anyAnchor && !isLost(p) && !p.orphan\n continue\n }\n p.st.stress = (p.st.load! * structureSafety) / (p.cap * capacityScale(p))\n if (p.bend) {\n p.bendLoad = p.st.mass + bending[i]\n const bent = restFlexure(o, p, lowerOf.get(i) ?? [])\n p.st.flexure = bent\n p.snap = bent > 1 && !p.st.stripped && !sectionOf(p, p.bend.gravity).reinforced\n // a beam or slab carries its load in bending: the load the solver routes through it is not a compression it takes, unless a designer gave\n // it a capacity (`structure.capacity`, `sizeStructure`), which then holds as well\n if (p.spec.structure?.capacity === undefined || bent > p.st.stress) p.st.stress = bent\n }\n if (p.st.stress > o.maxStress) o.maxStress = p.st.stress\n }\n if (o.wind) applyWind(o)\n if (o.maxStress > 0.8) o.active = true\n if (o.soil) o.soil.dirty = true\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Wind (`DestructionOptions.wind`): lateral load that grows with height, the walls and frame that resist it, the sway of the top\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n const newWind = (o: ObjRT, carried?: [number, number, number, number, number]): WindRT => {\n const cfg = exposureOf(windCfg!, o.spec.wind)\n const [x = 0, v = 0, y = 0, w = 0, peak = 0] = carried ?? []\n return {\n cfg, gust: { freq: [], amp: [], phase: [] }, gustKey: '', analysis: null, parts: [], sys: null, mu: 0, dyn: { x, v, y, w, peak }, tension: new Map(),\n emitted: { t: -Infinity, peak: 0, status: 'ok' },\n }\n }\n\n /** The wind direction in the object's own axes: the horizontal unit vector `[x, z]`. */\n const windDirection = (o: ObjRT, cfg: ResolvedWind): [number, number] => {\n const d = rotateVec(quat.conjugate(o.base.rot), cfg.direction)\n const h = Math.hypot(d[0], d[2])\n return h > 1e-9 ? [d[0] / h, d[2] / h] : [1, 0]\n }\n\n /** Axial force the wind adds to the walls and columns, the design drift and the first mode of the object as it stands now. */\n const applyWind = (o: ObjRT) => {\n const w = o.wind!\n const cfg = (w.cfg = exposureOf(windCfg!, o.spec.wind))\n const terrain = cfg.terrains.get(cfg.terrain)\n if (!terrain) throw new Error(`unknown wind terrain \"${cfg.terrain}\"`)\n const inputs: WindPartInput[] = []\n const at = new Map<number, number>()\n const keep: number[] = []\n let ground = Infinity, foundationTop = -Infinity\n o.parts.forEach((p, i) => {\n if (isLost(p) || isTerrain(p) || o.collapsed.has(p.spec.id) || o.unsup[i]) return\n const box = aabbOf(p.spec.shape, p.pos, p.q)\n const role = p.spec.structure?.role\n const e = p.mat.strength?.elasticGPa\n const kind: WindPartInput['kind'] = role === 'wall' ? 'wall' : role === 'column' ? 'column' : role === 'beam' ? 'beam' : role === 'foundation' ? 'foundation' : 'other'\n at.set(i, inputs.length)\n keep.push(i)\n ground = Math.min(ground, box.min[1])\n if (kind === 'foundation') foundationTop = Math.max(foundationTop, box.max[1])\n inputs.push({ min: box.min, max: box.max, kind, ...(e ? { elasticPa: e * 1e9 } : {}), mass: p.st.mass, ...(p.spec.damper ? { damper: true } : {}) })\n })\n keep.forEach((i, k) => {\n if (inputs[k].kind !== 'column') return\n const beams: number[] = []\n for (const j of o.byPart.get(o.parts[i].spec.id)!) {\n if (j.st.open) continue\n const b = at.get(j.ia === i ? j.ib : j.ia)\n if (b !== undefined && inputs[b].kind === 'beam') beams.push(b)\n }\n inputs[k].beams = beams\n })\n // a slab that rests on a beam works with it as a flange\n keep.forEach((i, k) => {\n if (inputs[k].kind !== 'beam') return\n for (const j of o.byPart.get(o.parts[i].spec.id)!) {\n if (j.st.open) continue\n const q = o.parts[j.ia === i ? j.ib : j.ia]\n const role = q.spec.structure?.role\n if ((role === 'slab' || role === 'roof') && !isLost(q) && q.spec.shape.kind === 'box') {\n inputs[k].slab = q.dims[1]\n break\n }\n }\n })\n const c: WindCase = {\n speed: cfg.speed, direction: windDirection(o, cfg), terrain, cls: cfg.class, topography: cfg.topography, statistical: cfg.statistical, drag: cfg.drag, damping: cfg.damping,\n airDensity: cfg.airDensity, minHeight: cfg.minHeight, bandHeight: cfg.bandHeight, stiffnessFactor: cfg.stiffnessFactor, beamFactor: cfg.beamFactor, loadFactor: cfg.loadFactor,\n chord: cfg.chord, meanRatio: cfg.meanRatio, gustFactor: cfg.gustFactor, flange: cfg.flange,\n }\n const a = inputs.length && cfg.speed > 0 ? analyzeWind(inputs, c, foundationTop > -Infinity ? foundationTop : ground) : null\n w.analysis = a\n w.parts = keep\n for (const p of o.parts) delete p.st.wind\n if (!a) {\n w.sys = null\n delete o.st.wind\n return\n }\n // the load on the walls and columns: compression adds to their load, tension takes from it (and pulls on the part when it passes the dead load)\n keep.forEach((i, k) => {\n const N = a.axial[k]\n const p = o.parts[i]\n if (!N || !p.structural || o.unsup[i]) return\n p.st.wind = N\n const dead = p.st.load ?? p.st.mass\n const force = N * cfg.loadFactor\n let stress = 0\n if (force >= 0) stress = (dead * structureSafety + force / GRAVITY) / (p.cap * capacityScale(p))\n else if (dead + force / GRAVITY < 0) {\n let cap = w.tension.get(i)\n if (cap === undefined) {\n const r = p.spec.reinforcement\n const ratio = p.spec.structure?.rebar?.ratio\n cap = tensionCapacity(p.dims, {\n ...(r ? { reinforcement: r } : {}), ...(ratio ? { ratio } : {}), yieldMPa: flexure.rebarYieldMPa,\n ...(p.mat.strength?.tensileMPa !== undefined ? { tensileMPa: p.mat.strength.tensileMPa } : {}),\n })\n w.tension.set(i, cap)\n }\n stress = Math.min(10, (-(dead + force / GRAVITY) * GRAVITY) / Math.max(cap * capacityScale(p), 1))\n }\n if (stress > (p.st.stress ?? 0)) p.st.stress = stress\n if ((p.st.stress ?? 0) > o.maxStress) o.maxStress = p.st.stress ?? 0\n })\n // the first mode, with the tuned mass damper if there is one\n const key = `${cfg.speed}|${cfg.terrain}|${cfg.topography}|${cfg.statistical}|${cfg.meanRatio}|${cfg.gust.components}|${cfg.gust.maxHz}|${cfg.gust.scale}|${cfg.gust.seed}`\n if (key !== w.gustKey) {\n w.gustKey = key\n const v10 = cfg.speed * cfg.topography * cfg.statistical * meanHeightFactor(10, terrain, a.cls, { meanRatio: cfg.meanRatio, minHeight: cfg.minHeight })\n w.gust = makeGust(v10, cfg.gust)\n }\n let md = 0, spec: PartSpec['damper'] | undefined\n for (const i of keep) {\n const p = o.parts[i]\n if (!p.spec.damper) continue\n const phi = shapeAt(a, p.pos[1] - (foundationTop > -Infinity ? foundationTop : ground))\n md += p.st.mass * phi * phi\n spec ??= p.spec.damper\n }\n const sys: SwaySystem = { M: a.modalMass, K: a.modalStiffness, C: 2 * cfg.damping * a.omega * a.modalMass }\n w.mu = 0\n if (md > 0 && a.modalMass > 0) {\n w.mu = md / a.modalMass\n const tuned = damperTuning(w.mu, cfg.tuning)\n const f = spec?.frequency ?? tuned.frequency * a.frequency\n const zeta = spec?.damping ?? tuned.damping\n sys.damper = { m: md, k: md * (2 * Math.PI * f) ** 2, c: 2 * zeta * md * 2 * Math.PI * f }\n }\n w.sys = a.modalMass > 0 && a.omega > 0 ? sys : null\n const st: WindState = {\n speed: cfg.speed, pressure: a.pressure, shear: a.shear, moment: a.moment, deflection: a.deflection, drift: a.drift, limit: cfg.driftLimit, overturn: Math.min(a.overturn, 1000),\n frequency: a.frequency, lean: a.lean, sway: w.dyn.x, peak: w.dyn.peak, status: a.overturn > 1 ? 'overturn' : a.drift > cfg.driftLimit ? 'drift' : 'ok',\n }\n if (sys.damper) st.damper = { ratio: w.mu, travel: w.dyn.y - w.dyn.x }\n o.st.wind = st\n }\n\n /** Moves the top of the building with the gust (the first mode and the damper, integrated together) and reports `sway` when it changes. */\n const stepWind = (o: ObjRT, dt: number) => {\n const w = o.wind!\n const a = w.analysis\n const st = o.st.wind\n if (!a || !st || !w.sys) return\n const gust = w.gust\n const I = a.intensity\n const force = (t: number) => {\n const n = gustAt(gust, t)\n return a.modalForce * (2 * I * n + I * I * (n * n - 1))\n }\n const wn = Math.max(a.omega, w.sys.damper ? Math.sqrt(w.sys.damper.k / w.sys.damper.m) : 0)\n stepSway(w.dyn, w.sys, time - dt, dt, force, (2 * Math.PI) / wn / 20)\n const d = w.dyn\n d.peak = Math.max(Math.abs(d.x), d.peak * Math.exp(-dt / w.cfg.peakDecay))\n st.sway = d.x\n st.peak = d.peak\n if (st.damper) st.damper.travel = d.y - d.x\n const e = w.emitted\n if (d.peak < e.peak * 0.8) e.peak = d.peak\n if (st.status !== e.status || (time - e.t >= 0.5 && d.peak > e.peak * 1.05 + 1e-3)) {\n w.emitted = { t: time, peak: d.peak, status: st.status }\n const dir = windDirection(o, w.cfg)\n const world = rotateVec(o.base.rot, [dir[0], 0, dir[1]])\n emit({ ...base(o), type: 'sway', sway: d.x, peak: d.peak, drift: st.drift, overturn: st.overturn, frequency: st.frequency, direction: world, status: st.status })\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Soil (`DestructibleSpec.soil`): footings and piles on the ground, settlement, tilt and tipping over\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n const isTerrain = (p: PartRT) => !!p.spec.tags?.includes('terrain')\n const isFoundation = (p: PartRT) => p.spec.structure?.role === 'foundation' && !isLost(p)\n const slopeTilt = (a: number, b: number) => Math.atan(Math.hypot(a, b))\n\n /** The springs the object stands on: a grid of cells under each footing, one per pile, and a footing under each part that rests on the terrain. */\n const soilSprings = (o: ObjRT, profile: SoilProfile): { springs: Array<SoilSpring & { key: string }>; baseY: number } => {\n const found = o.parts.filter(isFoundation)\n const box = (p: PartRT) => aabbOf(p.spec.shape, p.pos, p.q)\n const surface = profile.surface ?? Math.max(...found.map((p) => box(p).max[1]))\n const prints: Array<{ x0: number; x1: number; z0: number; z1: number; bottom: number; part: PartRT }> = []\n for (const f of found) {\n const b = box(f)\n if (!isTerrain(f)) {\n prints.push({ x0: b.min[0], x1: b.max[0], z0: b.min[2], z1: b.max[2], bottom: b.min[1], part: f })\n continue\n }\n // the ground itself: each structural part that rests on it gets a footing at least `footingWidth` wide (a strip under a wall, a pad under a pillar)\n const fi = o.idx.get(f.spec.id)!\n const width = profile.footingWidth ?? soilCfg.footingWidth\n for (const j of o.byPart.get(f.spec.id)!) {\n if (j.st.open || !j.bears) continue\n const r = j.ia === fi ? j.ib : j.ia\n const q = o.parts[r]\n if (!q.structural || isLost(q) || restsOn(o, j, r) !== fi) continue\n const c = box(q)\n const x0 = Math.max(c.min[0], b.min[0]), x1 = Math.min(c.max[0], b.max[0]), z0 = Math.max(c.min[2], b.min[2]), z1 = Math.min(c.max[2], b.max[2])\n const cx = (x0 + x1) / 2, cz = (z0 + z1) / 2\n const wx = Math.max(width, x1 - x0), wz = Math.max(width, z1 - z0)\n prints.push({ x0: cx - wx / 2, x1: cx + wx / 2, z0: cz - wz / 2, z1: cz + wz / 2, bottom: c.min[1], part: q })\n }\n }\n const springs: Array<SoilSpring & { key: string }> = []\n for (const fp of prints) {\n const wx = Math.max(0.01, fp.x1 - fp.x0), wz = Math.max(0.01, fp.z1 - fp.z0)\n const depth = Math.max(0, surface - fp.bottom)\n const pile = fp.part.spec.structure?.role === 'foundation' ? fp.part.spec.structure.pile : undefined\n if (pile) {\n const count = Math.max(1, Math.round(pile.count ?? 1))\n const nx = Math.ceil(Math.sqrt(count)), nz = Math.ceil(count / nx)\n const cap = pileCapacity(profile, pile, depth, soilCfg.byId).ultimate\n const tip = soilAt(profile, depth + pile.length, soilCfg.byId)\n const k = pileStiffness(pile, fp.part.mat.strength?.elasticGPa ?? soilCfg.pileElasticGPa, tip.elasticMPa, tip.poisson)\n for (let i = 0; i < count; i++) {\n const col = i % nx, row = Math.floor(i / nx)\n springs.push({ key: `${fp.part.spec.id}#${i}`, x: fp.x0 + ((col + 0.5) * wx) / nx, z: fp.z0 + ((row + 0.5) * wz) / nz, hx: wx / (2 * nx), hz: wz / (2 * nz), k, cap })\n }\n continue\n }\n const B = Math.min(wx, wz)\n const g = footingSoil(profile, depth, B, soilCfg.byId, soilCfg.influence)\n const ks = subgradeModulus(g.elasticMPa, g.poisson, B, soilCfg.rigidity)\n const size = Math.max(wx, wz) / Math.max(1, soilCfg.cells)\n const nx = Math.max(1, Math.round(wx / size)), nz = Math.max(1, Math.round(wz / size))\n const area = (wx * wz) / (nx * nz)\n for (let i = 0; i < nx; i++) {\n for (let k = 0; k < nz; k++) {\n springs.push({ key: `${fp.part.spec.id}#${i}.${k}`, x: fp.x0 + ((i + 0.5) * wx) / nx, z: fp.z0 + ((k + 0.5) * wz) / nz, hx: wx / (2 * nx), hz: wz / (2 * nz), k: ks * area, cap: soilCfg.safety * g.allowableKPa * 1000 * area })\n }\n }\n }\n return { springs, baseY: prints.length ? Math.min(...prints.map((fp) => fp.bottom)) : 0 }\n }\n\n /** Weight (N) and centre of mass of what stands on the ground: every part left that is not the terrain and has not fallen. */\n const soilWeight = (o: ObjRT): { w: number; c: Vec3 } => {\n let m = 0\n const c: Vec3 = [0, 0, 0]\n for (const p of o.parts) {\n if (isLost(p) || isTerrain(p) || o.collapsed.has(p.spec.id) || o.unsup[o.idx.get(p.spec.id)!]) continue\n m += p.st.mass\n for (let k = 0; k < 3; k++) c[k] += p.st.mass * p.pos[k]\n }\n return { w: m * GRAVITY, c: m > 0 ? [c[0] / m, c[1] / m, c[2] / m] : c }\n }\n\n const initSoil = (o: ObjRT, profile: SoilProfile, carried?: SoilState, carrySets?: Record<string, number>) => {\n const so: SoilRT = { profile, s: 0, a: 0, b: 0, imp: [0, 0], pivot: [0, 0, 0], dirty: true, sets: new Map(), emitted: { t: -Infinity, s: 0, tilt: 0, status: 'stable' } }\n const { springs, baseY } = soilSprings(o, profile)\n if (!springs.length) return\n const [x0, z0] = stiffnessCentre(springs)\n so.pivot = [x0, baseY, z0]\n // the out-of-plumb is taken the unfavourable way: about the axis the foundations are weakest in, toward the side the weight already leans to\n let ix = 0, iz = 0\n for (const sp of springs) {\n ix += sp.k * (sp.x - x0) ** 2\n iz += sp.k * (sp.z - z0) ** 2\n }\n const { c } = soilWeight(o)\n const along = ix <= iz ? 0 : 1\n const off = along === 0 ? c[0] - x0 : c[2] - z0\n const sign = Math.abs(off) > 1e-6 ? Math.sign(off) : 1\n so.imp = along === 0 ? [sign * soilCfg.imperfection, 0] : [0, sign * soilCfg.imperfection]\n if (carried) {\n const t = Math.tan((carried.tilt * Math.PI) / 180)\n so.s = carried.settlement\n so.a = t * carried.direction[0]\n so.b = t * carried.direction[2]\n so.emitted = { t: -Infinity, s: carried.settlement, tilt: carried.tilt, status: carried.status }\n o.st.soil = clone(carried)\n for (const [k, v] of Object.entries(carrySets ?? {})) so.sets.set(k, v)\n if (carried.status === 'toppled') for (const p of o.parts) p.anchored = false\n }\n o.soil = so\n applySoilPose(o)\n }\n\n /** The settled pose: tilted about the pivot by the slopes of the base, then down by the settlement; `st.position`/`rotation` follow. */\n const applySoilPose = (o: ObjRT) => {\n const so = o.soil\n if (!so) {\n o.st.position = [o.base.pos[0], o.base.pos[1], o.base.pos[2]]\n o.st.rotation = [o.base.rot[0], o.base.rot[1], o.base.rot[2], o.base.rot[3]]\n return\n }\n const angle = slopeTilt(so.a, so.b)\n // the side that goes down `a` per metre of x turns +x toward -y: a rotation about (b, 0, -a)\n const R = angle > 1e-12 ? quat.fromAxisAngle(vec.normalize([so.b, 0, -so.a]), angle) : quat.identity()\n const t = vec.sub(vec.sub(so.pivot, rotateVec(R, so.pivot)), [0, so.s, 0])\n o.st.rotation = quat.normalize(quat.mul(o.base.rot, R))\n o.st.position = vec.add(o.base.pos, rotateVec(o.base.rot, t))\n const lean = Math.hypot(so.a, so.b)\n const st: SoilState = o.st.soil ?? { settlement: 0, tilt: 0, direction: [0, 0, 0], bearing: 0, edge: 0, status: 'stable', offset: { position: [0, 0, 0], rotation: [0, 0, 0, 1] } }\n st.settlement = so.s\n st.tilt = (angle * 180) / Math.PI\n st.direction = lean > 1e-12 ? [so.a / lean, 0, so.b / lean] : [0, 0, 0]\n st.offset = { position: t, rotation: R }\n o.st.soil = st\n }\n\n /** The object tipped over: nothing holds it to the ground any more, everything falls. */\n const topple = (o: ObjRT, src?: string) => {\n for (const p of o.parts) p.anchored = false\n solveStructure(o)\n recomputeGroups(o)\n if (!pendingCollapse.has(o)) pendingCollapse.set(o, src)\n }\n\n /**\n * Solve the ground under the object and move it toward the equilibrium. `dt` 0 (the object is placed): it takes the equilibrium at once, as a\n * building that has stood there. In `update` an elastic change is taken at once and a yielding soil moves the object at `sinkRate`/`tiltRate`;\n * with no stable equilibrium it keeps sinking and leaning until its centre of mass passes the edge of its foundations and it tips over.\n */\n const settleSoil = (o: ObjRT, dt: number) => {\n const so = o.soil!\n const st = o.st.soil\n if (st?.status === 'toppled') return\n const { springs } = soilSprings(o, so.profile)\n for (const sp of springs) sp.set = so.sets.get(sp.key) ?? 0\n const { w, c } = soilWeight(o)\n if (!springs.length || w <= 0) {\n if (springs.length === 0 && w > 0) {\n so.s += soilCfg.sinkRate * dt\n applySoilPose(o)\n o.st.soil!.status = 'yielding'\n }\n return\n }\n const height = Math.max(0, c[1] - so.pivot[1])\n // the wind overturns the building as if its centre of mass stood `M / W` further downwind\n const wa = o.wind?.analysis\n const push = wa ? windDirection(o, o.wind!.cfg) : [0, 0]\n const shift = wa ? wa.moment / w : 0\n const r = solveFoundation(springs, w, c[0] + shift * push[0], c[2] + shift * push[1], height, so.imp, { s: so.s, a: so.a, b: so.b })\n let status: SoilState['status'] = 'stable'\n const sinkStep = soilCfg.sinkRate * dt\n const tiltStep = Math.tan((soilCfg.tiltRate * Math.PI) / 180) * dt\n if (r.stable && (!r.yielded || dt === 0)) {\n so.s = r.s\n so.a = r.a\n so.b = r.b\n } else if (r.stable) {\n const ds = r.s - so.s, da = r.a - so.a, db = r.b - so.b\n const fs = Math.abs(ds) > sinkStep ? sinkStep / Math.abs(ds) : 1\n const lean = Math.hypot(da, db)\n const ft = lean > tiltStep ? tiltStep / lean : 1\n so.s += ds * fs\n so.a += da * ft\n so.b += db * ft\n if (fs < 1 || ft < 1) status = 'yielding'\n } else {\n status = 'yielding'\n if (dt === 0) {\n // placed where the ground cannot hold it: it starts from the elastic settlement and moves from there in `update`\n so.s = w / springs.reduce((sum, sp) => sum + sp.k, 0)\n } else {\n so.s += sinkStep * (r.bearing >= 1 ? 1 : 0.25)\n const lean = Math.hypot(so.a, so.b)\n const ux = lean > 1e-9 ? so.a / lean : Math.sign(so.imp[0]), uz = lean > 1e-9 ? so.b / lean : Math.sign(so.imp[1])\n so.a += ux * tiltStep\n so.b += uz * tiltStep\n }\n }\n if (so.s !== 0 || so.a !== 0 || so.b !== 0) {\n const sets = yieldSprings(springs, so.s, so.a, so.b)\n springs.forEach((sp, i) => {\n if (sets[i] > 0) so.sets.set(sp.key, sets[i])\n })\n }\n applySoilPose(o)\n const out = o.st.soil!\n out.bearing = r.bearing\n out.edge = r.edge\n out.status = status\n // tipped over: the centre of mass, moved over by the lean, passed the edge of the foundations in the direction it leans\n const lean = Math.hypot(so.a, so.b)\n if (lean > 1e-9) {\n const [x0, z0] = [so.pivot[0], so.pivot[2]]\n const ux = so.a / lean, uz = so.b / lean\n const e = (c[0] - x0 + height * (so.a + so.imp[0])) * ux + (c[2] - z0 + height * (so.b + so.imp[1])) * uz\n let edge = 0\n for (const sp of springs) edge = Math.max(edge, (sp.x - x0) * ux + (sp.z - z0) * uz + sp.hx * Math.abs(ux) + sp.hz * Math.abs(uz))\n if (e > edge || slopeTilt(so.a, so.b) > Math.PI / 3) out.status = 'toppled'\n }\n }\n\n const stepSoil = (o: ObjRT, dt: number) => {\n const so = o.soil!\n if (o.st.soil?.status === 'toppled') return\n if (!so.dirty && o.st.soil?.status !== 'yielding') return\n so.dirty = false\n settleSoil(o, dt)\n const st = o.st.soil!\n const e = so.emitted\n const changed = st.status !== e.status || ((time - e.t >= 0.5 || e.t === -Infinity) && (Math.abs(st.tilt - e.tilt) > 0.01 || Math.abs(st.settlement - e.s) > 0.002))\n if (changed) {\n so.emitted = { t: time, s: st.settlement, tilt: st.tilt, status: st.status }\n emit({ ...base(o), type: 'settle', settlement: st.settlement, tilt: st.tilt, direction: rotateVec(o.base.rot, st.direction), bearing: st.bearing, status: st.status })\n }\n if (st.status === 'toppled') topple(o)\n }\n\n /**\n * Ask for a collapse report. It is not computed right away: a blow can break several parts in one go (a column and the roof's supports, or a\n * column whose joint opens just before the column itself fractures), so the groups are examined once, after every loss of the operation.\n */\n const collapseCheck = (o: ObjRT, src?: string) => {\n if (!o.hasStructure || !o.parts.some((p) => p.anchored)) return\n if (!pendingCollapse.has(o)) pendingCollapse.set(o, src)\n }\n\n /** Report the groups of remaining structural parts that lost every anchor (each part is reported once). */\n const flushCollapse = () => {\n for (const [o, src] of [...pendingCollapse]) {\n pendingCollapse.delete(o)\n if (!objects.has(o.id) || objects.get(o.id) !== o) continue\n for (const g of o.st.groups) {\n const ps = g.map((id) => o.byId.get(id)!).filter((p) => !isLost(p) && !o.collapsed.has(p.spec.id))\n if (ps.length === 0 || g.some((id) => o.byId.get(id)!.anchored) || !ps.some((p) => p.structural)) continue\n for (const p of ps) {\n o.collapsed.add(p.spec.id)\n p.st.status = 'collapsed'\n setStage(o, p, 3, {}, src)\n }\n emit({ ...base(o, src), type: 'collapse', parts: ps.map((p) => p.spec.id), mass: ps.reduce((sum, p) => sum + p.st.mass, 0) })\n }\n }\n }\n\n const getObj = (id: string): ObjRT => {\n const o = objects.get(id)\n if (!o) throw new Error(`unknown object \"${id}\"`)\n return o\n }\n const getPart = (o: ObjRT, id: string): PartRT => {\n const p = o.byId.get(id)\n if (!p) throw new Error(`unknown part \"${id}\" in object \"${o.id}\"`)\n return p\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Geometry in world space\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n const partXf = (o: ObjRT, p: PartRT): { c: Vec3; q: Quat } => ({ c: toWorld(o.st.position, o.st.rotation, p.pos), q: quat.mul(o.st.rotation, p.q) })\n const objLocal = (o: ObjRT, w: Vec3) => toLocal(o.st.position, o.st.rotation, w)\n const objLocalDir = (o: ObjRT, w: Vec3) => rotateVec(quat.conjugate(o.st.rotation), w)\n const jointWorld = (o: ObjRT, j: JointRT) => toWorld(o.st.position, o.st.rotation, j.pos)\n const distToPart = (o: ObjRT, p: PartRT, w: Vec3) => {\n const { c, q } = partXf(o, p)\n return distanceToShape(p.spec.shape, toLocal(c, q, w))\n }\n const partWorldAabb = (o: ObjRT, p: PartRT) => {\n const { c, q } = partXf(o, p)\n return aabbOf(p.spec.shape, c, q)\n }\n\n interface PartRay { t0: number; t1: number; n: Vec3 }\n const rayPartRaw = (pos: Vec3, rot: Quat, spec: PartSpec, pq: Quat, origin: Vec3, d: Vec3, lp: Vec3 = spec.position): PartRay | null => {\n const c = toWorld(pos, rot, lp)\n const q = quat.mul(rot, pq)\n const qi = quat.conjugate(q)\n const r = rayShape(spec.shape, rotateVec(qi, vec.sub(origin, c)), rotateVec(qi, d))\n return r ? { t0: r.t0, t1: r.t1, n: rotateVec(q, r.n0) } : null\n }\n const rayPart = (o: ObjRT, p: PartRT, origin: Vec3, d: Vec3): PartRay | null => rayPartRaw(o.st.position, o.st.rotation, p.spec, p.q, origin, d, p.pos)\n\n const raySphereMiss = (origin: Vec3, d: Vec3, c: Vec3, r: number, maxDist: number): boolean => {\n const oc = vec.sub(origin, c)\n const b = vec.dot(oc, d)\n const cc = vec.dot(oc, oc) - r * r\n if (cc > 0 && b > 0) return true\n const disc = b * b - cc\n if (disc < 0) return true\n return -b - Math.sqrt(disc) > maxDist\n }\n\n const raycastInternal = (origin: Vec3, dir: Vec3, maxDist: number, ignore?: Set<string>, worldOnly = false): (RayHit & { pathLen: number }) | null => {\n const d = vec.normalize(dir)\n let best: (RayHit & { pathLen: number }) | null = null\n for (const o of objects.values()) {\n if (raySphereMiss(origin, d, toWorld(o.st.position, o.st.rotation, o.bc), o.br, best ? Math.min(maxDist, best.distance) : maxDist)) continue\n for (const p of o.parts) {\n if (isLost(p) || ignore?.has(`${o.id}\\0${p.spec.id}`)) continue\n const r = rayPart(o, p, origin, d)\n if (!r || r.t0 < 0 || r.t0 > maxDist) continue\n if (p.st.opening && insideOpening(o, p, vec.madd(origin, d, r.t0))) continue\n if (!best || r.t0 < best.distance) best = { object: o.id, part: p.spec.id, point: vec.madd(origin, d, r.t0), normal: r.n, distance: r.t0, pathLen: r.t1 - r.t0 }\n }\n }\n for (const im of worldOnly ? [] : impls.values()) {\n for (const ps of im.impl.describe().parts) {\n if (ignore?.has(`${im.impl.id}\\0${ps.id}`)) continue\n const ov = im.poses.get(ps.id)\n const r = rayPartRaw(im.position, im.rotation, ps, ov?.q ?? quatFromEuler(...(ps.rotation ?? [0, 0, 0])), origin, d, ov?.pos)\n if (!r || r.t0 < 0 || r.t0 > maxDist) continue\n if (!best || r.t0 < best.distance) best = { 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 }\n }\n }\n return best\n }\n\n // impl hosting\n const implHit = (im: ImplRT, hit: Hit): HitResult => {\n let h = hit\n if (hit.space === 'local') {\n h = { ...hit, space: 'world', point: toWorld(im.position, im.rotation, hit.point) }\n if (hit.direction) h.direction = rotateVec(im.rotation, hit.direction)\n }\n const start = cur.length\n for (const e of im.impl.hit(h) ?? []) emit(e.time === undefined ? { ...e, time } : e)\n const mine = cur.slice(start)\n const res: HitResult = { object: im.impl.id, damage: 0, penetrated: false, exitEnergy: 0, events: mine, point: hit.point }\n for (const e of mine) {\n if (e.type === 'damage') res.damage += e.amount\n if (e.type === 'hole' && e.hole.through) res.penetrated = true\n if (res.part === undefined && 'part' in e) res.part = (e as { part: string }).part\n }\n return res\n }\n\n const implJointPos = (im: ImplRT, a: string, b: string): Vec3 | null => {\n const parts = im.impl.describe().parts\n const pa = parts.find((p) => p.id === a), pb = parts.find((p) => p.id === b)\n if (!pa || !pb) return null\n const A = aabbOf(pa.shape, pa.position, quatFromEuler(...(pa.rotation ?? [0, 0, 0])))\n const B = aabbOf(pb.shape, pb.position, quatFromEuler(...(pb.rotation ?? [0, 0, 0])))\n const pos: Vec3 = [0, 0, 0]\n for (let k = 0; k < 3; k++) pos[k] = (Math.max(A.min[k], B.min[k]) + Math.min(A.max[k], B.max[k])) / 2\n return toWorld(im.position, im.rotation, pos)\n }\n\n /** Find the part a hit lands on: a short ray along `dir`, else the nearest part within `tol`. */\n const locate = (o: ObjRT, point: Vec3, dir: Vec3 | undefined, tol: number, only?: PartRT): Loc | null => {\n const cands = only ? [only] : o.parts\n if (dir && vec.length(dir) > 1e-9) {\n const d = vec.normalize(dir)\n const origin = vec.madd(point, d, -0.05)\n let best: Loc | null = null\n let bestT = Infinity\n let inside: Loc | null = null\n for (const p of cands) {\n if (isLost(p)) continue\n const r = rayPart(o, p, origin, d)\n if (!r) continue\n if (r.t0 >= 0 && r.t0 <= 0.15) {\n if (r.t0 < bestT) {\n bestT = r.t0\n best = { p, point: vec.madd(origin, d, r.t0), normal: r.n, dir: d, pathLen: Math.max(r.t1 - r.t0, 1e-4) }\n }\n } else if (r.t0 < 0 && r.t1 > 0 && !inside) {\n inside = { p, point, normal: vec.scale(d, -1), dir: d, pathLen: Math.max(r.t1 - 0.05, p.thickness) }\n }\n }\n if (best) return best\n if (inside) return inside\n }\n let np: PartRT | null = null\n let nd = Infinity\n for (const p of cands) {\n if (isLost(p)) continue\n const dd = distToPart(o, p, point)\n if (dd < nd) {\n nd = dd\n np = p\n }\n }\n if (!np || nd > tol) return null\n const { c, q } = partXf(o, np)\n const sp = surfacePoint(np.spec.shape, toLocal(c, q, point))\n const normal = rotateVec(q, sp.normal)\n return { p: np, point: toWorld(c, q, sp.point), normal, dir: dir && vec.length(dir) > 1e-9 ? vec.normalize(dir) : vec.scale(normal, -1), pathLen: np.thickness }\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Marks on parts\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n const markDamaged = (p: PartRT) => {\n if (p.st.status === 'intact') p.st.status = 'damaged'\n }\n\n const addDent = (o: ObjRT, p: PartRT, wp: Vec3, wn: Vec3, radius: number, depth: number, src?: string) => {\n const dent: Dent = { point: objLocal(o, wp), normal: objLocalDir(o, wn), radius, depth }\n const arr = p.st.dents\n let ni = -1, nd = Infinity\n for (let i = 0; i < arr.length; i++) {\n const dd = vec.distance(arr[i].point, dent.point)\n if (dd < nd) {\n nd = dd\n ni = i\n }\n }\n if (ni >= 0 && (arr.length >= maxDents || nd < arr[ni].radius * 0.6)) {\n arr[ni].depth = Math.min(0.1, Math.max(arr[ni].depth, depth) + depth * 0.3)\n arr[ni].radius = Math.max(arr[ni].radius, radius)\n } else arr.push(dent)\n markDamaged(p)\n emit({ ...base(o, src), type: 'dent', part: p.spec.id, dent, worldPoint: wp })\n }\n\n const addHole = (o: ObjRT, p: PartRT, wp: Vec3, wn: Vec3, diameter: number, through: boolean, exit?: Vec3, src?: string) => {\n const hole: Hole = { point: objLocal(o, wp), normal: objLocalDir(o, wn), diameter, through }\n p.st.holes.push(hole)\n if (p.st.holes.length > maxHoles) p.st.holes.shift()\n markDamaged(p)\n emit({ ...base(o, src), type: 'hole', part: p.spec.id, hole, worldPoint: wp, ...(exit ? { exitPoint: exit } : {}) })\n setStage(o, p, 1, {}, src)\n return hole\n }\n\n const addCrack = (o: ObjRT, p: PartRT, wp: Vec3, wn: Vec3, length: number, src?: string) => {\n const crack: Crack = { point: objLocal(o, wp), normal: objLocalDir(o, wn), length: Math.min(length, Math.max(p.bound, 0.05)), rays: 5 + Math.floor(rnd() * 5) }\n p.st.cracks.push(crack)\n if (p.st.cracks.length > 16) p.st.cracks.shift()\n markDamaged(p)\n emit({ ...base(o, src), type: 'crack', part: p.spec.id, crack, worldPoint: wp })\n setStage(o, p, 1, {}, src)\n }\n\n const debris = (o: ObjRT, p: PartRT, kind: DebrisKind, point: Vec3, normal: Vec3, count: number, speed: number, src?: string) =>\n emit({ ...base(o, src), type: 'debris', part: p.spec.id, kind, point, normal, count, speed })\n\n const holeRate = (hole: Hole, pressurized: boolean) => (pressurized ? 0.5 : 0.1) * (hole.diameter / 0.009)\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Failure, joints\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n const detachEvents = (o: ObjRT, opened: JointRT[], by: 'break' | 'tool' | 'part_lost', src?: string) => {\n 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]) })\n }\n\n const checkDestroyed = (o: ObjRT, src?: string) => {\n if (!o.st.destroyed && o.parts.length > 0 && o.parts.every(isLost)) {\n o.st.destroyed = true\n emit({ ...base(o, src), type: 'destroyed' })\n }\n }\n\n const partLost = (o: ObjRT, p: PartRT, src?: string) => {\n const opened: JointRT[] = []\n for (const j of o.byPart.get(p.spec.id) ?? []) {\n if (j.st.open) continue\n j.st.open = true\n j.st.openedBy = 'part_lost'\n opened.push(j)\n }\n solveStructure(o)\n recomputeGroups(o)\n detachEvents(o, opened, 'part_lost', src)\n collapseCheck(o, src)\n checkDestroyed(o, src)\n }\n\n /**\n * Distance from a world point to the joint's contact region: the overlap box of the two parts' bounds (or, when they only nearly touch, the box\n * of the gap between them). Measuring to the joint centre would make a thick part untouchable: a blow on a trunk's surface is half the trunk's\n * width away from a joint that sits on its axis.\n */\n const jointReach = (o: ObjRT, j: JointRT, point: Vec3): number => {\n const A = partWorldAabb(o, o.parts[j.ia]), B = partWorldAabb(o, o.parts[j.ib])\n let d2 = 0\n for (let k = 0; k < 3; k++) {\n const lo = Math.min(Math.max(A.min[k], B.min[k]), Math.min(A.max[k], B.max[k]))\n const hi = Math.max(Math.max(A.min[k], B.min[k]), Math.min(A.max[k], B.max[k]))\n const d = point[k] < lo ? lo - point[k] : point[k] > hi ? point[k] - hi : 0\n d2 += d * d\n }\n return Math.sqrt(d2)\n }\n /** How far from the contact region a blow still counts: half the smallest dimension of the smaller part, at least 6 cm. */\n const jointReachLimit = (o: ObjRT, j: JointRT): number => {\n const pa = o.parts[j.ia], pb = o.parts[j.ib]\n const small = pa.dims[0] * pa.dims[1] * pa.dims[2] <= pb.dims[0] * pb.dims[1] * pb.dims[2] ? pa : pb\n return Math.max(0.06, 0.5 * Math.min(small.dims[0], small.dims[1], small.dims[2]))\n }\n\n const wearJoints = (o: ObjRT, p: PartRT, amount: number, near?: Vec3, radius = 0.06, src?: string, split = false) => {\n if (amount <= 0) return\n const mine = (o.byPart.get(p.spec.id) ?? []).filter((j) => !j.st.open)\n if (split && mine.length) amount /= mine.length\n for (const j of mine) {\n if (j.st.open) continue\n // the rebar of a reinforced part (a cage, or the tension steel of `structure.rebar`) ties it to the next one: blows do not wear it, only a torch\n // or a saw cuts it (or the part itself giving way)\n if (j.spec.kind === 'rebar' && (isReinforced(o.parts[j.ia].spec) || isReinforced(o.parts[j.ib].spec))) continue\n if (near && jointReach(o, j, near) > Math.max(radius, jointReachLimit(o, j))) continue\n j.st.hp -= amount\n if (j.st.hp <= 0) {\n j.st.hp = 0\n j.st.open = true\n j.st.openedBy = 'break'\n solveStructure(o)\n recomputeGroups(o)\n detachEvents(o, [j], 'break', src)\n collapseCheck(o, src)\n }\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Damage stages: spall, breach, reinforcement cage\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n const setStage = (o: ObjRT, p: PartRT, stage: DamageStage, extra: { opening?: { center: Vec3; radius: number }; fragments?: Fragment[] } = {}, src?: string) => {\n if (!p.staged || (p.st.stage ?? 0) >= stage) return\n p.st.stage = stage\n emit({ ...base(o, src), type: 'stage', part: p.spec.id, stage, ...extra })\n }\n\n /** `1` when the outward normal points along the part's local +thin axis, else `-1`. */\n const faceOf = (o: ObjRT, p: PartRT, worldNormal: Vec3): number => (rotateVec(quat.conjugate(partXf(o, p).q), worldNormal)[p.thin] >= 0 ? 1 : -1)\n\n const spallOuter = (o: ObjRT, p: PartRT, wp: Vec3, face: number, normal: Vec3, radius: number, src?: string) => {\n if (p.layers.length === 0) return\n const lp = objLocal(o, wp)\n const layer = outerLayer(p.layers, p.rt.spalls, face, lp)\n if (!layer) return\n const spalls = (p.rt.spalls ??= [])\n spalls.push([layer.index, face, lp[0], lp[1], lp[2], radius])\n if (spalls.length > MAX_SPALLS) spalls.shift()\n markDamaged(p)\n emit({ ...base(o, src), type: 'spall', part: p.spec.id, layer: layer.index, point: wp, area: Math.PI * radius * radius })\n debris(o, p, layer.mat.hitDebris, wp, normal, 5, 2, src)\n setStage(o, p, 1, {}, src)\n }\n\n const insideOpening = (o: ObjRT, p: PartRT, objectPoint: Vec3): boolean => {\n const op = p.st.opening\n if (!op) return false\n const [u, v] = planeAxes(p.thin)\n const lp = toLocal(p.pos, p.q, objectPoint)\n const lc = toLocal(p.pos, p.q, op.center)\n return Math.hypot(lp[u] - lc[u], lp[v] - lc[v]) <= op.radius\n }\n\n /** Square metres of wall a blow removes: the volume its damage takes out, over the thickness it crosses. */\n const breachAreaOf = (p: PartRT, damage: number, blast: boolean): number =>\n (damage / (p.mat.hpPerKg * p.mat.density) / Math.max(p.thickness, 0.005)) * (blast ? breachBlastFactor : 1)\n\n const localHolesOf = (p: PartRT): LocalHole[] =>\n p.st.holes.map((h) => ({ point: toLocal(p.pos, p.q, h.point), normal: rotateVec(quat.conjugate(p.q), h.normal), diameter: h.diameter }))\n\n const unitsOf = (p: PartRT) => p.spec.units ?? { size: [p.mat.fragmentSize?.[1] ?? 0.2, p.mat.fragmentSize?.[1] ?? 0.2, p.thickness] as Vec3, bond: 'stack' as const }\n\n const FRAGMENT_SHAPE = { shatter: 'shard', splinter: 'splinter', tear: 'scrap' } as const\n\n /** Unit-sized fragments of `cells` (part-local), thrown from `hitW`; the holes that fell on a unit stay on it as `marks`. */\n const cellFragments = (o: ObjRT, p: PartRT, cells: readonly UnitCell[], hitW: Vec3, dir: Vec3 | null, speed: number, mass: number, tag: string): Fragment[] => {\n const { c, q } = partXf(o, p)\n const holes = p.st.holes.length > 0 ? localHolesOf(p) : []\n const [u, v] = planeAxes(p.thin)\n const faceArea = (cell: UnitCell) => cell.size[u] * cell.size[v]\n const total = cells.reduce((sum, cell) => sum + faceArea(cell), 0) || 1\n const shape = p.spec.units ? 'chunk' : FRAGMENT_SHAPE[p.mat.fracture as keyof typeof FRAGMENT_SHAPE] ?? 'chunk'\n return cells.map((cell, i) => {\n const cw = toWorld(c, q, cell.center)\n const out = vec.normalize(vec.sub(cw, hitW), [0, 1, 0])\n const dv = dir ? vec.normalize(vec.madd(out, dir, 0.6)) : out\n const k = speed * (0.6 + 0.8 * rnd())\n const marks = marksInBox(cell.center, cell.size, undefined, holes)\n return {\n id: `${p.spec.id}#${tag}${i}`, part: p.spec.id, material: p.spec.material, shape, center: cw, size: [cell.size[0], cell.size[1], cell.size[2]], rotation: q,\n velocity: [dv[0] * k, dv[1] * k + 0.5 * rnd(), dv[2] * k], angularVelocity: [(rnd() - 0.5) * 8, (rnd() - 0.5) * 8, (rnd() - 0.5) * 8],\n mass: (mass * faceArea(cell)) / total, ...(marks.length > 0 ? { marks } : {}),\n }\n })\n }\n\n const worldBars = (o: ObjRT, p: PartRT, bars: ReadonlyArray<readonly [Vec3, Vec3]>): Array<[Vec3, Vec3]> => {\n const { c, q } = partXf(o, p)\n return bars.map(([a, b]) => [toWorld(c, q, a), toWorld(c, q, b)])\n }\n\n /** A blow that made through damage of `area` m² at `wp` (world): adds up with the earlier ones within the breach radius, and opens the part past its threshold. */\n const addBreach = (o: ObjRT, p: PartRT, wp: Vec3, area: number, energy: number, dir: Vec3 | null, src?: string) => {\n if (!p.staged || area <= 0 || (p.st.stage ?? 0) >= 2 || p.st.stripped || isLost(p)) return\n const lp = objLocal(o, wp)\n const list = (p.rt.breach ??= [])\n list.push([lp[0], lp[1], lp[2], area])\n if (list.length > MAX_SPALLS) list.shift()\n let total = 0\n const sum: Vec3 = [0, 0, 0]\n for (const [x, y, z, a] of list) {\n if (vec.distance([x, y, z], lp) > breachRadius) continue\n total += a\n sum[0] += x * a\n sum[1] += y * a\n sum[2] += z * a\n }\n if (total < (p.spec.breach?.area ?? BREACH_AREA)) return\n openBreach(o, p, [sum[0] / total, sum[1] / total, sum[2] / total], total, energy, dir, src)\n }\n\n /**\n * Stage 2: the units around `center` (object-local) come out as fragments the size of one unit, the part keeps an opening and its mass drops. An\n * opening as wide as the part cuts it in two (a column, a lintel): that is a fracture instead.\n */\n const openBreach = (o: ObjRT, p: PartRT, center: Vec3, total: number, energy: number, dir: Vec3 | null, src?: string) => {\n const [u, v] = planeAxes(p.thin)\n const radius = clamp(Math.sqrt(total / Math.PI), Math.sqrt((p.spec.breach?.area ?? BREACH_AREA) / Math.PI), breachRadius)\n const lc = toLocal(p.pos, p.q, center)\n lc[p.thin] = 0\n const { c, q } = partXf(o, p)\n const worldCenter = toWorld(c, q, lc)\n if (2 * radius >= Math.min(p.dims[u], p.dims[v])) {\n failPart(o, p, worldCenter, dir, energy, 12, src)\n return\n }\n const cells = cellsWithin(unitGrid(p.dims, p.thin, unitsOf(p), BREACH_GRID_CAP), p.thin, lc, radius)\n const removed = (p.st.mass * cells.reduce((sum, cell) => sum + cell.size[u] * cell.size[v], 0)) / (p.dims[u] * p.dims[v])\n const speed = clamp(Math.sqrt((2 * energy * 0.1) / Math.max(removed, 0.05)), 0.5, 8)\n const fragments = cellFragments(o, p, cells, worldCenter, dir, speed, removed, 'b')\n const holes = localHolesOf(p)\n p.st.holes = p.st.holes.filter((_, i) => !cells.some((cell) => marksInBox(cell.center, cell.size, undefined, [holes[i]!]).length > 0))\n p.st.mass = Math.max(0, p.st.mass - removed)\n p.rt.removed = (p.rt.removed ?? 0) + removed\n p.st.opening = { center: objLocal(o, worldCenter), radius }\n markDamaged(p)\n setStage(o, p, 1, {}, src)\n setStage(o, p, 2, { opening: { center: worldCenter, radius }, fragments }, src)\n debris(o, p, p.mat.breakDebris, worldCenter, vec.scale(dir ?? [0, 1, 0], -1), 14, 3, src)\n const reinforcement = p.spec.reinforcement\n if (reinforcement) {\n const bars = worldBars(o, p, clipBarsToDisc(rebarBars(p.dims, p.thin, reinforcement.spacing), u, v, [lc[u], lc[v]], radius + 0.05))\n if (bars.length > 0) emit({ ...base(o, src), type: 'expose', part: p.spec.id, bars })\n }\n if (p.structural) solveStructure(o)\n }\n\n /** The concrete of a reinforced part is gone: the part stays as its rebar cage, with the capacity the reinforcement leaves it. */\n const stripPart = (o: ObjRT, p: PartRT, reinforcement: NonNullable<PartSpec['reinforcement']>, src?: string) => {\n const bars = rebarBars(p.dims, p.thin, reinforcement.spacing)\n p.st.stripped = true\n p.st.hp = p.st.maxHp\n p.st.mass = rebarMass(bars, reinforcement.diameter, materials.get(reinforcement.material)?.density)\n p.st.holes = []\n p.st.burning = false\n p.rt.jet = false\n markDamaged(p)\n emit({ ...base(o, src), type: 'expose', part: p.spec.id, bars: worldBars(o, p, bars) })\n solveStructure(o)\n collapseCheck(o, src)\n }\n\n /** The units of the part that are still there (the opening of a breach is already gone), as a fragment plan. */\n const unitFragmentPlan = (p: PartRT, cap: number): PlannedFragment[] => {\n const grid = unitGrid(p.dims, p.thin, unitsOf(p), cap)\n const op = p.st.opening\n const cells = op ? cellsOutside(grid, p.thin, toLocal(p.pos, p.q, op.center), op.radius) : grid\n const [u, v] = planeAxes(p.thin)\n return cells.map((cell) => ({ center: cell.center, size: cell.size, q: quat.identity(), shape: 'chunk' as const, weight: cell.size[u] * cell.size[v] }))\n }\n\n /** The bare cage gives way (overload, a blast, a cut that finishes): the part is lost for good. */\n const loseCage = (o: ObjRT, p: PartRT, src?: string) => {\n p.st.status = 'broken'\n p.st.hp = 0\n p.st.mass = 0\n emit({ ...base(o, src), type: 'expose', part: p.spec.id, bars: [] })\n debris(o, p, 'sparks', partXf(o, p).c, [0, 1, 0], 6, 3, src)\n partLost(o, p, src)\n }\n\n /**\n * A reinforced beam or slab that fails in bending folds at the hinge and comes down in one piece, held together by its bars: the joints it rests on\n * open, it keeps what rests on it, and it falls (a `collapse` follows) instead of turning to rubble.\n */\n const hingeDrop = (o: ObjRT, p: PartRT, src?: string) => {\n const i = o.idx.get(p.spec.id)!\n const opened: JointRT[] = []\n for (const j of o.byPart.get(p.spec.id) ?? []) {\n if (j.st.open || restsOn(o, j, i) < 0) continue\n j.st.open = true\n j.st.hp = 0\n j.st.openedBy = 'break'\n opened.push(j)\n }\n p.st.hp = Math.max(1, p.st.maxHp * 0.1)\n p.st.cracked = true\n markDamaged(p)\n debris(o, p, p.mat.breakDebris, partXf(o, p).c, [0, -1, 0], 12, 2, src)\n solveStructure(o)\n recomputeGroups(o)\n detachEvents(o, opened, 'break', src)\n collapseCheck(o, src)\n }\n\n /** Part hit points reached 0 (or it was forced to explode): fragments, debris, joints open. */\n const failPart = (o: ObjRT, p: PartRT, origin: Vec3 | null, dir: Vec3 | null, fragEnergy: number, cap: number, src?: string, force?: FractureStyle) => {\n if (isLost(p)) return\n if (p.st.stripped) {\n loseCage(o, p, src)\n return\n }\n if (!force && p.bend && (p.st.flexure ?? 0) > 1 && sectionOf(p, p.bend.gravity).reinforced) {\n hingeDrop(o, p, src)\n return\n }\n const ex = p.spec.explodes\n const style = force ?? (p.snap ? 'snap' : p.mat.fracture === 'none' ? 'snap' : p.mat.fracture)\n const { c, q } = partXf(o, p)\n const hitW = origin ?? c\n const grain = p.spec.grain ? AXIS[p.spec.grain] : undefined\n const hitLocal = toLocal(c, q, hitW)\n const unitPlan = p.spec.units ? unitFragmentPlan(p, maxFragments * UNIT_FRAGMENT_FACTOR) : []\n const plan = unitPlan.length > 0 ? unitPlan : planFragments({\n style, dims: p.dims, thickness: p.thickness, grain, hit: hitLocal, fragmentSize: p.mat.fragmentSize ?? [0.04, 0.2], maxFragments, rnd,\n })\n const holes = p.st.holes.length > 0 ? localHolesOf(p) : []\n const mass = p.st.mass\n const totW = plan.reduce((s, f) => s + f.weight, 0) || 1\n const energy = ex ? ex.energy * 0.2 : fragEnergy\n const speed = clamp(Math.sqrt((2 * energy) / Math.max(mass, 0.05)), 0.3, ex ? 40 : cap)\n const fragments: Fragment[] = plan.map((f, i) => {\n const cw = toWorld(c, q, f.center)\n const out = vec.normalize(vec.sub(cw, hitW), [0, 1, 0])\n const dv = dir ? vec.normalize(vec.madd(out, dir, 0.6)) : out\n const k = speed * (0.6 + 0.8 * rnd())\n const marks = marksInBox(f.center, f.size, f.q, holes)\n return {\n id: `${p.spec.id}#${i}`, part: p.spec.id, material: p.spec.material, shape: f.shape, center: cw, size: f.size, rotation: quat.mul(q, f.q),\n velocity: [dv[0] * k, dv[1] * k + 0.5 * rnd(), dv[2] * k],\n angularVelocity: [(rnd() - 0.5) * 12, (rnd() - 0.5) * 12, (rnd() - 0.5) * 12],\n mass: (mass * f.weight) / totW, ...(marks.length > 0 ? { marks } : {}),\n }\n })\n const reinforcement = p.spec.reinforcement\n if (!reinforcement) {\n p.st.status = 'broken'\n p.st.hp = 0\n p.st.mass = 0\n p.st.burning = false\n p.rt.jet = false\n }\n emit({ ...base(o, src), type: 'fracture', part: p.spec.id, style, fragments, point: hitW })\n debris(o, p, p.mat.breakDebris, c, [0, 1, 0], clamp(Math.round(Math.cbrt(partVolume(p.spec.shape)) * 30), 3, 20), 2, src)\n setStage(o, p, 3, {}, src)\n if (reinforcement) {\n stripPart(o, p, reinforcement, src)\n return\n }\n if (ex) {\n emit({ ...base(o, src), type: 'explode', part: p.spec.id, point: c, energy: ex.energy, radius: ex.radius, ...(ex.lethalRadius !== undefined ? { lethalRadius: ex.lethalRadius } : {}), ...(ex.effect !== undefined ? { effect: ex.effect } : {}) })\n blasts.push({ point: c, energy: ex.energy, radius: ex.radius, ...(ex.lethalRadius !== undefined ? { lethalRadius: ex.lethalRadius } : {}), source: src })\n }\n partLost(o, p, src)\n }\n\n /**\n * Sets an explosive part off from outside (`explodes.chain`): it will explode after the delay of `trigger`, once. The delay is one draw\n * from the world seed, so the same inputs give the same order of blasts.\n */\n const prime = (o: ObjRT, p: PartRT, trigger: ChainTrigger, src?: string) => {\n const spec = chainDelayOf(p.spec, trigger)\n if (spec === undefined || isLost(p) || p.rt.chainDue !== undefined) return\n const delay = drawChainDelay(spec, rnd)\n p.rt.chainDue = time + delay\n primed.set(p, o)\n o.active = true\n emit({ ...base(o, src), type: 'primed', part: p.spec.id, point: partXf(o, p).c, trigger, delay })\n }\n\n const CHAIN_TRIGGER_OF: Partial<Record<DamageType, ChainTrigger>> = { ballistic: 'shot', explosive: 'explosion' }\n\n /** Remove hit points. Returns the amount actually removed. */\n const applyDamage = (o: ObjRT, p: PartRT, amount: number, type: DamageType, origin: Vec3 | null, dir: Vec3 | null, fragEnergy: number, cap: number, src?: string): number => {\n if (isLost(p) || amount <= 0) return 0\n const prev = p.st.hp\n p.st.hp -= amount\n markDamaged(p)\n const trigger = CHAIN_TRIGGER_OF[type]\n const chained = trigger !== undefined && chainDelayOf(p.spec, trigger) !== undefined\n // a bullet or a blast sets a chained part off after its delay instead of tearing it apart on the spot\n if (chained && p.st.hp <= 0 && p.rt.chainDue === undefined) p.st.hp = Math.min(prev, 1)\n if (p.st.hp <= 0 && p.mat.fracture === 'none' && !p.spec.explodes) p.st.hp = Math.min(prev, 1)\n const done = prev - p.st.hp\n if (done > 0) emit({ ...base(o, src), type: 'damage', part: p.spec.id, amount: done, hp: Math.max(0, p.st.hp), damageType: type })\n if (p.st.hp <= 0) failPart(o, p, origin, dir, fragEnergy, cap, src)\n else if (chained && (trigger === 'explosion' || 1 - p.st.hp / p.st.maxHp >= shotDamageFractionOf(p.spec))) prime(o, p, trigger, src)\n return done\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Hits\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n /** A container of flammable fluid with a hole that goes through: it leaks. */\n const leaksFlammable = (p: PartRT): boolean => {\n const c = p.spec.contains\n return !!c && FLAMMABLE_FLUIDS.includes(c.fluid) && (p.st.liters ?? 0) > 0 && p.st.holes.some((h) => h.through)\n }\n\n /**\n * A round that went through the wall of a container of flammable fluid lights the leak or does not: the spark of a hard round on metal and the\n * flame of an incendiary or tracer (`Hit.ignition`, `Hit.incendiary`, `Hit.tracer`), weighed by how full the container is (`options.ignition`).\n * A plain bullet carries neither and only leaks. The part burns or goes off at the next `update` (`rt.lit`).\n */\n const rollIgnition = (o: ObjRT, p: PartRT, round: BallisticExtras) => {\n const c = p.spec.contains\n if (!c || !FLAMMABLE_FLUIDS.includes(c.fluid) || p.rt.jet || p.rt.lit) return\n const fill = c.liters > 0 ? (p.st.liters ?? 0) / c.liters : 0\n const chance = ignitionChance(round, { sparkTarget: sparkTargetFactor(p.mat.id, !!p.mat.tags?.includes('metal'), ignitionRules), fill, fluid: c.fluid }, ignitionRules)\n if (chance > 0 && rnd() < chance) {\n p.rt.lit = true\n o.active = true\n }\n }\n\n /** What is lit by a fire or a blast near: the leaks of flammable fluid within `radius` of `centre` (object parts only). */\n const lightLeaksNear = (centre: Vec3, radius: number) => {\n for (const o of objects.values()) {\n for (const q of o.parts) {\n if (isLost(q) || q.rt.lit || q.rt.jet || !leaksFlammable(q)) continue\n if (vec.distance(partXf(o, q).c, centre) - q.bound > radius) continue\n q.rt.lit = true\n o.active = true\n }\n }\n }\n\n interface BallisticOut { penetrated: boolean; exitEnergy: number; exitPoint?: Vec3; damage: number }\n\n const ballistic = (o: ObjRT, p: PartRT, entry: Vec3, n: Vec3, d: Vec3, E: number, caliber: number, pathLen: number, src?: string, round: BallisticExtras = {}): BallisticOut => {\n const mat = p.mat\n const piercing = round.piercing ?? 1\n // a bare cage and an opening do not stop a bullet\n if (p.st.stripped || (p.st.opening && insideOpening(o, p, objLocal(o, entry)))) {\n return { penetrated: true, exitEnergy: E, exitPoint: vec.madd(entry, d, Math.min(pathLen, p.thickness)), damage: 0 }\n }\n const sin = Math.min(1, Math.abs(vec.dot(d, n)))\n const angle = (Math.asin(sin) * 180) / Math.PI\n const slant = Math.max(sin, 0.3)\n const effM = p.thickness / slant\n const face = p.layers.length > 0 ? faceOf(o, p, n) : 1\n const exitLocal = objLocal(o, vec.madd(entry, d, Math.min(pathLen, effM)))\n const coats = p.layers.length > 0 ? layersEnergy(p.layers, p.rt.spalls, face, objLocal(o, entry)) + layersEnergy(p.layers, p.rt.spalls, -face, exitLocal) : 0\n // each coat adds penetration x thickness to the core's; a part without layers keeps the plain formula\n const thr = coats > 0 ? (mat.penetration * p.thickness * 1000 + coats) / slant : mat.penetration * effM * 1000\n // the bullet's kind matters against hard targets (steel, masonry); wood, flesh and the like take every bullet for its energy\n const hard = mat.tags?.includes('metal') || mat.tags?.includes('masonry')\n // a round that carries its penetration (mm by material class) goes through a part as thick as that, whatever the energy says; else the energy rule with `piercing`\n const penMm = penetrationOf(mat, round.penetration)\n const Ep = penMm !== undefined ? penMm * mat.penetration : piercing === 1 || !hard ? E : E * piercing\n const penetrated = Ep > thr\n // a thin brittle shell that shatters (a pane, a bottle) is lost to one bullet that a thick block of the same glass shrugs off: the same\n // fragility factor that melee uses for blunt hits (1 for ductile materials and for shells 2 cm or thicker, up to x118 for 3 mm glass)\n const scale = (mat.damageScale?.ballistic ?? 1) * (mat.fracture === 'shatter' ? fragility(mat.ductility, p.thickness) : 1)\n const id = p.spec.id\n if (!penetrated && mat.ricochetDeg && angle < mat.ricochetDeg) {\n const r = vec.sub(d, vec.scale(n, 2 * vec.dot(d, n)))\n emit({ ...base(o, src), type: 'ricochet', part: id, point: entry, direction: vec.normalize(r), energy: E * 0.4 })\n debris(o, p, mat.hitDebris, entry, n, 3, 3, src)\n const dmg = applyDamage(o, p, E * DMG_PER_J * scale * 0.2, 'ballistic', entry, d, E * 0.1, 12, src)\n return { penetrated: false, exitEnergy: 0, damage: dmg }\n }\n if (p.layers.length > 0) spallOuter(o, p, entry, face, n, Math.max(0.03, (caliber / 1000) * 4), src)\n const brittle = mat.ductility < 0.3\n const ratio = Ep / Math.max(thr, 1e-6)\n const crackLen = clamp(0.03 + ratio * 0.2, 0.03, 0.8)\n let exitPoint: Vec3 | undefined\n if (penetrated) {\n exitPoint = vec.madd(entry, d, Math.min(pathLen, effM + layersThickness(p.layers, face) / slant + layersThickness(p.layers, -face) / slant))\n const hole = addHole(o, p, entry, n, (caliber / 1000) * (mat.ductility >= 0.3 ? 1 : 1.5), true, exitPoint, src)\n if (p.layers.length > 0) spallOuter(o, p, exitPoint, -face, vec.scale(n, -1), Math.max(0.03, (caliber / 1000) * 4), src)\n addBreach(o, p, entry, Math.PI * (hole.diameter / 2) * (hole.diameter / 2), E, d, src)\n // a thin ductile sheet is dished around the hole it is punched through: deeper the more energy the shot carries\n if (mat.ductility >= 0.5 && p.thickness <= THIN_SHEET_DISHING) addDent(o, p, entry, n, Math.max((caliber * 3) / 1000, 0.012), clamp(E * 0.00002, 0.001, 0.03), src)\n if (brittle && mat.fracture === 'shatter') addCrack(o, p, entry, n, crackLen, src)\n if (p.spec.contains && (p.st.liters ?? 0) > 0) {\n emit({\n ...base(o, src), type: 'leak', part: id, fluid: p.spec.contains.fluid, point: entry,\n direction: p.spec.contains.outflow ? vec.normalize(rotateVec(o.st.rotation, rotateVec(p.q, p.spec.contains.outflow))) : n, rate: holeRate(hole, !!p.spec.contains.pressurized),\n pressurized: !!p.spec.contains.pressurized,\n })\n rollIgnition(o, p, round)\n }\n } else if (mat.ductility >= 0.5) {\n addDent(o, p, entry, n, Math.max((caliber * 3) / 1000, 0.012), clamp(Math.min(Math.max(p.thickness * 3, 0.003), ratio * 0.01), 0.001, 0.05), src)\n } else if (brittle) {\n addCrack(o, p, entry, n, crackLen, src)\n if (mat.fracture !== 'shatter') addHole(o, p, entry, n, caliber / 1000, false, undefined, src)\n } else addHole(o, p, entry, n, caliber / 1000, false, undefined, src)\n debris(o, p, mat.hitDebris, entry, n, clamp(Math.round(E / 60) + 2, 2, 14), clamp(Math.sqrt(E) / 6, 1, 8), src)\n // a bullet only wears the joints of the part it hits, by the energy the part absorbed (a through-and-through shot transfers little)\n wearJoints(o, p, (penetrated ? thr : E) * 0.02, undefined, 0, src, true)\n const dmg = applyDamage(o, p, E * DMG_PER_J * scale, 'ballistic', entry, d, E * 0.1, 12, src)\n return { penetrated, exitEnergy: penetrated ? (penMm !== undefined ? E * (1 - thr / Ep) : E - thr / (hard ? piercing : 1)) : 0, exitPoint, damage: dmg }\n }\n\n const melee = (o: ObjRT, p: PartRT, kind: 'blunt' | 'slash', E: number, point: Vec3, n: Vec3, d: Vec3, contactR: number, src?: string): number => {\n const mat = p.mat\n const thrMm = mat.penetration * p.thickness * 1000\n // brittle thin shells (a bottle, a mug, a pane) break from a knock that a thick block shrugs off\n const fragile = kind === 'blunt' ? fragility(mat.ductility, p.thickness) : 1\n const Ec = E * fragile\n if (E > 0) {\n if (kind === 'blunt') {\n if (mat.ductility >= 0.5) addDent(o, p, point, n, Math.max(contactR, 0.015), clamp(E * 0.0001, 0.001, 0.06), src)\n else if (mat.ductility < 0.3) {\n if (Ec >= 5) addCrack(o, p, point, n, clamp(0.04 + Math.min(Ec, E * 6) * 0.0008, 0.04, 0.6), src)\n } else if (E >= thrMm * 0.2) addDent(o, p, point, n, Math.max(contactR, 0.015), clamp(E * 0.00006, 0.001, 0.04), src)\n } else if (mat.fracture === 'tear') {\n addHole(o, p, point, n, clamp(0.02 + E * 0.0005, 0.02, 0.3), true, undefined, src)\n } else if (mat.ductility >= 0.5) {\n addDent(o, p, point, n, Math.max(contactR, 0.01), clamp(E * 0.00004, 0.0005, 0.02), src)\n }\n debris(o, p, mat.hitDebris, point, n, clamp(Math.round(E / 25) + 1, 1, 10), clamp(Math.sqrt(E) / 8, 1, 6), src)\n }\n // a blow shakes the joints of the part it lands on, except on the terrain a structure stands on (an anchored part tagged `terrain`): a piece that lands on the\n // ground does not loosen every wall that stands on it\n if (kind === 'blunt') {\n if (!(p.anchored && p.spec.tags?.includes('terrain'))) wearJoints(o, p, E * 0.3, undefined, 0, src)\n } else wearJoints(o, p, E * 0.3, point, 0.06, src)\n if (kind === 'blunt' && E > 0 && p.layers.length > 0) spallOuter(o, p, point, faceOf(o, p, n), n, Math.max(contactR, 0.05), src)\n const scale = mat.damageScale?.[kind] ?? 1\n const done = applyDamage(o, p, Ec * DMG_PER_J * scale * (kind === 'slash' ? p.cutFactor : 1), kind, point, d, E * 0.1, 12, src)\n addBreach(o, p, point, breachAreaOf(p, done, false), E, d, src)\n return done\n }\n\n /**\n * What one part takes of a blast: dents, cracks, debris, heat, joint wear and the hit points. `reach` is the share of the blast that gets to the\n * part (`blast.shelter`; 1 without it) and it comes back, so a caller can report it. It is computed from the point of the part nearest to the centre.\n */\n const blastPart = (o: ObjRT, p: PartRT, point: Vec3, energy: number, radius: number, src: string | undefined, res: HitResult, reachAt?: (wp: Vec3, p: PartRT) => number): number | null => {\n if (isLost(p)) return null\n const { c, q } = partXf(o, p)\n const lp = toLocal(c, q, point)\n const dist = distanceToShape(p.spec.shape, lp)\n if (dist >= radius) return null\n const sp = surfacePoint(p.spec.shape, lp)\n const wp = toWorld(c, q, sp.point)\n const reach = reachAt ? reachAt(wp, p) : 1\n const f = (1 - dist / radius) ** 2 * reach\n const Ein = energy * f * BLAST_COUPLING\n const wn = rotateVec(q, sp.normal)\n if (!res.part) {\n res.part = p.spec.id\n res.point = wp\n }\n const mat = p.mat\n if (Ein > 20) {\n if (mat.ductility >= 0.5) addDent(o, p, wp, wn, clamp(0.05 + Math.sqrt(Ein) * 0.002, 0.05, 0.4), clamp(0.004 + Ein * 0.00002, 0.004, 0.08), src)\n else if (mat.ductility < 0.3 && Ein > 60) addCrack(o, p, wp, wn, clamp(0.05 + Ein * 0.0005, 0.05, 1), src)\n debris(o, p, mat.hitDebris, wp, wn, clamp(Math.round(Ein / 80) + 1, 1, 12), clamp(Math.sqrt(Ein) / 4, 2, 15), src)\n }\n const th = mat.thermal\n if (th.ignitionC !== undefined && p.st.fuel > 0) {\n p.st.temperature += 300 * f\n o.active = true\n if (f >= 0.25 && !p.st.burning) {\n p.st.temperature = Math.max(p.st.temperature, th.ignitionC + 1)\n checkIgnite(o, p, src)\n }\n }\n wearJoints(o, p, Ein * 0.5, undefined, 0, src)\n const amount = Ein * DMG_PER_J * (mat.damageScale?.explosive ?? 1)\n if (blastFrontSpeed > 0 && dist > 0 && mat.tags?.includes('glass')) {\n frontQueue.push({ o, p, due: time + dist / blastFrontSpeed, amount, fragEnergy: Ein * 0.3, point, ...(src !== undefined ? { src } : {}) })\n return reach\n }\n if (Ein > 20 && p.layers.length > 0) spallOuter(o, p, wp, faceOf(o, p, wn), wn, clamp(0.05 + Math.sqrt(Ein) * 0.002, 0.05, 0.4), src)\n const dealt = applyDamage(o, p, amount, 'explosive', point, null, Ein * 0.3, 40, src)\n res.damage += dealt\n if (p.bend && flexure.enabled) bendByBlast(o, p, point, energy, radius, reach, src)\n if (dist <= BREACH_BLAST_REACH * Math.cbrt(Math.max(0, energy) / 1000)) addBreach(o, p, wp, breachAreaOf(p, dealt, true), Ein, null, src)\n return reach\n }\n\n const blastObject = (o: ObjRT, point: Vec3, energy: number, radius: number, src?: string): HitResult => {\n const start = cur.length\n const res: HitResult = { object: o.id, damage: 0, penetrated: false, exitEnergy: 0, events: [] }\n for (const p of o.parts) blastPart(o, p, point, energy, radius, src, res)\n res.events = cur.slice(start)\n return res\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Blast options: shelter, fragment hits, confinement (all off by default)\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n interface BlastCfg {\n shelter: Required<ShelterOptions> | null\n frag: Required<FragmentHitOptions> | null\n /** A number is the multiplier itself. */\n conf: Required<ConfinementOptions> | number | null\n }\n\n const blastCfg = (call?: BlastOptions): BlastCfg => {\n const pick = <K extends keyof BlastOptions>(key: K): BlastOptions[K] => (call && call[key] !== undefined ? call[key] : options.blast?.[key])\n const merge = <T extends object>(v: boolean | T | undefined, defaults: Required<T>): Required<T> | null => {\n if (!v) return null\n const out = { ...defaults }\n if (v !== true) for (const [key, value] of Object.entries(v)) if (value !== undefined) (out as Record<string, unknown>)[key] = value\n return out\n }\n const conf = pick('confinement')\n return {\n shelter: merge(pick('shelter'), SHELTER_DEFAULTS),\n frag: merge(pick('fragmentHits'), FRAGMENT_HIT_DEFAULTS),\n conf: typeof conf === 'number' ? (Number.isFinite(conf) ? Math.max(0, conf) : 1) : merge(conf, CONFINEMENT_DEFAULTS),\n }\n }\n\n /** Same directions in every blast of this world: a Fibonacci lattice turned by the world seed. */\n const confinementRays = new Map<number, Vec3[]>()\n const raysOf = (n: number): Vec3[] => {\n let rays = confinementRays.get(n)\n if (rays) return rays\n const r = createRng((options.seed ?? 1) ^ 0x5bd1e995)\n const off = r.next()\n const phi0 = r.next() * Math.PI * 2\n rays = []\n for (let i = 0; i < n; i++) {\n const y = 1 - (2 * (i + off)) / n\n const s = Math.sqrt(Math.max(0, 1 - y * y))\n const phi = phi0 + i * 2.399963229728653\n rays.push([Math.cos(phi) * s, y, Math.sin(phi) * s])\n }\n confinementRays.set(n, rays)\n return rays\n }\n\n /** Pressure multiplier of a blast at `point`: the host's number, or an estimate from rays that hit parts (never the ones that are lost or open). */\n const confinementOf = (conf: BlastCfg['conf'], point: Vec3, radius: number): number => {\n if (conf === null) return 1\n if (typeof conf === 'number') return conf\n let hits = 0\n let sum = 0\n for (const d of raysOf(Math.max(1, Math.round(conf.rays)))) {\n const h = raycastInternal(point, d, radius * conf.reach, undefined, true)\n if (h) {\n hits++\n sum += h.distance\n }\n }\n if (hits === 0) return 1\n const closed = hits / Math.max(1, Math.round(conf.rays))\n const ratio = clamp(radius / Math.max(sum / hits, 1e-3), 0, 2)\n return Math.min(Math.max(1, conf.max), 1 + conf.gain * closed ** conf.power * ratio)\n }\n\n const FLAG_LOST = 1\n const FLAG_OPEN = 2\n\n /** The legacy blast: every part of every object, then every impl, each at full strength. */\n const blastPlain = (point: Vec3, energy: number, radius: number, src?: string, lethal?: number): HitResult[] => {\n const out: HitResult[] = []\n for (const o of [...objects.values()]) {\n if (vec.distance(toWorld(o.st.position, o.st.rotation, o.bc), point) - o.br >= radius) continue\n const r = blastObject(o, point, energy, radius, src)\n if (r.part) out.push(r)\n }\n for (const im of [...impls.values()]) {\n if (implInRange(im, point, radius)) out.push(implHit(im, { type: 'explosive', point, energy, radius, ...(lethal !== undefined ? { lethalRadius: lethal } : {}), ...(src !== undefined ? { source: src } : {}) }))\n }\n return out\n }\n\n const implParts = (im: ImplRT) =>\n im.impl.describe().parts.map((ps) => {\n const ov = im.poses.get(ps.id)\n return { ps, c: toWorld(im.position, im.rotation, ov?.pos ?? ps.position), q: quat.mul(im.rotation, ov?.q ?? quatFromEuler(...(ps.rotation ?? [0, 0, 0]))) }\n })\n\n const implInRange = (im: ImplRT, point: Vec3, radius: number): boolean => implParts(im).some(({ ps, c, q }) => distanceToShape(ps.shape, toLocal(c, q, point)) < radius)\n\n /** A blast with shelter, fragment hits or confinement. Parts are served from the nearest to the farthest, so a wall takes the blast (and may break) before what is behind it. */\n const blastScene = (point: Vec3, energy: number, radius: number, src: string | undefined, cfg: BlastCfg, only?: ObjRT | ImplRT, lethal?: number): HitResult[] => {\n const mult = confinementOf(cfg.conf, point, radius)\n const E = energy * mult\n const shelter = cfg.shelter\n const flags = new Map<PartRT, number>()\n const inRange: ObjRT[] = []\n for (const o of objects.values()) {\n if (vec.distance(toWorld(o.st.position, o.st.rotation, o.bc), point) - o.br >= radius) continue\n inRange.push(o)\n if (shelter) for (const p of o.parts) flags.set(p, (isLost(p) ? FLAG_LOST : 0) | (p.st.opening || p.st.stripped ? FLAG_OPEN : 0))\n }\n // what each blocker stands in front of, to aim its fragments\n const shields = new Map<PartRT, Vec3[]>()\n /** Share of the blast that gets to `tp` (world) through everything between it and the centre; `self` never blocks. */\n const reachAt = (tp: Vec3, self: PartRT | null): number => {\n if (!shelter) return 1\n const L = vec.distance(point, tp)\n if (L < 1e-4) return 1\n const d = vec.scale(vec.sub(tp, point), 1 / L)\n let t = 1\n for (const o of inRange) {\n if (raySphereMiss(point, d, toWorld(o.st.position, o.st.rotation, o.bc), o.br, L)) continue\n for (const p of o.parts) {\n if (p === self) continue\n const was = flags.get(p) ?? 0\n if (was & FLAG_LOST) continue\n const r = rayPart(o, p, point, d)\n if (!r) continue\n const t0 = Math.max(r.t0, 0)\n const path = Math.min(r.t1, L) - t0\n if (path < shelter.minPath) continue\n const mid = vec.madd(point, d, t0 + path / 2)\n const opening = p.st.opening && insideOpening(o, p, mid)\n if (opening && was & FLAG_OPEN) continue\n if (p.st.stripped && was & FLAG_OPEN) continue\n const resistance = p.mat.hpPerKg * p.mat.density * path * (p.mat.damageScale?.shelter ?? 1)\n let ti = Math.exp(-resistance / shelter.k)\n // destroyed or breached by this same blast: part of what it held back goes through\n if (isLost(p) || opening || (p.st.stripped && !(was & FLAG_OPEN))) ti += (1 - ti) * shelter.brokenTransmission\n t *= ti\n if (cfg.frag) {\n let list = shields.get(p)\n if (!list) shields.set(p, (list = []))\n list.push(tp)\n }\n }\n }\n return t\n }\n\n interface Item { dist: number; order: number; o?: ObjRT; p?: PartRT; im?: ImplRT }\n const items: Item[] = []\n let order = 0\n for (const o of inRange) {\n if (only && only !== o) continue\n for (const p of o.parts) {\n if (isLost(p)) continue\n const dist = distToPart(o, p, point)\n if (dist < radius) items.push({ dist, order: order++, o, p })\n }\n }\n for (const im of impls.values()) {\n if (only && only !== im) continue\n let dist = Infinity\n for (const { ps, c, q } of implParts(im)) dist = Math.min(dist, distanceToShape(ps.shape, toLocal(c, q, point)))\n if (dist < radius) items.push({ dist, order: order++, im })\n }\n items.sort((a, b) => a.dist - b.dist || a.order - b.order)\n\n const results = new Map<ObjRT | ImplRT, HitResult>()\n const reports = new Map<ObjRT | ImplRT, BlastReport>()\n const report = (key: ObjRT | ImplRT): BlastReport => {\n let r = reports.get(key)\n if (!r) reports.set(key, (r = { shelter: 0, confinement: mult, fragmentHits: 0 }))\n return r\n }\n const thrown: Array<{ frag: Fragment; object: string; part: PartRT | null }> = []\n const sweep = (from: number) => {\n if (!cfg.frag) return\n for (let i = from; i < cur.length; i++) {\n const e = cur[i]!\n if (e.type !== 'fracture' && e.type !== 'stage') continue\n for (const frag of e.fragments ?? []) thrown.push({ frag, object: e.object, part: objects.get(e.object)?.byId.get(e.part) ?? null })\n }\n }\n\n for (const it of items) {\n if (it.o && it.p) {\n const o = it.o\n let res = results.get(o)\n if (!res) results.set(o, (res = { object: o.id, damage: 0, penetrated: false, exitEnergy: 0, events: [] }))\n const start = cur.length\n const k = blastPart(o, it.p, point, E, radius, src, res, shelter ? reachAt : undefined)\n res.events.push(...cur.slice(start))\n sweep(start)\n if (k !== null) {\n const rep = report(o)\n rep.shelter = Math.max(rep.shelter, k)\n if (shelter) (rep.parts ??= {})[it.p.spec.id] = k\n }\n } else if (it.im) {\n const im = it.im\n // the impl takes one hit: the share of the blast that gets to its parts, weighted by how hard the blast hits each\n let num = 0\n let den = 0\n for (const { ps, c, q } of implParts(im)) {\n const lp = toLocal(c, q, point)\n const dist = distanceToShape(ps.shape, lp)\n if (dist >= radius) continue\n const f = (1 - dist / radius) ** 2\n const sp = surfacePoint(ps.shape, lp)\n num += f * reachAt(toWorld(c, q, sp.point), null)\n den += f\n }\n const k = den > 0 ? num / den : 1\n const res = implHit(im, { type: 'explosive', point, energy: E * k, radius, ...(lethal !== undefined ? { lethalRadius: lethal } : {}), ...(shelter ? { shelter: k } : {}), ...(src !== undefined ? { source: src } : {}) })\n results.set(im, res)\n report(im).shelter = k\n }\n }\n\n if (cfg.frag && thrown.length > 0) {\n const g = cfg.frag\n const energyOf = (f: Fragment) => 0.5 * f.mass * (f.velocity[0] ** 2 + f.velocity[1] ** 2 + f.velocity[2] ** 2)\n const list = thrown\n .map((t, i) => ({ ...t, i, e: energyOf(t.frag) }))\n .sort((a, b) => b.e - a.e || a.i - b.i)\n .slice(0, Math.max(0, Math.floor(g.max)))\n list.forEach((t, i) => throwFragment(t.frag, t.object, t.part, g, point, i, src, shields, results, reports, mult))\n }\n\n const out: HitResult[] = []\n const reportShelter = (key: ObjRT | ImplRT, res: HitResult) => {\n res.blast = reports.get(key) ?? { shelter: 1, confinement: mult, fragmentHits: 0 }\n }\n const summary: Array<{ object: string; part?: string; factor: number }> = []\n let fragmentHits = 0\n for (const o of objects.values()) {\n const r = results.get(o)\n if (!r?.part) continue\n reportShelter(o, r)\n out.push(r)\n for (const [part, factor] of Object.entries(r.blast?.parts ?? {})) summary.push({ object: o.id, part, factor })\n fragmentHits += r.blast?.fragmentHits ?? 0\n }\n for (const im of impls.values()) {\n const r = results.get(im)\n if (!r) continue\n reportShelter(im, r)\n out.push(r)\n if (shelter) summary.push({ object: im.impl.id, factor: r.blast?.shelter ?? 1 })\n fragmentHits += r.blast?.fragmentHits ?? 0\n }\n emit({ type: 'blast', object: '', time, ...(src !== undefined ? { source: src } : {}), point, energy: E, radius, confinement: mult, shelter: summary, fragmentHits })\n return out\n }\n\n /** Integer seed from numbers: a fragment's flight depends only on the blast and on the fragment, not on what the world did before. */\n const seedOf = (...nums: number[]): number => {\n let h = 2166136261\n for (const n of nums) {\n h = Math.imul(h ^ (Math.round(n * 1000) | 0), 16777619)\n h ^= h >>> 15\n }\n return h | 0\n }\n\n /** One fragment of a part the blast broke flies on: a low-energy hit on the first part or impl it reaches within its throw. */\n const throwFragment = (\n frag: Fragment, objectId: string, from: PartRT | null, g: Required<FragmentHitOptions>, centre: Vec3, index: number, src: string | undefined,\n shields: Map<PartRT, Vec3[]>, results: Map<ObjRT | ImplRT, HitResult>, reports: Map<ObjRT | ImplRT, BlastReport>, mult: number,\n ) => {\n const v = frag.velocity\n const speed = Math.hypot(v[0], v[1], v[2])\n const energy = g.energyFactor * 0.5 * frag.mass * speed * speed\n if (speed < 0.5 || energy < 1) return\n const r = createRng(seedOf(options.seed ?? 1, centre[0], centre[1], centre[2], index, frag.center[0], frag.center[1], frag.center[2]))\n let dir = vec.scale(v, 1 / speed)\n // a fragment of a blocker whose flight points at a target behind it goes for that target\n const behind = from ? shields.get(from) : undefined\n if (behind) {\n let best = Math.cos((g.aim * Math.PI) / 180)\n for (const tp of behind) {\n const to = vec.sub(tp, frag.center)\n const len = vec.length(to)\n if (len < 1e-4) continue\n const cos = vec.dot(dir, to) / len\n if (cos >= best) {\n best = cos\n dir = vec.scale(to, 1 / len)\n }\n }\n }\n const spread = Math.tan((g.spread * Math.PI) / 180)\n dir = vec.normalize([dir[0] + (r.next() - 0.5) * 2 * spread, dir[1] + (r.next() - 0.5) * 2 * spread, dir[2] + (r.next() - 0.5) * 2 * spread], dir)\n const range = Math.min(g.range, speed * g.flightTime)\n const origin = vec.madd(frag.center, dir, 0.02)\n const rh = raycastInternal(origin, dir, range, from ? new Set([`${objectId}\\0${from.spec.id}`]) : undefined)\n if (!rh) return\n const hit: Hit = {\n type: g.hitType, point: rh.point, direction: dir, energy, radius: 0.05, part: rh.part,\n ...(g.hitType === 'ballistic' ? { caliber: clamp(Math.max(...frag.size) * 1000, 3, 30), mass: frag.mass * 1000 } : {}),\n ...(src !== undefined ? { source: src } : {}),\n }\n emit({ type: 'fragment_hit', object: objectId, time, ...(src !== undefined ? { source: src } : {}), from: { object: objectId, part: frag.part }, target: { object: rh.object, part: rh.part }, point: rh.point, direction: dir, energy, mass: frag.mass, speed })\n const im = impls.get(rh.object)\n const o = im ? undefined : objects.get(rh.object)\n const key = im ?? o\n if (!key) return\n const res = im ? implHit(im, hit) : doHit(o!, hit, o!.byId.get(rh.part))\n const have = results.get(key)\n if (have) {\n have.damage += res.damage\n have.events.push(...res.events)\n if (!have.part) have.part = res.part\n if (res.penetrated) have.penetrated = true\n } else results.set(key, { ...res, events: [...res.events] })\n let rep = reports.get(key)\n if (!rep) reports.set(key, (rep = { shelter: 1, confinement: mult, fragmentHits: 0 }))\n rep.fragmentHits++\n }\n\n const blastWorld = (point: Vec3, energy: number, radius: number, src?: string, call?: BlastOptions, only?: ObjRT | ImplRT, lethal?: number): HitResult[] => {\n const cfg = blastCfg(call)\n const res = !cfg.shelter && !cfg.frag && cfg.conf === null ? blastPlain(point, energy, radius, src, lethal) : blastScene(point, energy, radius, src, cfg, only, lethal)\n // a blast is a flame: a container that leaks flammable fluid inside it catches\n lightLeaksNear(point, radius)\n return res\n }\n\n const heatObject = (o: ObjRT, point: Vec3, T: number, radius: number, duration: number, src?: string): HitResult => {\n const start = cur.length\n const res: HitResult = { object: o.id, damage: 0, penetrated: false, exitEnergy: 0, events: [] }\n for (const p of o.parts) {\n if (isLost(p)) continue\n const dist = distToPart(o, p, point)\n if (dist >= radius) continue\n const f = clamp(1 - dist / radius, 0.25, 1)\n if (!res.part) {\n res.part = p.spec.id\n res.point = point\n }\n if (T > p.st.temperature) {\n const k = (0.8 * f) / (p.mat.thermal.heatCapacity ?? 1)\n p.st.temperature += (T - p.st.temperature) * (1 - Math.exp(-k * duration))\n }\n o.active = true\n // a flame held against a flammable leak lights it: it burns, or goes off by its chain, at the next update\n if (T >= FLAME_LIGHTS_LEAK_C && !p.rt.jet && !p.rt.lit && leaksFlammable(p)) p.rt.lit = true\n checkIgnite(o, p, src)\n }\n res.events = cur.slice(start)\n return res\n }\n\n const doHit = (o: ObjRT, hit: Hit, only?: PartRT): HitResult => {\n let point = hit.point\n let dir = hit.direction\n if (hit.space === 'local') {\n point = toWorld(o.st.position, o.st.rotation, point)\n if (dir) dir = rotateVec(o.st.rotation, dir)\n }\n const src = hit.source\n const start = cur.length\n let res: HitResult = { object: o.id, damage: 0, penetrated: false, exitEnergy: 0, events: [] }\n const E = hit.energy ?? 0\n if (hit.type === 'ballistic') {\n const loc = locate(o, point, dir, 0.05, only)\n if (loc) {\n const out = ballistic(o, loc.p, loc.point, loc.normal, loc.dir, E, hit.caliber ?? 9, loc.pathLen, src, hit)\n res = { ...res, part: loc.p.spec.id, point: loc.point, damage: out.damage, penetrated: out.penetrated, exitEnergy: out.exitEnergy }\n }\n } else if (hit.type === 'blunt' || hit.type === 'slash') {\n const radius = hit.radius ?? 0\n const loc = locate(o, point, dir, Math.max(0.05, radius), only)\n if (loc) {\n res.part = loc.p.spec.id\n res.point = loc.point\n res.damage += melee(o, loc.p, hit.type, E, loc.point, loc.normal, loc.dir, radius || 0.03, src)\n if (radius > 0.1 && !only) {\n for (const p of o.parts) {\n if (p === loc.p || isLost(p)) continue\n const dd = distToPart(o, p, point)\n if (dd >= radius) continue\n const { c, q } = partXf(o, p)\n const sp = surfacePoint(p.spec.shape, toLocal(c, q, point))\n res.damage += melee(o, p, hit.type, E * (1 - dd / radius) ** 2, toWorld(c, q, sp.point), rotateVec(q, sp.normal), loc.dir, radius, src)\n }\n }\n }\n } else if (hit.type === 'explosive') {\n const call = hit.blast || hit.confinement !== undefined ? { ...hit.blast, ...(hit.confinement !== undefined ? { confinement: hit.confinement } : {}) } : undefined\n const cfg = blastCfg(call)\n if (!cfg.shelter && !cfg.frag && cfg.conf === null) res = blastObject(o, point, E, hit.radius ?? 2, src)\n else {\n res = blastWorld(point, E, hit.radius ?? 2, src, call, o)[0] ?? res\n res.events = cur.slice(start)\n }\n } else {\n res = heatObject(o, point, hit.temperature ?? 800, hit.radius ?? 0.25, hit.duration ?? 1, src)\n }\n res.events = cur.slice(start)\n return res\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // Fire, heat, melting, leaks\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n const checkIgnite = (o: ObjRT, p: PartRT, src?: string) => {\n const th = p.mat.thermal\n if (isLost(p) || p.st.burning || th.ignitionC === undefined || p.st.fuel <= 0 || p.st.temperature < th.ignitionC) return\n p.st.burning = true\n p.st.temperature = Math.max(p.st.temperature, th.flameC ?? 800)\n o.active = true\n markDamaged(p)\n emit({ ...base(o, src), type: 'ignite', part: p.spec.id, point: partXf(o, p).c })\n }\n\n const syncMass = (p: PartRT) => {\n p.st.mass = Math.max(0, p.mass0 * (1 - p.st.melt) - (p.fuel0 - p.st.fuel))\n }\n\n const burnStep = (o: ObjRT, p: PartRT, dt: number) => {\n const th = p.mat.thermal\n const use = Math.min((th.burnRate ?? 0.01) * p.area * dt, p.st.fuel)\n p.st.fuel -= use\n syncMass(p)\n if (p.structural) o.dirty = true\n p.st.temperature = th.flameC ?? 800\n markDamaged(p)\n if (p.fuel0 > 0) {\n p.st.char = clamp(1 - p.st.fuel / p.fuel0, 0, 1)\n p.st.hp = Math.min(p.st.hp, Math.max(1, p.st.maxHp * (p.st.fuel / p.fuel0)))\n }\n if (p.st.fuel <= 1e-9) {\n p.st.fuel = 0\n p.st.burning = false\n p.st.char = 1\n const c = partXf(o, p).c\n if ((th.fuelFraction ?? 0) >= 0.8) {\n p.st.status = 'ashes'\n p.st.hp = 0\n p.st.mass = p.mass0 * (1 - (th.fuelFraction ?? 0))\n emit({ ...base(o), type: 'burnout', part: p.spec.id, point: c })\n debris(o, p, 'ash', c, [0, 1, 0], clamp(Math.round(Math.cbrt(partVolume(p.spec.shape)) * 30), 3, 20), 1)\n partLost(o, p)\n } else {\n emit({ ...base(o), type: 'burnout', part: p.spec.id, point: c })\n }\n }\n }\n\n const meltStep = (o: ObjRT, p: PartRT, dt: number) => {\n const th = p.mat.thermal\n if (th.meltC === undefined || p.st.temperature <= th.meltC) return\n const rate = (th.meltRate ?? 0.05) * ((p.st.temperature - th.meltC) / 100)\n p.st.melt = Math.min(1, p.st.melt + rate * dt)\n syncMass(p)\n if (p.structural) o.dirty = true\n markDamaged(p)\n p.rt.dripT += dt\n if (p.rt.dripT >= 0.25) {\n p.rt.dripT -= 0.25\n const b = partWorldAabb(o, p)\n const pt: Vec3 = [b.min[0] + (b.max[0] - b.min[0]) * (0.2 + 0.6 * rnd()), b.min[1], b.min[2] + (b.max[2] - b.min[2]) * (0.2 + 0.6 * rnd())]\n emit({ ...base(o), type: 'drip', part: p.spec.id, point: pt, material: p.mat.id })\n }\n if (p.st.melt - p.rt.meltEmitted >= 0.05 || p.st.melt >= 1) {\n p.rt.meltEmitted = p.st.melt\n emit({ ...base(o), type: 'melt', part: p.spec.id, melt: p.st.melt })\n }\n if (p.st.melt >= 1) {\n p.st.status = 'melted'\n p.st.hp = 0\n p.st.mass = 0\n p.st.burning = false\n p.rt.jet = false\n partLost(o, p)\n }\n }\n\n const stepObject = (o: ObjRT, dt: number, sources: Array<{ o: ObjRT; p: PartRT; flame: number }>) => {\n const parts = o.parts\n const T0 = o.tmp\n T0.length = parts.length\n for (let i = 0; i < parts.length; i++) T0[i] = parts[i].st.temperature\n let hot = false\n for (let i = 0; i < parts.length; i++) {\n const p = parts[i]\n if (isLost(p)) continue\n const th = p.mat.thermal\n const hc = th.heatCapacity ?? 1\n const s = p.st\n if (p.rt.jet) {\n s.temperature = Math.max(s.temperature, 900)\n } else if (s.burning) {\n burnStep(o, p, dt)\n if (isLost(p)) continue\n }\n if (!s.burning && !p.rt.jet) {\n // conduction from hotter neighbours through closed joints, then cooling\n let dT = 0\n let maxN = s.temperature\n for (const j of o.byPart.get(p.spec.id)!) {\n if (j.st.open) continue\n const k = j.ia === i ? j.ib : j.ia\n if (isLost(parts[k]) || T0[k] <= T0[i]) continue\n const c = (th.conductivity + parts[k].mat.thermal.conductivity) / 2\n dT += (T0[k] - T0[i]) * (1 - Math.exp((-1.2 * c * dt) / hc))\n if (T0[k] > maxN) maxN = T0[k]\n }\n if (dT > 0) s.temperature = Math.min(s.temperature + dT, maxN)\n s.temperature += (ambient - s.temperature) * (1 - Math.exp(-dt / (20 * hc)))\n if (Math.abs(s.temperature - ambient) < 0.05) s.temperature = ambient\n }\n meltStep(o, p, dt)\n if (isLost(p)) continue\n checkIgnite(o, p)\n const ex = p.spec.explodes\n if (ex && chainDelayOf(p.spec, 'fire') !== undefined) {\n if (s.temperature >= (ex.atC ?? FIRE_PRIME_C)) prime(o, p, 'fire')\n } else if (ex && ex.atC !== undefined && s.temperature >= ex.atC) {\n failPart(o, p, null, null, 0, 40)\n continue\n }\n // leaks\n const cont = p.spec.contains\n if (cont && (s.liters ?? 0) > 0) {\n let rate = 0\n for (const h of s.holes) if (h.through) rate += holeRate(h, !!cont.pressurized)\n if (rate > 0) {\n s.liters = Math.max(0, (s.liters ?? 0) - rate * dt)\n hot = true\n if (FLAMMABLE_FLUIDS.includes(cont.fluid) && (s.temperature >= 350 || p.rt.lit) && !p.rt.jet) {\n p.rt.lit = false\n if (ex && chainDelayOf(p.spec, 'fire') !== undefined) {\n prime(o, p, 'fire')\n continue\n }\n if (ex) {\n failPart(o, p, null, null, 0, 40)\n continue\n }\n p.rt.jet = true\n s.burning = true\n emit({ ...base(o), type: 'ignite', part: p.spec.id, point: partXf(o, p).c })\n }\n }\n }\n if ((s.liters ?? 0) <= 0) p.rt.lit = false\n if (p.rt.jet && (s.liters ?? 0) <= 0) {\n p.rt.jet = false\n s.burning = false\n emit({ ...base(o), type: 'extinguish', part: p.spec.id })\n }\n // thermal shock\n const sc = th.thermalShockC\n if (sc !== undefined) {\n p.rt.shockT = Math.max(0, p.rt.shockT - dt)\n const rate = Math.abs(s.temperature - p.rt.prevTemp) / dt\n p.rt.prevTemp = s.temperature\n if (rate > sc && p.rt.shockT <= 0) {\n p.rt.shockT = 1\n const { c, q } = partXf(o, p)\n const lp: Vec3 = [(rnd() - 0.5) * p.dims[0], (rnd() - 0.5) * p.dims[1], (rnd() - 0.5) * p.dims[2]]\n const sp = surfacePoint(p.spec.shape, lp)\n addCrack(o, p, toWorld(c, q, sp.point), rotateVec(q, sp.normal), 0.1 + (rate / sc) * 0.1)\n applyDamage(o, p, p.st.maxHp * 0.25, 'heat', null, null, 5, 3)\n if (isLost(p)) continue\n }\n }\n if (s.burning || p.rt.jet) sources.push({ o, p, flame: p.rt.jet ? 900 : th.flameC ?? 800 })\n if (s.burning || p.rt.jet || s.temperature > ambient + 0.5) hot = true\n }\n if (o.hasStructure) {\n if (o.dirty) {\n o.dirty = false\n solveStructure(o)\n }\n for (const p of parts) {\n if (!p.structural || isLost(p)) continue\n const stress = p.st.stress ?? 0\n p.rt.stressT = Math.max(0, (p.rt.stressT ?? 0) - dt)\n if (stress > 1) {\n if (p.rt.stressT <= 0) {\n p.rt.stressT = 0.5\n emit({ ...base(o), type: 'stress', part: p.spec.id, stress, load: p.st.load ?? 0 })\n }\n applyDamage(o, p, overloadRate(stress) * p.st.maxHp * dt, 'blunt', null, null, 5, 3)\n } else if (stress > 0.8 && p.mat.ductility < 0.3 && p.rt.stressT <= 0 && p.st.cracks.length < 6) {\n p.rt.stressT = 0.5\n const { c, q } = partXf(o, p)\n const sp = surfacePoint(p.spec.shape, [(rnd() - 0.5) * p.dims[0], (rnd() - 0.5) * p.dims[1], (rnd() - 0.5) * p.dims[2]])\n addCrack(o, p, toWorld(c, q, sp.point), rotateVec(q, sp.normal), 0.1 + (stress - 0.8) * 0.5)\n }\n }\n if (o.maxStress > 0.8) hot = true\n }\n o.active = hot\n }\n\n /** A leak of flammable fluid within `ignition.fireNear.radius` of a burning part (or of a jet) lights at `chancePerSecond`. */\n const igniteLeaksNearFire = (sources: Array<{ o: ObjRT; p: PartRT; flame: number }>, dt: number) => {\n const { radius, chancePerSecond } = ignitionRules.fireNear\n if (chancePerSecond <= 0) return\n const chance = 1 - Math.exp(-chancePerSecond * dt)\n for (const src of sources) {\n if (!src.p.st.burning && !src.p.rt.jet) continue\n const sc = partXf(src.o, src.p).c\n for (const o of objects.values()) {\n for (const q of o.parts) {\n if (q === src.p || isLost(q) || q.rt.lit || q.rt.jet || !leaksFlammable(q)) continue\n if (vec.distance(partXf(o, q).c, sc) - q.bound - src.p.bound > radius) continue\n if (rnd() < chance) {\n q.rt.lit = true\n o.active = true\n }\n }\n }\n }\n }\n\n const spread = (sources: Array<{ o: ObjRT; p: PartRT; flame: number }>, dt: number) => {\n for (const src of sources) {\n if (!src.p.st.burning && !src.p.rt.jet) continue\n const sc = toWorld(src.o.st.position, src.o.st.rotation, src.p.pos)\n const A = partWorldAabb(src.o, src.p)\n for (const o of objects.values()) {\n if (o === src.o) continue\n if (vec.distance(toWorld(o.st.position, o.st.rotation, o.bc), sc) > o.br + src.p.bound + fireSpread) continue\n for (const q of o.parts) {\n if (isLost(q) || q.st.burning) continue\n const B = partWorldAabb(o, q)\n const gap = Math.hypot(\n Math.max(0, A.min[0] - B.max[0], B.min[0] - A.max[0]),\n Math.max(0, A.min[1] - B.max[1], B.min[1] - A.max[1]),\n Math.max(0, A.min[2] - B.max[2], B.min[2] - A.max[2]),\n )\n if (gap >= fireSpread || src.flame <= q.st.temperature) continue\n const f = 1 - gap / fireSpread\n q.st.temperature += (src.flame - q.st.temperature) * (1 - Math.exp((-0.6 * f * dt) / (q.mat.thermal.heatCapacity ?? 1)))\n o.active = true\n }\n }\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------------------------------\n // World API\n // -------------------------------------------------------------------------------------------------------------------------------------------\n\n /** The primed part that goes off first: earliest due time, then the older object, then the part listed first. */\n const nextPrimed = (until: number): { o: ObjRT; p: PartRT } | null => {\n let best: { o: ObjRT; p: PartRT } | null = null\n for (const [p, o] of primed) {\n if (objects.get(o.id) !== o || isLost(p)) {\n primed.delete(p)\n continue\n }\n const due = p.rt.chainDue as number\n if (due > until) continue\n if (!best) best = { o, p }\n else {\n const bestDue = best.p.rt.chainDue as number\n if (due < bestDue || (due === bestDue && (o.order < best.o.order || (o.order === best.o.order && (o.idx.get(p.spec.id) ?? 0) < (best.o.idx.get(best.p.spec.id) ?? 0))))) best = { o, p }\n }\n }\n return best\n }\n\n /**\n * Explodes the primed parts whose delay ran out by `until`, one at a time in order of time; each blast is resolved before the next part goes off,\n * so a part it primes counts its delay from that moment, not from the end of the frame.\n */\n const detonatePrimed = (until: number) => {\n const end = time\n for (let next = nextPrimed(until); next; next = nextPrimed(until)) {\n primed.delete(next.p)\n time = Math.max(0, Math.min(end, next.p.rt.chainDue as number))\n next.p.rt.chainDue = undefined\n failPart(next.o, next.p, null, null, 0, 40)\n drainBlasts()\n }\n time = end\n }\n\n /** Lands the damage of the glass the blast front has reached by `time`, the nearest first. */\n const releaseFront = () => {\n if (frontQueue.length === 0) return\n frontQueue.sort((a, b) => a.due - b.due)\n while (frontQueue.length > 0 && frontQueue[0]!.due <= time) {\n const hit = frontQueue.shift()!\n if (objects.get(hit.o.id) !== hit.o) continue\n applyDamage(hit.o, hit.p, hit.amount, 'explosive', hit.point, null, hit.fragEnergy, 40, hit.src)\n }\n }\n\n /** Collapse events are produced after the whole operation: make sure the result of the operation carries them. */\n const withCollapses = (r: { value: HitResult[]; events: DestructionEvent[] }): HitResult[] => {\n const last = r.value[r.value.length - 1]\n if (!last) return r.value\n for (const e of r.events) if (e.type === 'collapse' && !r.value.some((h) => h.events.includes(e))) last.events.push(e)\n return r.value\n }\n\n /** An explosive hit on an impl: a blast of its own when blast options are on, else the plain hit. */\n const blastImpl = (im: ImplRT, h: Hit): HitResult => {\n const call = h.blast || h.confinement !== undefined ? { ...h.blast, ...(h.confinement !== undefined ? { confinement: h.confinement } : {}) } : undefined\n const cfg = blastCfg(call)\n if (!cfg.shelter && !cfg.frag && cfg.conf === null) return implHit(im, h)\n const world = h.space === 'local' ? toWorld(im.position, im.rotation, h.point) : h.point\n const r = blastWorld(world, h.energy ?? 0, h.radius ?? 2, h.source, call, im)\n return r.find((x) => x.object === im.impl.id) ?? implHit(im, h)\n }\n\n const whole = (fn: () => HitResult): HitResult => {\n const r = run(fn)\n r.value.events = r.events\n return r.value\n }\n\n const world: DestructionWorld = {\n materials,\n get time() {\n return time\n },\n add(spec, opts: AddOptions = {}) {\n const id = opts.id ?? nextId()\n if (taken(id)) throw new Error(`object \"${id}\" already exists`)\n objects.set(id, build(resolveSpec(spec), id, opts.position ?? [0, 0, 0], opts.rotation ?? [0, 0, 0, 1]))\n return id\n },\n register(impl, opts: AddOptions = {}) {\n const id = opts.id ?? impl.id\n if (taken(id)) throw new Error(`object \"${id}\" already exists`)\n impls.set(id, { impl, position: opts.position ?? [0, 0, 0], rotation: opts.rotation ?? [0, 0, 0, 1], poses: new Map() })\n return id\n },\n setPartPose(objectId, partId, position, rotation) {\n const q = quatFromEuler(...(rotation ?? [0, 0, 0]))\n const im = impls.get(objectId)\n if (im) {\n im.impl.setPartPose?.(partId, position, rotation)\n im.poses.set(partId, { pos: [position[0], position[1], position[2]], q })\n return\n }\n const o = getObj(objectId)\n const p = getPart(o, partId)\n p.pos = [position[0], position[1], position[2]]\n p.q = q\n updateBound(o)\n },\n remove(id) {\n objects.delete(id)\n impls.delete(id)\n },\n has: (id) => taken(id),\n ids: () => [...objects.keys(), ...impls.keys()],\n setTransform(id, position, rotation) {\n const im = impls.get(id)\n if (im) {\n im.position = [position[0], position[1], position[2]]\n im.rotation = [rotation[0], rotation[1], rotation[2], rotation[3]]\n return\n }\n const o = getObj(id)\n o.base = { pos: [position[0], position[1], position[2]], rot: [rotation[0], rotation[1], rotation[2], rotation[3]] }\n applySoilPose(o)\n },\n splitGroup(id, group, newId) {\n if (impls.has(id)) throw new Error(`object \"${id}\" is a registered DestructibleImpl and cannot be split; its module owns its pieces`)\n const o = getObj(id)\n if (o.st.groups.length < 2) return id\n const names = o.st.groups[group]\n if (!names) throw new Error(`object \"${id}\" has no group ${group}`)\n const moved = new Set(names)\n const nid = newId ?? nextId()\n if (objects.has(nid)) throw new Error(`object \"${nid}\" already exists`)\n // an open joint between the two objects stays with the original\n const carryFor = (keep: (pid: string) => boolean, keepOpen: (a: string, b: string) => boolean = () => false): Carry => ({\n parts: new Map(o.parts.filter((p) => keep(p.spec.id)).map((p) => [p.spec.id, { st: p.st, rt: p.rt }])),\n joints: new Map([\n ...o.joints.filter((j) => (keep(j.spec.a) && keep(j.spec.b)) || (j.st.open && keepOpen(j.spec.a, j.spec.b))).map((j): [string, { st: JointState; step: number }] => [j.spec.id, { st: j.st, step: j.step }]),\n ...o.st.joints.filter((st) => st.open && !o.jointMap.has(st.id) && keepOpen(st.a, st.b)).map((st): [string, { st: JointState; step: number }] => [st.id, { st, step: 0 }]),\n ]),\n collapsed: [...o.collapsed].filter(keep),\n })\n const sub = (keep: (pid: string) => boolean): DestructibleSpec => {\n const s: DestructibleSpec = { parts: o.spec.parts.filter((p) => keep(p.id)), joints: (o.spec.joints ?? []).filter((j) => keep(j.a) && keep(j.b)) }\n if (o.spec.name !== undefined) s.name = o.spec.name\n if (o.spec.tags) s.tags = [...o.spec.tags]\n if (o.spec.soil !== undefined) s.soil = o.spec.soil\n return clone(s)\n }\n const inNew = (pid: string) => moved.has(pid)\n const inOld = (pid: string) => !moved.has(pid)\n const pos = o.st.position, rot = o.st.rotation\n const fresh = build(sub(inNew), nid, pos, rot, carryFor(inNew, (a, b) => inNew(a) && inNew(b)))\n const restCarry = carryFor(inOld, (a, b) => !(inNew(a) && inNew(b)))\n if (o.st.soil) restCarry.soil = o.st.soil\n if (o.soil?.sets.size) restCarry.soilSets = Object.fromEntries(o.soil.sets)\n const rest = build(sub(inOld), id, o.soil ? o.base.pos : pos, o.soil ? o.base.rot : rot, restCarry)\n objects.set(id, rest)\n objects.set(nid, fresh)\n return nid\n },\n hit(objectId, h) {\n const im = impls.get(objectId)\n if (im) return whole(() => (h.type === 'explosive' ? blastImpl(im, h) : implHit(im, h)))\n const o = getObj(objectId)\n return whole(() => doHit(o, h))\n },\n hitPart(objectId, partId, h) {\n const im = impls.get(objectId)\n if (im) return whole(() => implHit(im, h))\n const o = getObj(objectId)\n const p = getPart(o, partId)\n return whole(() => doHit(o, h, p))\n },\n explode(point, energy, radius, source, blast) {\n return withCollapses(run(() => blastWorld(point, energy, radius, source, blast)))\n },\n raycast(origin, direction, maxDistance = Infinity) {\n const r = raycastInternal(origin, direction, maxDistance)\n return r ? { object: r.object, part: r.part, point: r.point, normal: r.normal, distance: r.distance } : null\n },\n shoot(origin, direction, energy, caliber, source, round) {\n const extras: BallisticExtras = typeof round === 'number' ? { piercing: round } : round ?? {}\n return withCollapses(run(() => {\n const results: HitResult[] = []\n const d = vec.normalize(direction)\n const ignore = new Set<string>()\n let org = origin\n let E = energy\n for (let i = 0; i < 4 && E > 0; i++) {\n const rh = raycastInternal(org, d, Infinity, ignore)\n if (!rh) break\n const im = impls.get(rh.object)\n if (im) {\n const r = implHit(im, { type: 'ballistic', point: rh.point, direction: d, energy: E, caliber, ...extras, ...(source !== undefined ? { source } : {}) })\n r.part = rh.part\n r.point = rh.point\n r.exitEnergy = r.penetrated ? E * 0.5 : 0\n results.push(r)\n ignore.add(`${im.impl.id}\\0${rh.part}`)\n if (!r.penetrated) break\n org = vec.madd(rh.point, d, Math.min(rh.pathLen, 0.05) + 0.001)\n E = r.exitEnergy\n continue\n }\n const o = getObj(rh.object)\n const p = getPart(o, rh.part)\n const start = cur.length\n const out = ballistic(o, p, rh.point, rh.normal, d, E, caliber, rh.pathLen, source, extras)\n results.push({ object: o.id, part: p.spec.id, point: rh.point, damage: out.damage, penetrated: out.penetrated, exitEnergy: out.exitEnergy, events: cur.slice(start) })\n ignore.add(`${o.id}\\0${p.spec.id}`)\n if (!out.penetrated || !out.exitPoint) break\n org = vec.madd(out.exitPoint, d, 0.001)\n E = out.exitEnergy\n }\n return results\n }))\n },\n disassemble(objectId, jointId, tool: ToolKind, dt) {\n const im = impls.get(objectId)\n if (im) return im.impl.disassemble ? im.impl.disassemble(jointId, tool, dt) : -1\n const o = getObj(objectId)\n const j = o.jointMap.get(jointId)\n if (!j || !j.spec.tools.includes(tool)) return -1\n if (j.st.open) return 1\n return run(() => {\n j.st.progress = Math.min(1, j.st.progress + (j.spec.seconds > 0 ? dt / j.spec.seconds : 1))\n if (j.st.progress >= 1 - 1e-9) j.st.progress = 1\n const step = Math.floor(j.st.progress * 10 + 1e-9)\n if (step > j.step || j.st.progress >= 1) {\n j.step = step\n emit({ ...base(o), type: 'disassemble_progress', joint: j.spec.id, tool, progress: j.st.progress })\n }\n if (j.st.progress >= 1) {\n j.st.open = true\n j.st.openedBy = 'tool'\n solveStructure(o)\n recomputeGroups(o)\n detachEvents(o, [j], 'tool')\n collapseCheck(o)\n }\n return j.st.progress\n }).value\n },\n workableJoints(objectId, tool) {\n const im = impls.get(objectId)\n if (im) {\n const spec = im.impl.describe()\n return im.impl.state().joints.filter((js) => {\n const j = (spec.joints ?? []).find((x) => (x.id ?? `${x.a}~${x.b}`) === js.id)\n return !js.open && !!j && (j.tools ?? JOINT_DEFAULTS[j.kind].tools).includes(tool)\n })\n }\n return getObj(objectId).joints.filter((j) => !j.st.open && j.spec.tools.includes(tool)).map((j) => j.st)\n },\n nearestJoint(objectId, point, maxDistance = 0.3, tool) {\n const im = impls.get(objectId)\n // Candidates: closed joints with their world position and whether `tool` can undo them.\n const cands: { st: JointState; d: number; ok: boolean }[] = []\n if (im) {\n const spec = im.impl.describe()\n for (const js of im.impl.state().joints) {\n if (js.open) continue\n const pos = implJointPos(im, js.a, js.b)\n const j = (spec.joints ?? []).find((x) => (x.id ?? `${x.a}~${x.b}`) === js.id)\n cands.push({ st: js, d: pos ? vec.distance(pos, point) : Infinity, ok: !!j && (j.tools ?? JOINT_DEFAULTS[j.kind].tools).includes(tool as ToolKind) })\n }\n } else {\n const o = getObj(objectId)\n for (const j of o.joints) {\n if (j.st.open) continue\n cands.push({ st: j.st, d: vec.distance(jointWorld(o, j), point), ok: tool ? j.spec.tools.includes(tool) : true })\n }\n }\n const pick = (only: boolean): JointState | null => {\n let best: JointState | null = null\n let bd = maxDistance\n for (const c of cands) {\n if (only && !c.ok) continue\n if (c.d <= bd) {\n bd = c.d\n best = c.st\n }\n }\n return best\n }\n return (tool ? pick(true) : null) ?? pick(false)\n },\n extinguish(objectId, partId, coolC = 200) {\n const im = impls.get(objectId)\n if (im) {\n run(() => im.impl.extinguish?.(partId))\n return\n }\n const o = getObj(objectId)\n run(() => {\n for (const p of partId ? [getPart(o, partId)] : o.parts) {\n if (isLost(p)) continue\n if (p.st.burning) {\n p.st.burning = false\n p.rt.jet = false\n emit({ ...base(o), type: 'extinguish', part: p.spec.id })\n }\n p.st.temperature = Math.max(ambient, p.st.temperature - coolC)\n }\n o.active = true\n })\n },\n setWind(next) {\n windOpts = { ...windOpts, ...Object.fromEntries(Object.entries(next).filter(([, v]) => v !== undefined)) }\n windCfg = resolveWind(windOpts)\n for (const o of objects.values()) {\n if (!o.hasStructure || o.spec.wind === false) continue\n o.wind ??= newWind(o)\n o.dirty = true\n o.active = true\n }\n },\n vent(objectId, partId, opening = {}) {\n if (impls.has(objectId)) return false\n const o = getObj(objectId)\n const p = getPart(o, partId)\n const c = p.spec.contains\n if (!c || isLost(p) || (p.st.liters ?? 0) <= 0) return false\n if (p.st.holes.some((h) => h.vent)) return true\n return run(() => {\n const wp = opening.point ?? partXf(o, p).c\n const wn = vec.normalize(opening.normal ?? [0, 1, 0])\n const hole: Hole = { point: objLocal(o, wp), normal: objLocalDir(o, wn), diameter: opening.diameter ?? VENT_DIAMETER, through: true, vent: true }\n p.st.holes.push(hole)\n if (p.st.holes.length > maxHoles) p.st.holes.shift()\n o.active = true\n emit({\n ...base(o), type: 'leak', part: partId, fluid: c.fluid, point: wp,\n direction: c.outflow ? vec.normalize(rotateVec(o.st.rotation, rotateVec(p.q, c.outflow))) : wn, rate: holeRate(hole, !!c.pressurized), pressurized: !!c.pressurized,\n })\n return true\n }).value\n },\n seal(objectId, partId) {\n if (impls.has(objectId)) return 0\n const o = getObj(objectId)\n const p = getPart(o, partId)\n const before = p.st.holes.length\n p.st.holes = p.st.holes.filter((h) => !h.vent)\n o.active = true\n return before - p.st.holes.length\n },\n setLiters(objectId, partId, liters) {\n if (impls.has(objectId)) return\n const p = getPart(getObj(objectId), partId)\n if (!p.spec.contains) return\n p.st.liters = clamp(liters, 0, p.spec.contains.liters)\n getObj(objectId).active = true\n },\n update(dt) {\n if (!(dt > 0)) return []\n return run(() => {\n time += dt\n const sources: Array<{ o: ObjRT; p: PartRT; flame: number }> = []\n for (const o of [...objects.values()]) if (o.active) stepObject(o, dt, sources)\n for (const o of [...objects.values()]) if (o.soil && objects.get(o.id) === o) stepSoil(o, dt)\n for (const o of [...objects.values()]) if (o.wind && objects.get(o.id) === o) stepWind(o, dt)\n if (sources.length) {\n spread(sources, dt)\n igniteLeaksNearFire(sources, dt)\n }\n detonatePrimed(time)\n releaseFront()\n for (const im of [...impls.values()]) {\n if (!im.impl.update) continue\n for (const e of im.impl.update(dt) ?? []) emit(e.time === undefined ? { ...e, time } : e)\n }\n }).events\n },\n state: (id) => objects.get(id)?.st ?? impls.get(id)?.impl.state() ?? null,\n snapshot: (id) => {\n const st = objects.get(id)?.st ?? impls.get(id)?.impl.state()\n return st ? clone(st) : null\n },\n part: (id, partId) => objects.get(id)?.byId.get(partId)?.st ?? impls.get(id)?.impl.state().parts.find((p) => p.id === partId) ?? null,\n reset(id) {\n const im = impls.get(id)\n if (im) {\n im.impl.reset?.()\n return\n }\n const o = getObj(id)\n objects.set(id, build(o.spec, id, o.base.pos, o.base.rot))\n },\n on(type: DestructionEventType | '*', fn) {\n let set = listeners.get(type)\n if (!set) listeners.set(type, (set = new Set()))\n set.add(fn)\n return () => {\n set!.delete(fn)\n }\n },\n serialize(): DestructionSnapshot {\n return {\n version: 1,\n time,\n rng: rng.state(),\n counter,\n objects: [...objects.values()].map((o) => {\n const runtime: ObjectRuntime = { parts: {}, joints: {}, collapsed: [...o.collapsed], ...(o.soil?.sets.size ? { soil: Object.fromEntries(o.soil.sets) } : {}), ...(o.wind ? { wind: [o.wind.dyn.x, o.wind.dyn.v, o.wind.dyn.y, o.wind.dyn.w, o.wind.dyn.peak] as [number, number, number, number, number] } : {}) }\n for (const p of o.parts) runtime.parts[p.spec.id] = clone(p.rt)\n for (const j of o.joints) runtime.joints[j.spec.id] = j.step\n return { id: o.id, spec: clone(o.spec), state: clone(o.st), runtime }\n }),\n ...(impls.size\n ? { impls: [...impls.values()].map((im) => ({ id: im.impl.id, position: [...im.position] as Vec3, rotation: [...im.rotation] as Quat, data: im.impl.serialize?.() })) }\n : {}),\n }\n },\n load(snap) {\n if (snap.version !== 1) throw new Error(`unsupported snapshot version ${String(snap.version)}`)\n objects.clear()\n time = snap.time\n rng.set(snap.rng)\n counter = snap.counter ?? 0\n for (const e of snap.objects) {\n const state = clone(e.state)\n const carry: Carry = {\n parts: new Map(\n state.parts.map((st) => [st.id, { st, rt: e.runtime?.parts[st.id] ? clone(e.runtime.parts[st.id]) : { ...freshRuntime(), prevTemp: st.temperature } }]),\n ),\n joints: new Map(state.joints.map((st) => [st.id, { st, step: e.runtime?.joints[st.id] ?? 0 }])),\n collapsed: e.runtime?.collapsed,\n ...(e.runtime?.wind ? { wind: e.runtime.wind } : {}),\n }\n let pos = state.position, rot = state.rotation\n if (state.soil) {\n // the saved pose has the settlement on top of the host's: take it off to get the host's back\n carry.soil = state.soil\n if (e.runtime?.soil) carry.soilSets = e.runtime.soil\n rot = quat.normalize(quat.mul(state.rotation, quat.conjugate(state.soil.offset.rotation)))\n pos = vec.sub(state.position, rotateVec(rot, state.soil.offset.position))\n }\n objects.set(e.id, build(clone(e.spec), e.id, pos, rot, carry))\n }\n for (const e of snap.impls ?? []) {\n const im = impls.get(e.id)\n if (!im) continue\n im.position = [e.position[0], e.position[1], e.position[2]]\n im.rotation = [e.rotation[0], e.rotation[1], e.rotation[2], e.rotation[3]]\n if (e.data !== undefined) im.impl.load?.(e.data)\n }\n },\n }\n return world\n}\n","[\n {\n \"id\": \"brick_wall_plastered\",\n \"name\": \"Plastered brick wall\",\n \"core\": { \"material\": \"brick\", \"thickness\": 0.09 },\n \"layers\": [{ \"material\": \"plaster\", \"thickness\": 0.02, \"faces\": \"both\" }],\n \"units\": { \"size\": [0.23, 0.075, 0.11], \"bond\": \"running\", \"mortar\": \"plaster\" },\n \"breach\": { \"area\": 0.25 }\n },\n {\n \"id\": \"concrete_block_wall\",\n \"name\": \"Concrete block wall\",\n \"core\": { \"material\": \"concrete\", \"thickness\": 0.14 },\n \"fill\": 0.55,\n \"units\": { \"size\": [0.39, 0.19, 0.14], \"bond\": \"running\", \"mortar\": \"plaster\" },\n \"breach\": { \"area\": 0.25 }\n },\n {\n \"id\": \"reinforced_concrete\",\n \"name\": \"Reinforced concrete wall\",\n \"core\": { \"material\": \"concrete\", \"thickness\": 0.2 },\n \"reinforcement\": { \"material\": \"steel\", \"spacing\": 0.18, \"diameter\": 0.008, \"residualCapacity\": 0.15 },\n \"units\": { \"size\": [0.6, 0.42, 0.2], \"bond\": \"stack\", \"mortar\": \"concrete\" },\n \"breach\": { \"area\": 0.25 }\n },\n {\n \"id\": \"drywall\",\n \"name\": \"Drywall partition on steel studs\",\n \"core\": { \"material\": \"plaster\", \"thickness\": 0.0125 },\n \"layers\": [{ \"material\": \"plaster\", \"thickness\": 0.0125, \"faces\": \"+\" }],\n \"depth\": 0.095,\n \"breach\": { \"area\": 0.25 }\n },\n {\n \"id\": \"wood_frame_wall\",\n \"name\": \"Wood frame wall\",\n \"core\": { \"material\": \"plywood\", \"thickness\": 0.012 },\n \"layers\": [{ \"material\": \"plaster\", \"thickness\": 0.0125, \"faces\": \"-\" }],\n \"depth\": 0.1135,\n \"breach\": { \"area\": 0.25 }\n },\n {\n \"id\": \"log_wall\",\n \"name\": \"Log wall\",\n \"core\": { \"material\": \"wood_soft\", \"thickness\": 0.2 },\n \"fill\": 0.785,\n \"breach\": { \"area\": 0.25 }\n },\n {\n \"id\": \"sheet_metal_shack\",\n \"name\": \"Corrugated sheet metal wall\",\n \"core\": { \"material\": \"steel\", \"thickness\": 0.0006 },\n \"depth\": 0.02,\n \"breach\": { \"area\": 0.25 }\n },\n {\n \"id\": \"glass_pane\",\n \"name\": \"Glass pane\",\n \"core\": { \"material\": \"glass\", \"thickness\": 0.006 },\n \"breach\": { \"area\": 0.1 }\n }\n]\n","import assembliesJson from './data/assemblies.json'\nimport { MATERIALS } from './materials'\nimport type { MaterialDef, MaterialId, PartBreach, PartSpec, PartUnits, Reinforcement, SurfaceLayer, Vec3 } from './types'\n\n/**\n * 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\n * `src/data/assemblies.json`); `assemblyPart` turns one into a `PartSpec`. Extend or override with `registerAssembly`.\n */\nexport interface AssemblyDef {\n id: string\n name: string\n /** `thickness` is the core's, in metres: what a bullet has to get through besides the coats. */\n core: { material: MaterialId; thickness: number }\n /** Coats, outermost first. */\n layers?: readonly SurfaceLayer[]\n /** Physical depth of the wall when it is not core plus coats (a drywall partition is mostly air between the boards). */\n depth?: number\n /** Solid fraction of the core (hollow blocks, round logs): scales its mass and the thickness a bullet crosses. Default 1. */\n fill?: number\n units?: PartUnits\n reinforcement?: Reinforcement\n breach?: PartBreach\n}\n\nexport interface AssemblyPartOptions {\n id: string\n /** Along the part's x axis. */\n width: number\n /** Along the part's y axis. */\n height: number\n position: Vec3\n rotation?: Vec3\n structure?: PartSpec['structure']\n /** Other `PartSpec` fields (tags, anchored, hp...). */\n extra?: Partial<PartSpec>\n /** Materials to read densities from (default the built-in `MATERIALS`). */\n materials?: ReadonlyMap<MaterialId, MaterialDef>\n}\n\n/** Built-in assemblies; `registerAssembly` adds to this list. */\nexport const ASSEMBLIES: AssemblyDef[] = assembliesJson as unknown as AssemblyDef[]\n\nexport const registerAssembly = (def: AssemblyDef): void => {\n const at = ASSEMBLIES.findIndex((a) => a.id === def.id)\n if (at >= 0) ASSEMBLIES[at] = def\n else ASSEMBLIES.push(def)\n}\n\nexport const getAssembly = (id: string): AssemblyDef | undefined => ASSEMBLIES.find((a) => a.id === id)\n\nconst faceCount = (layer: SurfaceLayer): number => (layer.faces === 'both' ? 2 : 1)\n\n/** Physical depth of the wall in metres. */\nexport const assemblyDepth = (def: AssemblyDef): number => def.depth ?? def.core.thickness + (def.layers ?? []).reduce((sum, l) => sum + l.thickness * faceCount(l), 0)\n\n/**\n * 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`)\n * plus the coats; `thickness` is the core's, so each coat adds its own `penetration x thickness` to what a bullet must cross.\n */\nexport const assemblyPart = (assemblyId: string, options: AssemblyPartOptions): PartSpec => {\n const def = getAssembly(assemblyId)\n if (!def) throw new Error(`unknown assembly \"${assemblyId}\"`)\n const densityOf = (id: MaterialId): number => {\n const m = options.materials?.get(id) ?? MATERIALS.find((x) => x.id === id)\n if (!m) throw new Error(`unknown material \"${id}\" in assembly \"${assemblyId}\"`)\n return m.density\n }\n const fill = def.fill ?? 1\n const area = options.width * options.height\n const coreMass = area * def.core.thickness * fill * densityOf(def.core.material)\n const layerMass = (def.layers ?? []).reduce((sum, l) => sum + area * l.thickness * faceCount(l) * densityOf(l.material), 0)\n return {\n id: options.id,\n material: def.core.material,\n shape: { kind: 'box', size: [options.width, options.height, assemblyDepth(def)] },\n position: options.position,\n ...(options.rotation ? { rotation: options.rotation } : {}),\n mass: coreMass + layerMass,\n thickness: def.core.thickness * fill,\n ...(def.layers ? { layers: def.layers.map((l) => ({ ...l })) } : {}),\n ...(def.units ? { units: { ...def.units, size: [...def.units.size] as Vec3 } } : {}),\n ...(def.reinforcement ? { reinforcement: { ...def.reinforcement } } : {}),\n ...(def.breach ? { breach: { ...def.breach } } : {}),\n ...(options.structure ? { structure: options.structure } : {}),\n ...options.extra,\n }\n}\n","import type { DestructibleSpec, JointSpec, MaterialId, PartSpec, PileSpec, Reinforcement, SoilProfile } from './types'\n\nexport interface FrameOptions {\n /** Total length along x between the outer column centres, metres (default 8). */\n spanX?: number\n /** Total length along z (default 8). */\n spanZ?: number\n /** Columns along x (at least 2, default 3). */\n columnsX?: number\n /** Columns along z (at least 2, default 3). */\n columnsZ?: number\n /** Height of one floor from slab top to the underside of the next slab, metres (default 3). */\n height?: number\n /** Number of floors (default 1). */\n floors?: number\n /** Brick walls on every perimeter bay of every floor; the first bay of the ground floor on the -z side gets a door opening (default false). */\n walls?: boolean\n /** A thin roof slab resting on the top beams (default true); without it the top floor is open. */\n roof?: boolean\n columnSize?: number\n beamHeight?: number\n slabThickness?: number\n wallThickness?: number\n doorWidth?: number\n doorHeight?: number\n /** Material of foundations, columns, beams, slabs and roof (default `concrete`). */\n material?: MaterialId\n wallMaterial?: MaterialId\n /** Override the load capacity of every column, kg (see `PartState.load`). */\n columnCapacity?: number\n /**\n * Tension steel ratio of the beams and slabs (`structure.rebar.ratio`; default beams 1%, slabs and roof 0.5%, inside the ranges of NBR 6118);\n * `false` makes them plain concrete (they snap when they bend past cracking).\n */\n rebar?: { beam?: number; slab?: number } | false\n /** Side of the square pad under each column in metres (default 2.2 x `columnSize`), 0.3 m thick. */\n footing?: number\n /** One raft under the whole frame instead of a pad per column (`raft`, the footprint plus `footing` / 2 each side, 0.4 m thick). */\n raft?: boolean\n /** Piles under each pad (or under the raft): the pad becomes a pile cap. */\n piles?: PileSpec\n /**\n * Columns run from storey to storey: each one rests on the column below (through the slab, as a cast-in-place column does) instead of on the slab,\n * so the slab carries only its own floor. Default false (the column of each storey stands on the slab below, as before).\n */\n continuousColumns?: boolean\n /** Rebar cage of the columns (`PartSpec.reinforcement`; default none). A caged column carries `0.85 fck Ac + As fy` and its `rebar` joints are monolithic. */\n columnCage?: Reinforcement\n /** Thickness of the roof slab (default 0.75 x `slabThickness`; a flat roof that carries a screed and equipment is as thick as a floor). */\n roofThickness?: number\n /** The ground the frame stands on (`DestructibleSpec.soil`). */\n soil?: string | SoilProfile\n}\n\n/**\n * A parametric test structure: a grid of columns on foundations, beams between the column tops, one slab per floor (the last one a roof), and\n * optional brick walls with a door. Joints are explicit and directional: columns rest on foundations (or on the slab below) with `rebar`, beams on\n * columns, slabs on beams, the roof rests on the top beams, walls hang on their columns with `mortar`. Part ids: `foundation_i_j`, `column_f_i_j`,\n * `beam_x_f_i_j`, `beam_z_f_i_j`, `slab_f`, `roof`, `wall_*`, `door`. Ground is y = 0 (the top of the foundations).\n */\nexport const buildFrame = (o: FrameOptions = {}): DestructibleSpec => {\n const spanX = o.spanX ?? 8, spanZ = o.spanZ ?? 8\n const nx = Math.max(2, o.columnsX ?? 3), nz = Math.max(2, o.columnsZ ?? 3)\n const H = o.height ?? 3, floors = Math.max(1, o.floors ?? 1)\n const cs = o.columnSize ?? 0.3, bh = o.beamHeight ?? 0.3, bw = 0.2, T = o.slabThickness ?? 0.2, wt = o.wallThickness ?? 0.2\n const dw = o.doorWidth ?? 1, dh = o.doorHeight ?? 2.1\n const mat = o.material ?? 'concrete', wmat = o.wallMaterial ?? 'brick'\n const roof = o.roof ?? true\n const rebarOf = (kind: 'beam' | 'slab') => (o.rebar === false ? {} : { rebar: { ratio: o.rebar?.[kind] ?? (kind === 'beam' ? 0.01 : 0.005) } })\n const xs = Array.from({ length: nx }, (_, i) => -spanX / 2 + (i * spanX) / (nx - 1))\n const zs = Array.from({ length: nz }, (_, j) => -spanZ / 2 + (j * spanZ) / (nz - 1))\n const parts: PartSpec[] = []\n const joints: JointSpec[] = []\n const on = (a: string, b: string, kind: JointSpec['kind']) => joints.push({ id: `${a}~${b}`, a, b, kind, bears: 'a_on_b' })\n\n const pad = o.footing ?? cs * 2.2\n const pile = o.piles ? { pile: { ...o.piles } } : {}\n if (o.raft) {\n parts.push({\n id: 'raft', material: mat, shape: { kind: 'box', size: [spanX + pad, 0.4, spanZ + pad] }, position: [0, -0.2, 0],\n structure: { role: 'foundation', ...pile }, anchored: true,\n })\n } else {\n for (let i = 0; i < nx; i++) {\n for (let j = 0; j < nz; j++) {\n parts.push({\n id: `foundation_${i}_${j}`, material: mat, shape: { kind: 'box', size: [pad, 0.3, pad] }, position: [xs[i], -0.15, zs[j]],\n structure: { role: 'foundation', ...pile }, anchored: true,\n })\n }\n }\n }\n for (let f = 0; f < floors; f++) {\n const yb = f * (H + T)\n const top = yb + H\n const last = f === floors - 1\n const slabId = last && roof ? 'roof' : `slab_${f}`\n for (let i = 0; i < nx; i++) {\n for (let j = 0; j < nz; j++) {\n const id = `column_${f}_${i}_${j}`\n parts.push({\n id, material: mat, shape: { kind: 'box', size: [cs, H, cs] }, position: [xs[i], yb + H / 2, zs[j]],\n structure: o.columnCapacity === undefined ? { role: 'column' } : { role: 'column', capacity: o.columnCapacity },\n ...(o.columnCage ? { reinforcement: { ...o.columnCage } } : {}),\n })\n on(id, f === 0 ? (o.raft ? 'raft' : `foundation_${i}_${j}`) : o.continuousColumns ? `column_${f - 1}_${i}_${j}` : `slab_${f - 1}`, 'rebar')\n }\n }\n const beams: string[] = []\n const beam = (id: string, size: [number, number, number], pos: [number, number, number], c1: string, c2: string) => {\n parts.push({ id, material: mat, shape: { kind: 'box', size }, position: pos, structure: { role: 'beam', ...rebarOf('beam') } })\n on(id, c1, 'rebar')\n on(id, c2, 'rebar')\n beams.push(id)\n }\n for (let j = 0; j < nz; j++) {\n for (let i = 0; i < nx - 1; i++) {\n beam(`beam_x_${f}_${i}_${j}`, [xs[i + 1] - xs[i] - cs, bh, bw], [(xs[i] + xs[i + 1]) / 2, top - bh / 2, zs[j]], `column_${f}_${i}_${j}`, `column_${f}_${i + 1}_${j}`)\n }\n }\n for (let i = 0; i < nx; i++) {\n for (let j = 0; j < nz - 1; j++) {\n beam(`beam_z_${f}_${i}_${j}`, [bw, bh, zs[j + 1] - zs[j] - cs], [xs[i], top - bh / 2, (zs[j] + zs[j + 1]) / 2], `column_${f}_${i}_${j}`, `column_${f}_${i}_${j + 1}`)\n }\n }\n const thick = last && roof ? o.roofThickness ?? T * 0.75 : T\n parts.push({\n id: slabId, material: mat, shape: { kind: 'box', size: [spanX + cs + 0.2, thick, spanZ + cs + 0.2] }, position: [0, top + thick / 2, 0],\n structure: { role: last && roof ? 'roof' : 'slab', ...rebarOf('slab') },\n })\n for (const b of beams) on(slabId, b, last && roof ? 'resting' : 'rebar')\n\n if (o.walls) {\n const wh = H - bh\n const wy = yb + wh / 2\n const wall = (id: string, size: [number, number, number], pos: [number, number, number], supports: string[]) => {\n parts.push({ id, material: wmat, shape: { kind: 'box', size }, position: pos, structure: { role: 'wall' } })\n for (const s of supports) on(id, s, 'mortar')\n }\n for (const j of [0, nz - 1]) {\n for (let i = 0; i < nx - 1; i++) {\n const c1 = `column_${f}_${i}_${j}`, c2 = `column_${f}_${i + 1}_${j}`\n const avail = xs[i + 1] - xs[i] - cs\n if (f === 0 && j === 0 && i === 0 && avail > dw + 0.4) {\n const side = (avail - dw) / 2\n const lx = xs[i] + cs / 2 + side / 2, rx = xs[i + 1] - cs / 2 - side / 2\n wall(`wall_door_left`, [side, wh, wt], [lx, wy, zs[j]], [c1])\n wall(`wall_door_right`, [side, wh, wt], [rx, wy, zs[j]], [c2])\n const lh = wh - dh\n wall(`wall_door_lintel`, [dw, lh, wt], [xs[i] + cs / 2 + side + dw / 2, yb + dh + lh / 2, zs[j]], ['wall_door_left', 'wall_door_right'])\n parts.push({ id: 'door', material: 'wood_hard', shape: { kind: 'box', size: [dw - 0.04, dh, 0.05] }, position: [xs[i] + cs / 2 + side + dw / 2, yb + dh / 2, zs[j]], tags: ['door'] })\n joints.push({ id: 'door~wall_door_left', a: 'door', b: 'wall_door_left', kind: 'hinge', bears: false })\n } else wall(`wall_x_${f}_${i}_${j}`, [avail, wh, wt], [(xs[i] + xs[i + 1]) / 2, wy, zs[j]], [c1, c2])\n }\n }\n for (const i of [0, nx - 1]) {\n for (let j = 0; j < nz - 1; j++) {\n wall(`wall_z_${f}_${i}_${j}`, [wt, wh, zs[j + 1] - zs[j] - cs], [xs[i], wy, (zs[j] + zs[j + 1]) / 2], [`column_${f}_${i}_${j}`, `column_${f}_${i}_${j + 1}`])\n }\n }\n }\n }\n return { name: 'frame', parts, joints, tags: ['structure'], ...(o.soil !== undefined ? { soil: o.soil } : {}) }\n}\n","import { createDestruction } from './world'\nimport { GRAVITY, bendGeometry, isFlexural, isReinforced, resolveFlexure, sectionMoments, sectionWidth, steelMoment, tensionSteel } from './flexure'\nimport { MATERIALS } from './materials'\nimport { shapeDims } from './math'\nimport { resolveWind, tensionCapacity } from './wind'\nimport type { DestructibleSpec, MaterialDef, SizeStructureOptions, StructureRole } from './types'\n\n/** Highest tension steel ratio a designer puts in a beam or slab (NBR 6118 17.3.5.2.4: 4% of the section). */\nconst MAX_REBAR_RATIO = 0.04\n\n/** The spec as the sizing worlds see it: the ground does not change the loads, so the soil is left out. */\nconst onRock = (spec: DestructibleSpec): DestructibleSpec => {\n if (spec.soil === undefined) return spec\n const { soil: _soil, ...rest } = spec\n return rest\n}\n\n/** The spec without one part (and its joints; inferred joints are inferred again without it). */\nconst without = (spec: DestructibleSpec, id: string): DestructibleSpec => {\n const reduced: DestructibleSpec = { ...spec, parts: spec.parts.filter((p) => p.id !== id), joints: (spec.joints ?? []).filter((j) => j.a !== id && j.b !== id) }\n if (!spec.joints) delete reduced.joints\n return reduced\n}\n\n/**\n * Sizes the tension steel of the reinforced beams, slabs, roofs and stairs of a structure (a `reinforcement` cage or a `structure.rebar`), the way\n * `sizeStructure` sizes the capacities: each one gets the `structure.rebar.ratio` that keeps its bending at rest (`PartState.flexure`) at `safety`\n * (`safetyByRole`) and, with `redundancy`, at most `redundancy` after the loss of any part of `redundancyRoles`. Steel is only added (up to 4% of the\n * section) and plain concrete stays plain: a beam the spec makes without steel is a beam without steel. Returns a copy.\n */\nexport const sizeRebar = (spec: DestructibleSpec, options: SizeStructureOptions = {}): DestructibleSpec => {\n const flexure = resolveFlexure(options.flexure)\n const materials = new Map<string, MaterialDef>(MATERIALS.map((m) => [m.id, m]))\n for (const m of options.materials ?? []) materials.set(m.id, m)\n const out = structuredClone(spec)\n const targets = out.parts.filter((p) => {\n const m = materials.get(p.material)\n return p.shape.kind === 'box' && !!m && isReinforced(p) && isFlexural(p, m, flexure)\n })\n if (targets.length === 0) return out\n const safety = options.safety ?? 0.65\n const safetyOf = (role: StructureRole): number => options.safetyByRole?.[role] ?? safety\n const bending = (s: DestructibleSpec): Map<string, number> => {\n const w = createDestruction({ ...(options.materials ? { materials: options.materials } : {}), structure: { flexure: options.flexure } })\n const id = w.add(onRock(s))\n return new Map(w.state(id)!.parts.map((p) => [p.id, p.flexure ?? 0]))\n }\n const base = bending(out)\n const factor = new Map(targets.map((p) => [p.id, (base.get(p.id) ?? 0) / safetyOf(p.structure!.role)]))\n if (options.redundancy !== undefined) {\n const roles: readonly StructureRole[] = options.redundancyRoles ?? ['column']\n for (const lost of out.parts) {\n if (!lost.structure || !roles.includes(lost.structure.role)) continue\n const l = bending(without(out, lost.id))\n for (const p of targets) if (p.id !== lost.id) factor.set(p.id, Math.max(factor.get(p.id)!, (l.get(p.id) ?? 0) / options.redundancy))\n }\n }\n for (const p of targets) {\n const f = factor.get(p.id)!\n const g = bendGeometry(p)\n if (f <= 1 || g.gravity < 0) continue\n const section = { b: sectionWidth(g, g.gravity), h: g.dims[g.gravity] }\n const steel = tensionSteel(p, g.dims, section, flexure)\n const m = materials.get(p.material)!\n const need = f * sectionMoments(m, section, steel, flexure).ultimate\n const momentOf = (area: number) => steelMoment(area, steel.yieldMPa, steel.d, section.b, m.strength!.compressiveMPa, flexure)\n // the smallest steel area whose moment reaches the need (the moment grows with the area), found by bisection, at most the 4% cap\n const cap = MAX_REBAR_RATIO * section.b * steel.d\n if (steel.area >= cap) continue\n let lo = steel.area, hi = cap\n if (momentOf(hi) > need) {\n for (let k = 0; k < 60; k++) {\n const mid = (lo + hi) / 2\n if (momentOf(mid) < need) lo = mid\n else hi = mid\n }\n }\n const ratio = hi / (section.b * steel.d)\n p.structure = { ...p.structure!, rebar: { ...p.structure!.rebar, ratio } }\n }\n return out\n}\n\n/**\n * 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\n * same load solver `createDestruction` uses, and each structural part (`structure.role` other than `none`) gets `structure.capacity = load / safety`,\n * so its at-rest stress is exactly `safety` (`safetyByRole` overrides it per role). With `redundancy` set, every part whose role is in\n * `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\n * `redundancy`. Parts without `structure`, with role `none`, or with no support path to an\n * anchored part are left as they are. The spec is not modified; a copy is returned.\n */\nexport const sizeStructure = (spec: DestructibleSpec, options: SizeStructureOptions = {}): DestructibleSpec => {\n const safety = options.safety ?? 0.65\n const redundancy = options.redundancy\n const redundancyRoles: readonly StructureRole[] = options.redundancyRoles ?? ['column']\n const safetyOf = (role: StructureRole): number => options.safetyByRole?.[role] ?? safety\n const loads = (s: DestructibleSpec, wind?: SizeStructureOptions['wind']): Map<string, { load: number; stress: number; wind: number }> => {\n const w = createDestruction({ ...(options.materials ? { materials: options.materials } : {}), ...(wind ? { wind } : {}) })\n const id = w.add(onRock(s))\n return new Map(w.state(id)!.parts.map((p) => [p.id, { load: p.load ?? 0, stress: p.stress ?? 0, wind: p.wind ?? 0 }]))\n }\n const out = structuredClone(spec)\n const base = loads(out, options.wind)\n const gamma = options.wind ? resolveWind(options.wind).loadFactor : 0\n const need = new Map<string, number>()\n for (const p of out.parts) {\n if (!p.structure || p.structure.role === 'none') continue\n const b = base.get(p.id)\n if (!b || b.stress <= 0) continue\n // the wind adds its factored axial force to the dead load (compression side); on the tension side the bars are sized below\n need.set(p.id, (b.load + (b.wind > 0 ? (gamma * b.wind) / GRAVITY : 0)) / safetyOf(p.structure.role))\n }\n if (redundancy !== undefined) {\n for (const col of out.parts) {\n if (!col.structure || !redundancyRoles.includes(col.structure.role)) continue\n const reduced: DestructibleSpec = {\n ...out,\n parts: out.parts.filter((p) => p.id !== col.id),\n joints: (out.joints ?? []).filter((j) => j.a !== col.id && j.b !== col.id),\n }\n // joints are inferred when the spec has none; removing a part then removes its joints with it\n if (!out.joints) delete reduced.joints\n const l = loads(reduced)\n for (const [id, n] of need) {\n const r = l.get(id)\n if (r && r.stress > 0) need.set(id, Math.max(n, r.load / redundancy))\n }\n }\n }\n for (const p of out.parts) {\n const n = need.get(p.id)\n if (n !== undefined) p.structure = { ...p.structure!, capacity: n }\n }\n if (options.wind) {\n // a wall or column that the wind pulls past its dead load needs bars for the pull: thicker bars, to the 40 mm of NBR 7480\n const yieldMPa = resolveFlexure(options.flexure).rebarYieldMPa\n for (const p of out.parts) {\n const b = base.get(p.id)\n if (!b || b.wind >= 0 || !p.reinforcement || p.shape.kind !== 'box') continue\n const pull = (-(b.load + (gamma * b.wind) / GRAVITY) * GRAVITY)\n if (pull <= 0) continue\n const dims = shapeDims(p.shape)\n const have = tensionCapacity(dims, { reinforcement: p.reinforcement, yieldMPa })\n const want = pull / safetyOf(p.structure?.role ?? 'wall')\n if (have > 0 && want > have) p.reinforcement = { ...p.reinforcement, diameter: Math.min(0.04, p.reinforcement.diameter * Math.sqrt(want / have)) }\n }\n }\n return sizeRebar(out, options)\n}\n","import type { DamageType, DestructionEventType, FractureStyle, JointKind, PartStatus, StructureRole, ToolKind } from './types'\n\n/** Locales shipped with the package. Unknown locales fall back to `en`. */\nexport type DestructionLocale = 'en' | 'pt-BR'\n\nexport interface DestructionStrings {\n /** Display name per material id (see `MATERIALS`). Unknown ids are not listed. */\n materialNames: Record<string, string>\n partStatus: Record<PartStatus, string>\n jointKinds: Record<JointKind, string>\n toolKinds: Record<ToolKind, string>\n damageTypes: Record<DamageType, string>\n /** Short label per event type, for logs and kill-feed style text. */\n eventLabels: Record<DestructionEventType, string>\n fractureStyles: Record<FractureStyle, string>\n structureRoles: Record<StructureRole, string>\n}\n\nexport const locales: Record<DestructionLocale, DestructionStrings> = {\n en: {\n materialNames: {\n steel: 'steel', cast_iron: 'cast iron', aluminium: 'aluminium', copper: 'copper', wood_soft: 'softwood', wood_hard: 'hardwood', plywood: 'plywood',\n mdf: 'MDF', glass: 'glass', tempered_glass: 'tempered glass', ceramic: 'ceramic', concrete: 'concrete', brick: 'brick', plaster: 'plaster',\n stone: 'stone', plastic: 'plastic', rubber: 'rubber', fabric: 'fabric', foam: 'foam', leather: 'leather', paper: 'paper', foliage: 'foliage',\n green_wood: 'green wood', cactus: 'cactus', flesh_fruit: 'fruit', wax: 'wax', soil: 'soil',\n },\n partStatus: { intact: 'intact', damaged: 'damaged', collapsed: 'collapsed', broken: 'broken', melted: 'melted', ashes: 'ashes' },\n jointKinds: {\n screw: 'screw', bolt: 'nut and bolt', nail: 'nail', weld: 'weld', glue: 'glue', hinge: 'hinge', clip: 'clip', tie: 'tie', mortar: 'mortar',\n fused: 'fused', stem: 'stem', rebar: 'rebar', resting: 'resting',\n },\n toolKinds: {\n hand: 'hand', screwdriver: 'screwdriver', wrench: 'wrench', pry_bar: 'pry bar', saw: 'saw', cutting_torch: 'cutting torch', knife: 'knife', hammer: 'hammer',\n },\n damageTypes: { ballistic: 'ballistic', blunt: 'blunt', slash: 'slash', explosive: 'explosive', fire: 'fire', heat: 'heat' },\n eventLabels: {\n damage: 'damage', dent: 'dent', hole: 'hole', crack: 'crack', ricochet: 'ricochet', debris: 'debris', fracture: 'broke', detach: 'came loose',\n disassemble_progress: 'taking apart', ignite: 'caught fire', extinguish: 'put out', burnout: 'burned to ash', melt: 'melting', drip: 'dripping',\n leak: 'leak', explode: 'exploded', primed: 'about to explode', stress: 'overload', collapse: 'collapsed', settle: 'ground gave way', sway: 'sway', spall: 'plaster came off', stage: 'damage stage', expose: 'rebar bare', body: 'body', blast: 'blast', fragment_hit: 'fragment hit', destroyed: 'destroyed',\n },\n fractureStyles: { shatter: 'shatter', crumble: 'crumble', splinter: 'splinter', tear: 'tear', snap: 'snap', none: 'none' },\n structureRoles: { foundation: 'foundation', column: 'column', beam: 'beam', slab: 'slab', wall: 'wall', partition: 'partition', roof: 'roof', stair: 'stairs', none: 'none' },\n },\n 'pt-BR': {\n materialNames: {\n steel: 'aço', cast_iron: 'ferro fundido', aluminium: 'alumínio', copper: 'cobre', wood_soft: 'madeira macia', wood_hard: 'madeira de lei',\n plywood: 'compensado', mdf: 'MDF', glass: 'vidro', tempered_glass: 'vidro temperado', ceramic: 'cerâmica', concrete: 'concreto', brick: 'tijolo',\n plaster: 'gesso', stone: 'pedra', plastic: 'plástico', rubber: 'borracha', fabric: 'tecido', foam: 'espuma', leather: 'couro', paper: 'papel',\n foliage: 'folhagem', green_wood: 'madeira verde', cactus: 'cacto', flesh_fruit: 'fruta', wax: 'cera', soil: 'terra',\n },\n partStatus: { intact: 'intacto', damaged: 'danificado', collapsed: 'desabado', broken: 'quebrado', melted: 'derretido', ashes: 'cinzas' },\n jointKinds: {\n screw: 'parafuso', bolt: 'porca e parafuso', nail: 'prego', weld: 'solda', glue: 'cola', hinge: 'dobradiça', clip: 'encaixe', tie: 'amarração',\n mortar: 'argamassa', fused: 'fundido', stem: 'caule', rebar: 'vergalhão', resting: 'apoiado',\n },\n toolKinds: {\n hand: 'mão', screwdriver: 'chave de fenda', wrench: 'chave inglesa', pry_bar: 'pé de cabra', saw: 'serra', cutting_torch: 'maçarico', knife: 'faca', hammer: 'martelo',\n },\n damageTypes: { ballistic: 'tiro', blunt: 'impacto', slash: 'corte', explosive: 'explosão', fire: 'fogo', heat: 'calor' },\n eventLabels: {\n damage: 'dano', dent: 'amassado', hole: 'furo', crack: 'trinca', ricochet: 'ricochete', debris: 'estilhaços', fracture: 'quebrou', detach: 'soltou',\n disassemble_progress: 'desmontando', ignite: 'pegou fogo', extinguish: 'apagou', burnout: 'virou cinza', melt: 'derretendo', drip: 'pingando',\n leak: 'vazamento', explode: 'explodiu', primed: 'prestes a explodir', stress: 'sobrecarga', collapse: 'desabou', settle: 'recalque do solo', sway: 'balanço', spall: 'reboco soltou', stage: 'estágio de dano', expose: 'vergalhão à mostra', body: 'corpo', blast: 'explosão', fragment_hit: 'estilhaço atingiu', destroyed: 'destruído',\n },\n fractureStyles: { shatter: 'estilhaçar', crumble: 'esfarelar', splinter: 'lascar', tear: 'rasgar', snap: 'partir', none: 'nenhuma' },\n structureRoles: { foundation: 'fundação', column: 'pilar', beam: 'viga', slab: 'laje', wall: 'parede', partition: 'divisória', roof: 'telhado', stair: 'escada', none: 'nenhum' },\n },\n}\n\nexport const resolveStrings = (locale: string | undefined): DestructionStrings => locales[(locale as DestructionLocale) ?? 'en'] ?? locales.en\n","import { checkDestructible as check } from '@adatechnology/game-contracts'\nimport type { CheckOptions as ContractCheckOptions, DestructibleImpl } from '@adatechnology/game-contracts'\nimport { MATERIALS } from './materials'\n\n// The contract itself lives in @adatechnology/game-contracts (a module depends only on that); re-exported here so that no import breaks.\nexport { IMPACT_CONTRACT, checkHit } from '@adatechnology/game-contracts'\nexport type { DestructibleImpl, ImpactContract } from '@adatechnology/game-contracts'\n\nexport interface CheckOptions {\n /** Ids of custom materials the impl uses besides the built-in `MATERIALS`. */\n materials?: string[]\n}\n\n/**\n * `checkDestructible` of `@adatechnology/game-contracts`, with the built-in `MATERIALS` (plus `options.materials`) as the known material ids.\n * It hits the impl (and calls `reset()` afterwards when there is one).\n */\nexport const checkDestructible = (impl: DestructibleImpl, options: CheckOptions = {}): { ok: boolean; problems: string[] } => {\n const contractOptions: ContractCheckOptions = { materials: [...MATERIALS.map((m) => m.id), ...(options.materials ?? [])] }\n return check(impl, contractOptions)\n}\n","import { GROUND } from './types'\nimport type { StructurePart, Support } from './types'\n\n/**\n * Load each part carries at rest, by the rules of the Visor de casas 3D (which the destruction world shares): load only goes down to supports closer to\n * the ground, shared equally, and a partition wall carries nothing, so what rests only on partitions has no load. `without` leaves one part out (as if it\n * had failed). Parts that are not structural (the tank) are not loaded.\n */\nexport function loadsAtRest(parts: readonly StructurePart[], supports: readonly Support[], without?: string): Map<string, number> {\n const byId = new Map(parts.filter((part) => part.id !== without).map((part) => [part.id, part]))\n const resting = new Map<string, string[]>()\n const carrying = new Map<string, string[]>()\n const push = (map: Map<string, string[]>, key: string, value: string): void => {\n const list = map.get(key)\n if (list) list.push(value)\n else map.set(key, [value])\n }\n for (const support of supports) {\n if (support.bears === false) continue\n if (!byId.has(support.part) || (support.on !== GROUND && !byId.has(support.on))) continue\n push(resting, support.part, support.on)\n push(carrying, support.on, support.part)\n }\n const partition = (id: string): boolean => byId.get(id)?.role === 'partition'\n const structural = (id: string): boolean => byId.has(id) && byId.get(id)!.role !== 'none'\n const distance = new Map<string, number>([[GROUND, 0]])\n const queue = [GROUND]\n for (let head = 0; head < queue.length; head++) {\n const current = queue[head]!\n if (current !== GROUND && partition(current)) continue\n for (const above of carrying.get(current) ?? []) {\n if (distance.has(above) || !structural(above)) continue\n distance.set(above, distance.get(current)! + 1)\n queue.push(above)\n }\n }\n const incoming = new Map<string, number>()\n const loads = new Map<string, number>()\n for (let head = queue.length - 1; head >= 1; head--) {\n const id = queue[head]!\n const total = (byId.get(id)!.mass || 1) + (incoming.get(id) ?? 0)\n loads.set(id, total)\n const below = (resting.get(id) ?? []).filter((other) => distance.has(other) && distance.get(other)! < distance.get(id)! && !(other !== GROUND && partition(other)))\n for (const other of below) incoming.set(other, (incoming.get(other) ?? 0) + total / below.length)\n }\n return loads\n}\n\nexport interface SizingOptions {\n /** Fraction of its capacity a pillar or bearing wall uses at rest. */\n safety: number\n /** The most of its capacity a pillar or bearing wall uses after any other pillar or bearing wall is lost. */\n redundancy: number\n /** Fraction of capacity every other structural part uses at rest. */\n safetyOthers: number\n}\n\nconst isBearing = (part: StructurePart): boolean => part.role === 'column' || part.role === 'wall'\n\n/**\n * Capacity of each loaded part, as a designer would size it: a pillar or bearing wall uses `safety` of it at rest and stays under `redundancy` when\n * any other pillar or bearing wall is lost (the house holds one loss and falls with two); every other part uses `safetyOthers`.\n * `sizeStructure` of game-destruction gives the same numbers except for beams of a framed building (it holds them under `redundancy` too).\n */\nexport function sizeCapacities(parts: readonly StructurePart[], supports: readonly Support[], options: SizingOptions): Map<string, number> {\n const loads = loadsAtRest(parts, supports)\n const worst = new Map<string, number>()\n for (const part of parts.filter(isBearing)) {\n for (const [id, load] of loadsAtRest(parts, supports, part.id)) {\n const before = loads.get(id)\n if (before && load / before > (worst.get(id) ?? 1)) worst.set(id, load / before)\n }\n }\n const capacities = new Map<string, number>()\n for (const part of parts) {\n const load = loads.get(part.id)\n if (load === undefined || part.role === 'none') continue\n const factor = isBearing(part) ? Math.max(1 / options.safety, (worst.get(part.id) ?? 1) / options.redundancy) : 1 / options.safetyOthers\n capacities.set(part.id, Math.max(1, load * factor))\n }\n return capacities\n}\n","import type { Rect } from '../types'\nimport type { SlabPanelOptions } from './options'\n\n/** A line of wall seen from above: it runs along `dir` at the coordinate `at` of the other axis, over `[from, to]`. */\nexport interface WallLine {\n dir: 'u' | 'v'\n at: number\n from: number\n to: number\n}\n\n/** A beam line: it runs along `dir` at `at` over `[from, to]`. A cut along `v` at `u = at` separates the panels on its two sides. */\nexport type Cut = WallLine\n\nexport interface Layout {\n leaves: Rect[]\n cuts: Cut[]\n}\n\nconst EPS = 1e-6\n\n/** The wall boxes `[u0, v0, u1, v1]` as lines. */\nexport function linesOf(boxes: readonly Rect[]): WallLine[] {\n return boxes.map(([u0, v0, u1, v1]) => (u1 - u0 >= v1 - v0 ? { dir: 'u', at: (v0 + v1) / 2, from: u0, to: u1 } : { dir: 'v', at: (u0 + u1) / 2, from: v0, to: v1 }))\n}\n\n/** Share of `[from, to]` the walls of the line `(dir, at)` cover, with gaps up to `doorGap` counted as wall. */\nfunction coverage(lines: readonly WallLine[], dir: 'u' | 'v', at: number, from: number, to: number, options: SlabPanelOptions): number {\n const spans = lines\n .filter((line) => line.dir === dir && Math.abs(line.at - at) <= options.lineTolerance)\n .map((line): [number, number] => [Math.max(from, line.from), Math.min(to, line.to)])\n .filter(([a, b]) => b > a)\n .sort((x, y) => x[0] - y[0])\n let covered = 0\n let end = from\n let start = NaN\n for (const [a, b] of spans) {\n if (Number.isNaN(start)) {\n start = a\n end = b\n } else if (a - end <= options.doorGap) end = Math.max(end, b)\n else {\n covered += end - start\n start = a\n end = b\n }\n }\n if (!Number.isNaN(start)) covered += end - start\n return to > from ? covered / (to - from) : 0\n}\n\n/** Positions of the lines of one direction, walls closer than the tolerance merged. */\nfunction positions(lines: readonly WallLine[], dir: 'u' | 'v', tolerance: number): number[] {\n const sorted = lines.filter((line) => line.dir === dir).map((line) => line.at).sort((a, b) => a - b)\n const out: number[] = []\n let group: number[] = []\n for (const at of sorted) {\n if (group.length && at - group[group.length - 1]! > tolerance) {\n out.push(group.reduce((s, x) => s + x, 0) / group.length)\n group = []\n }\n group.push(at)\n }\n if (group.length) out.push(group.reduce((s, x) => s + x, 0) / group.length)\n return out\n}\n\ninterface Candidate {\n dir: 'u' | 'v'\n at: number\n coverage: number\n /** 0 at the middle of the rectangle, 1 at its edge. */\n skew: number\n}\n\nconst round = (x: number): number => Math.round(x * 100) / 100\n\n/** The cut of `rect`: along `dir` at `at`, or none when it is already a panel. */\nfunction choose(rect: Rect, lines: readonly WallLine[], options: SlabPanelOptions): { dir: 'u' | 'v'; at: number } | null {\n const [u0, v0, u1, v1] = rect\n const width = u1 - u0\n const depth = v1 - v0\n const tooWide = width > options.maxSpan + EPS\n const tooDeep = depth > options.maxSpan + EPS\n const candidates: Candidate[] = []\n for (const at of positions(lines, 'v', options.lineTolerance)) {\n if (at < u0 + options.minPanel - EPS || at > u1 - options.minPanel + EPS) continue\n candidates.push({ dir: 'v', at, coverage: coverage(lines, 'v', at, v0, v1, options), skew: Math.abs(at - (u0 + u1) / 2) / (width / 2) })\n }\n for (const at of positions(lines, 'u', options.lineTolerance)) {\n if (at < v0 + options.minPanel - EPS || at > v1 - options.minPanel + EPS) continue\n candidates.push({ dir: 'u', at, coverage: coverage(lines, 'u', at, u0, u1, options), skew: Math.abs(at - (v0 + v1) / 2) / (depth / 2) })\n }\n const boundary = candidates.filter((c) => c.coverage >= options.lineCoverage)\n if (tooWide || tooDeep) {\n // cut across the longer side when both are too long\n const across: 'u' | 'v' = tooWide && (!tooDeep || width >= depth) ? 'v' : 'u'\n const pool = boundary.filter((c) => c.dir === across)\n if (pool.length) {\n const best = pool.reduce((a, b) => (b.skew - 0.25 * b.coverage < a.skew - 0.25 * a.coverage ? b : a))\n return { dir: best.dir, at: round(best.at) }\n }\n const length = across === 'v' ? width : depth\n const origin = across === 'v' ? u0 : v0\n return { dir: across, at: round(origin + length / Math.ceil(length / options.maxSpan - EPS)) }\n }\n if (!boundary.length) return null\n const best = boundary.reduce((a, b) => (b.coverage - 0.25 * b.skew > a.coverage - 0.25 * a.skew ? b : a))\n return { dir: best.dir, at: round(best.at) }\n}\n\n/** Cuts `rect` along the walls and into pieces no wider than `maxSpan` (the panels of a slab) and returns them with the cut lines. */\nexport function layoutPanels(rect: Rect, lines: readonly WallLine[], options: SlabPanelOptions): Layout {\n const leaves: Rect[] = []\n const cuts: Cut[] = []\n const walk = (r: Rect, depth: number): void => {\n const cut = depth < 16 ? choose(r, lines, options) : null\n if (!cut) {\n leaves.push(r)\n return\n }\n if (cut.dir === 'v') {\n cuts.push({ dir: 'v', at: cut.at, from: r[1], to: r[3] })\n walk([r[0], r[1], cut.at, r[3]], depth + 1)\n walk([cut.at, r[1], r[2], r[3]], depth + 1)\n } else {\n cuts.push({ dir: 'u', at: cut.at, from: r[0], to: r[2] })\n walk([r[0], r[1], r[2], cut.at], depth + 1)\n walk([r[0], cut.at, r[2], r[3]], depth + 1)\n }\n }\n walk(rect, 0)\n return { leaves, cuts }\n}\n\nexport const areaOf = (rect: Rect): number => Math.max(0, rect[2] - rect[0]) * Math.max(0, rect[3] - rect[1])\n\nexport function overlapArea(a: Rect, b: Rect): number {\n return Math.max(0, Math.min(a[2], b[2]) - Math.max(a[0], b[0])) * Math.max(0, Math.min(a[3], b[3]) - Math.max(a[1], b[1]))\n}\n\n/** Share of `rect` inside the union of `footprint` (the rectangles of the footprint do not overlap). */\nexport function shareInside(rect: Rect, footprint: readonly Rect[]): number {\n const area = areaOf(rect)\n return area > 0 ? Math.min(1, footprint.reduce((sum, other) => sum + overlapArea(rect, other), 0) / area) : 0\n}\n\n/** The stretches of the cut that border at least one of `panels` (the beams under the kept panels), as `[from, to]` runs. */\nexport function runsOf(cut: Cut, panels: readonly Rect[], tolerance = 0.02): [number, number][] {\n const spans: [number, number][] = []\n for (const [u0, v0, u1, v1] of panels) {\n if (cut.dir === 'v') {\n if (Math.abs(u0 - cut.at) < tolerance || Math.abs(u1 - cut.at) < tolerance) spans.push([Math.max(v0, cut.from), Math.min(v1, cut.to)])\n } else if (Math.abs(v0 - cut.at) < tolerance || Math.abs(v1 - cut.at) < tolerance) spans.push([Math.max(u0, cut.from), Math.min(u1, cut.to)])\n }\n const sorted = spans.filter(([a, b]) => b - a > tolerance).sort((x, y) => x[0] - y[0])\n const runs: [number, number][] = []\n for (const [a, b] of sorted) {\n const last = runs[runs.length - 1]\n if (last && a <= last[1] + tolerance) last[1] = Math.max(last[1], b)\n else runs.push([a, b])\n }\n return runs\n}\n","import type { JointKind } from '@adatechnology/game-contracts'\n\nimport { densityOf } from '../density'\nimport { round2, touches } from '../geometry'\nimport { CONSTRUCTION_SYSTEMS } from '../registry'\nimport { GROUND } from '../types'\nimport type { Rect, Structure, StructurePart, Support } from '../types'\nimport type { PartsAndSupports } from '../wall-detail/apply'\nimport { layoutPanels, linesOf, runsOf, shareInside } from './layout'\nimport type { Cut } from './layout'\nimport type { SlabPanelOptions } from './options'\n\nconst SLAB_ID = /^slab_(\\d+|top.*|ceiling|base)$/\nconst PLAN_TOLERANCE = 0.05\n/** Metres a support may end below the bottom of what it holds and still hold it (walls end under the bond beam, pillars at the slab). */\nconst BELOW = 0.35\nconst UP = 0.15\n/** A beam needs a support this close to each of its ends. */\nconst END_REACH = 0.35\nconst EPS = 1e-6\n\ntype Interval = [number, number]\n\nconst ceilTo = (value: number, step: number): number => Math.ceil(value / step - 1e-9) * step\nconst isConcreteSlab = (part: StructurePart, material: string): boolean => part.role === 'slab' && part.material === material && SLAB_ID.test(part.id)\nconst isBondBeam = (part: StructurePart, material: string): boolean => part.role === 'beam' && part.beamKind === 'bond_beam' && part.material === material\n\nfunction merged(intervals: readonly Interval[]): Interval[] {\n const out: Interval[] = []\n for (const [a, b] of intervals.slice().sort((x, y) => x[0] - y[0])) {\n const last = out[out.length - 1]\n if (last && a <= last[1] + EPS) last[1] = Math.max(last[1], b)\n else out.push([a, b])\n }\n return out\n}\n\n/**\n * The span the destruction world measures for a beam from `0` to `length` held at `supports`: twice the farthest any point is from its nearest support\n * (two supports `g` apart give `g`; a beam hanging `e` past its last support gives `2e`). `at` is where a new support helps the most.\n */\nexport function beamSpan(length: number, supports: readonly Interval[]): { span: number; at: number; lo: number; hi: number } {\n const held = merged(supports.map(([a, b]): Interval => [Math.max(0, a), Math.min(length, b)]).filter(([a, b]) => b > a))\n if (!held.length) return { span: Infinity, at: length / 2, lo: 0, hi: length }\n let span = 0\n let at = length / 2\n let lo = 0\n let hi = length\n const lead = held[0]![0]\n if (2 * lead > span) {\n span = 2 * lead\n at = 0\n lo = 0\n hi = lead\n }\n const trail = length - held[held.length - 1]![1]\n if (2 * trail > span) {\n span = 2 * trail\n at = length\n lo = length - trail\n hi = length\n }\n for (let k = 1; k < held.length; k++) {\n const gap = held[k]![0] - held[k - 1]![1]\n if (gap > span) {\n span = gap\n at = (held[k]![0] + held[k - 1]![1]) / 2\n lo = held[k - 1]![1]\n hi = held[k]![0]\n }\n }\n return { span, at, lo, hi }\n}\n\n/** A beam as a line in the plan: it runs along `dir` at the coordinate `at` of the other axis, from `from` to `to`. */\ninterface Line {\n dir: 'u' | 'v'\n at: number\n from: number\n to: number\n}\n\nconst lineOf = (aabb: Rect, dir: 'u' | 'v'): Line => (dir === 'u' ? { dir, at: (aabb[1] + aabb[3]) / 2, from: aabb[0], to: aabb[2] } : { dir, at: (aabb[0] + aabb[2]) / 2, from: aabb[1], to: aabb[3] })\nconst pointOf = (line: Line, s: number): [number, number] => (line.dir === 'u' ? [line.from + s, line.at] : [line.at, line.from + s])\n\n/** Where `box` holds a beam of `line` and `width`: the stretch of the beam (from its start), or undefined when it does not touch. */\nfunction holds(line: Line, width: number, box: Rect): Interval | undefined {\n const [across0, across1, along0, along1] = line.dir === 'u' ? [box[1], box[3], box[0], box[2]] : [box[0], box[2], box[1], box[3]]\n if (across0 >= line.at + width / 2 + PLAN_TOLERANCE || across1 <= line.at - width / 2 - PLAN_TOLERANCE) return undefined\n const a = Math.max(along0 - PLAN_TOLERANCE, line.from)\n const b = Math.min(along1 + PLAN_TOLERANCE, line.to)\n return b > a ? [a - line.from, b - line.from] : undefined\n}\n\n/** What can hold a beam from below: a pillar or a bearing wall, with how many steps it is from the ground (the destruction world only rests a part on the nearest-to-ground of its supports). */\ninterface Prop {\n box: Rect\n dist: number\n part?: StructurePart\n}\n\ninterface Spot {\n u: number\n v: number\n}\n\ninterface Context {\n structure: Structure\n options: SlabPanelOptions\n beamMaterial: string\n pillarMaterial: string\n joint: JointKind\n wallThickness: number\n parts: StructurePart[]\n supports: Support[]\n panelsOf: Map<string, StructurePart[]>\n pillars: number\n groundBase: string\n /** The distances of the last call to `distancesOf`, kept while no part or support is added (a tower asks for them once per bond beam and per slab). */\n distCache?: { parts: number; supports: number; map: Map<string, number> }\n}\n\nconst boxOfSpot = (spot: Spot, side: number): Rect => [spot.u - side / 2, spot.v - side / 2, spot.u + side / 2, spot.v + side / 2]\n\n/** Steps from the ground of every part, the way the destruction world counts them: through the supports that carry, and not through a partition. */\nfunction distancesOf(context: Context): Map<string, number> {\n const cache = context.distCache\n if (cache && cache.parts === context.parts.length && cache.supports === context.supports.length) return cache.map\n const map = distances(context.parts, context.supports)\n context.distCache = { parts: context.parts.length, supports: context.supports.length, map }\n return map\n}\n\nfunction distances(parts: readonly StructurePart[], supports: readonly Support[]): Map<string, number> {\n const byId = new Map(parts.map((p) => [p.id, p]))\n const carrying = new Map<string, string[]>()\n for (const s of supports) {\n if (s.bears === false || !byId.has(s.part) || (s.on !== GROUND && !byId.has(s.on))) continue\n const list = carrying.get(s.on)\n if (list) list.push(s.part)\n else carrying.set(s.on, [s.part])\n }\n const dist = new Map<string, number>([[GROUND, 0]])\n const queue = [GROUND]\n for (let head = 0; head < queue.length; head++) {\n const current = queue[head]!\n if (current !== GROUND && byId.get(current)?.role === 'partition') continue\n for (const above of carrying.get(current) ?? []) {\n if (dist.has(above) || byId.get(above)?.role === 'none') continue\n dist.set(above, dist.get(current)! + 1)\n queue.push(above)\n }\n }\n return dist\n}\n\n/** Pillars and bearing walls that end where `y0` is (under a beam or a bond beam at that height). */\nfunction propsUnder(context: Context, dist: ReadonlyMap<string, number>, y0: number, y1: number, floor: number): Prop[] {\n return context.parts\n .filter((q) => (q.role === 'column' || q.role === 'wall') && q.floor === floor && dist.has(q.id) && q.y0 < y0 - PLAN_TOLERANCE && q.y1 >= y0 - BELOW && q.y1 <= y1 + UP)\n .map((q) => ({ box: q.aabb, dist: dist.get(q.id)!, part: q }))\n}\n\n/** What holds the beam: of the props that touch it only the ones nearest to the ground do (the world rests a part on those). */\nfunction heldBy(line: Line, width: number, props: readonly Prop[]): { intervals: Interval[]; used: Prop[] } {\n const touching = props.map((prop) => ({ prop, interval: holds(line, width, prop.box) })).filter((x): x is { prop: Prop; interval: Interval } => x.interval !== undefined)\n if (!touching.length) return { intervals: [], used: [] }\n const nearest = Math.min(...touching.map((x) => x.prop.dist))\n const used = touching.filter((x) => x.prop.dist === nearest)\n return { intervals: used.map((x) => x.interval), used: used.map((x) => x.prop) }\n}\n\n/**\n * Finds where a beam (or bond beam) needs pillars so that it never goes more than `maxSpan` without a support (and, for a beam, so that each end is\n * held). `spots` collects the pillars, which then hold the beams after it; `dist` is how far from the ground a pillar is.\n */\nfunction pillarsFor(\n line: Line, width: number, props: readonly Prop[], spots: Array<Spot & { dist: number }>, dist: number, options: SlabPanelOptions, ends: boolean, ground: readonly Rect[] = [],\n): Interval[] {\n const length = line.to - line.from\n const side = options.columnSide\n const all = (): Prop[] => [...props, ...spots.map((spot) => ({ box: boxOfSpot(spot, side), dist: spot.dist }))]\n // a pillar of a storey above the first stands on a beam or a bond beam of the slab under it, not on the middle of a panel\n const allowed = merged(ground.map((box) => holds(line, 0.02, box)).filter((x): x is Interval => x !== undefined))\n const place = (at: number, lo: number, hi: number): number => {\n if (!allowed.length) return at\n let best: number | undefined\n let gap = Infinity\n for (const [a, b] of allowed) {\n const from = Math.max(a + side / 2, lo + 0.2)\n const to = Math.min(b - side / 2, hi - 0.2)\n if (to < from) continue\n const clamped = Math.min(to, Math.max(from, at))\n if (Math.abs(clamped - at) < gap) {\n gap = Math.abs(clamped - at)\n best = clamped\n }\n }\n return best ?? at\n }\n let held = heldBy(line, width, all()).intervals\n for (let guard = 0; guard < 64; guard++) {\n let at: number | undefined\n let lo = 0\n let hi = length\n if (ends && !held.some(([a]) => a <= END_REACH)) at = 0\n else if (ends && !held.some(([, b]) => b >= length - END_REACH)) at = length\n else {\n const found = beamSpan(length, held)\n if (found.span <= options.maxSpan + 1e-3) break\n at = found.at\n lo = found.lo\n hi = found.hi\n }\n const [u, v] = pointOf(line, at === 0 || at === length ? at : place(at, lo, hi))\n const spot = { u: round2(u), v: round2(v), dist }\n if (spots.some((other) => Math.hypot(other.u - spot.u, other.v - spot.v) < 0.15)) break\n spots.push(spot)\n held = heldBy(line, width, all()).intervals\n }\n return held\n}\n\nconst make = (draft: Omit<StructurePart, 'mass'>): StructurePart => {\n const [u0, v0, u1, v1] = draft.aabb\n const volume = Math.max(0, (u1 - u0) * (v1 - v0) * (draft.y1 - draft.y0))\n return { ...draft, aabb: draft.aabb.map(round2) as Rect, y0: round2(draft.y0), y1: round2(draft.y1), mass: Math.max(1, Math.round(volume * densityOf(draft.material))) }\n}\n\nconst rest = (context: Context, on: StructurePart | string, below: StructurePart, joint: JointKind = context.joint): void => {\n context.supports.push({ part: below.id, on: typeof on === 'string' ? on : on.id, joint })\n}\n\nconst distance = (a: Rect, b: Rect): number => Math.hypot(Math.max(a[0] - b[2], b[0] - a[2], 0), Math.max(a[1] - b[3], b[1] - a[3], 0))\n\n/** The panels of `slab` that `box` touches (the nearest one when none does). */\nfunction panelsUnder(context: Context, slab: string, box: Rect): StructurePart[] {\n const panels = context.panelsOf.get(slab) ?? []\n const touching = panels.filter((panel) => touches(panel.aabb, box, PLAN_TOLERANCE))\n return touching.length ? touching : panels.slice().sort((a, b) => distance(a.aabb, box) - distance(b.aabb, box)).slice(0, 1)\n}\n\n/** The pillar at `spot` from `bottom` to `top`, on the ground or on the slab of the storey below. */\nfunction addPillar(context: Context, spot: Spot, bottom: number, top: number, floor: number, below: string | undefined, slab: string): StructurePart {\n const pillar = make({\n id: `pillar_${floor}_${context.pillars++}`, role: 'column', material: context.pillarMaterial, floor, slab, aabb: boxOfSpot(spot, context.options.columnSide), y0: bottom, y1: top,\n })\n context.parts.push(pillar)\n if (below && context.panelsOf.has(below)) for (const panel of panelsUnder(context, below, pillar.aabb)) rest(context, panel, pillar, 'rebar')\n else rest(context, context.groundBase, pillar, 'rebar')\n return pillar\n}\n\n/** The storey under a slab: its floor, the slab it stands on (none: the ground) and the height its pillars start at. */\nfunction storeyUnder(context: Context, slab: StructurePart): { floor: number; below: string | undefined; bottom: number } {\n const levels = context.structure.levels\n const match = /^slab_(\\d+)$/.exec(slab.id)\n const floor = match && Number(match[1]) >= 1 ? Number(match[1]) - 1 : slab.id === 'slab_base' ? 0 : slab.floor\n return { floor, below: slab.id === 'slab_base' || floor < 1 ? undefined : `slab_${floor}`, bottom: slab.id === 'slab_base' ? 0 : (levels[floor] ?? 0) }\n}\n\n/** Steps from the ground of a pillar that stands under `slab`. */\nfunction pillarDist(context: Context, dist: ReadonlyMap<string, number>, storey: { below: string | undefined }): number {\n if (storey.below && context.panelsOf.has(storey.below)) return Math.min(...context.panelsOf.get(storey.below)!.map((p) => dist.get(p.id) ?? 99)) + 1\n return (dist.get(context.groundBase) ?? 0) + 1\n}\n\n/** Where a pillar can stand on the slab `below`: on its beams and on the bond beams at its level. */\nfunction groundOf(context: Context, below: string): Rect[] {\n const panels = context.panelsOf.get(below) ?? []\n const level = panels[0]?.y1\n if (level === undefined) return []\n return context.parts.filter((q) => q.role === 'beam' && (q.slab === below || (q.beamKind === 'bond_beam' && Math.abs(q.y1 - level) < 0.4))).map((q) => q.aabb)\n}\n\n/** Thickness of the panels of a slab: the shortest side of the widest of them over `thicknessRatio`, not under the minimum of the use. */\nfunction thicknessOf(leaves: readonly Rect[], roof: boolean, options: SlabPanelOptions): number {\n const shortest = Math.max(...leaves.map((leaf) => Math.min(leaf[2] - leaf[0], leaf[3] - leaf[1])))\n return Math.max(roof ? options.roofMinThickness : options.floorMinThickness, ceilTo(shortest / options.thicknessRatio, 0.01))\n}\n\nconst restThickness = (slab: StructurePart, thickness: number, roof: boolean): void => {\n if (roof) slab.y1 = round2(slab.y0 + thickness)\n else slab.y0 = round2(slab.y1 - thickness)\n slab.mass = Math.max(1, Math.round((slab.aabb[2] - slab.aabb[0]) * (slab.aabb[3] - slab.aabb[1]) * (slab.y1 - slab.y0) * densityOf(slab.material)))\n}\n\n/** Cuts one slab into panels, adds the beams under their edges and the pillars those need; re-points what rested on the slab. */\nfunction cutSlab(context: Context, slab: StructurePart, wallBoxes: readonly Rect[]): void {\n const { options } = context\n const roof = slab.cover === true\n const layout = layoutPanels(slab.aabb, linesOf(wallBoxes), options)\n const footprint = slab.footprint ?? [slab.aabb]\n const kept = layout.leaves.filter((leaf) => shareInside(leaf, footprint) >= options.footprintShare)\n const leaves = kept.length ? kept : [slab.aabb]\n const thickness = thicknessOf(leaves, roof, options)\n if (leaves.length === 1 && layout.cuts.length === 0) {\n restThickness(slab, thickness, roof)\n context.panelsOf.set(slab.id, [slab])\n return\n }\n const own = context.supports.filter((s) => s.part === slab.id && s.bears !== false)\n const resting = context.supports.filter((s) => s.on === slab.id)\n context.supports = context.supports.filter((s) => s.part !== slab.id && s.on !== slab.id)\n const [y0, y1] = roof ? [slab.y0, slab.y0 + thickness] : [slab.y1 - thickness, slab.y1]\n const panels = leaves.map((leaf, k) =>\n make({\n id: `${slab.id}_p${k}`, role: 'slab', material: slab.material, aabb: leaf, y0, y1, floor: slab.floor, ...(slab.cover ? { cover: true } : {}), slab: slab.id,\n ...(slab.footprint ? { footprint: slab.footprint } : {}),\n }),\n )\n context.parts.splice(context.parts.indexOf(slab), 1, ...panels)\n context.panelsOf.set(slab.id, panels)\n\n // the beams: under the edges of the panels, on pillars and bearing walls; a bond beam that already runs there is the beam\n const top = roof ? slab.y0 : y0\n const dist = distancesOf(context)\n const storey = storeyUnder(context, slab)\n const props = propsUnder(context, dist, top, slab.y1, storey.floor)\n const near = props.length ? Math.min(...props.map((p) => p.dist)) : pillarDist(context, dist, storey)\n const spots: Array<Spot & { dist: number }> = []\n const bonds = context.parts.filter((q) => q.role === 'beam' && q.beamKind === 'bond_beam' && q.y1 >= top - BELOW && q.y0 < slab.y1)\n const ground = storey.below ? groundOf(context, storey.below) : []\n const covered = (line: Line): boolean => {\n const width = context.wallThickness\n const spans = merged(bonds.map((bond) => holds(line, width + 0.5, bond.aabb)).filter((x): x is Interval => x !== undefined))\n return spans.reduce((sum, [a, b]) => sum + Math.max(0, Math.min(b, line.to - line.from) - Math.max(a, 0)), 0) >= (line.to - line.from) * 0.9\n }\n const [su0, sv0, su1, sv1] = slab.aabb\n const borders: Cut[] = [\n { dir: 'u', at: sv0, from: su0, to: su1 }, { dir: 'u', at: sv1, from: su0, to: su1 }, { dir: 'v', at: su0, from: sv0, to: sv1 }, { dir: 'v', at: su1, from: sv0, to: sv1 },\n ]\n const beams: Array<{ part: StructurePart; line: Line; width: number }> = []\n let count = 0\n for (const cut of [...layout.cuts, ...borders]) {\n for (const [from, to] of runsOf(cut, leaves)) {\n const line: Line = { dir: cut.dir === 'v' ? 'v' : 'u', at: cut.at, from, to }\n if (covered(line)) continue\n const held = pillarsFor(line, context.wallThickness, props, spots, near, options, true, ground)\n const span = Math.min(beamSpan(to - from, held).span, options.maxSpan)\n const depth = beamDepthFor(span, options)\n const width = Math.max(context.wallThickness, round2(depth / options.beamWidthRatio))\n const aabb: Rect = line.dir === 'u' ? [from, cut.at - width / 2, to, cut.at + width / 2] : [cut.at - width / 2, from, cut.at + width / 2, to]\n beams.push({ part: make({ id: `${slab.id}_b${count++}`, role: 'beam', material: context.beamMaterial, aabb, y0: top - depth, y1: top, floor: slab.floor, slab: slab.id }), line, width })\n }\n }\n const pillars = spots.map((spot) => addPillar(context, spot, storey.bottom, top, storey.floor, storey.below, slab.id))\n context.parts.splice(context.parts.indexOf(panels[panels.length - 1]!) + 1, 0, ...beams.map((b) => b.part))\n const all: Prop[] = [...props, ...pillars.map((p, k) => ({ box: p.aabb, dist: spots[k]!.dist, part: p }))]\n for (const { part: beam, line, width } of beams) for (const used of heldBy(line, width, all).used) rest(context, used.part!, beam)\n\n // the panels rest on the beams of their edges and on the bond beams (the walls and pillars under them hold the beams)\n for (const panel of panels) {\n for (const { part: beam } of beams) if (touches(panel.aabb, beam.aabb, PLAN_TOLERANCE)) rest(context, beam, panel)\n for (const bond of bonds) if (touches(panel.aabb, bond.aabb, PLAN_TOLERANCE)) rest(context, bond, panel, own.find((s) => s.on === bond.id)?.joint ?? context.joint)\n }\n for (const panel of panels.filter((p) => !context.supports.some((s) => s.part === p.id))) {\n const nearest = [...beams.map((b) => b.part), ...bonds].sort((a, b) => distance(a.aabb, panel.aabb) - distance(b.aabb, panel.aabb))[0]\n if (nearest) rest(context, nearest, panel)\n }\n // what rested on the slab rests on the panels it touches\n for (const support of resting) {\n const upper = context.parts.find((q) => q.id === support.part)\n if (!upper) continue\n for (const panel of panelsUnder(context, slab.id, upper.aabb)) context.supports.push({ ...support, on: panel.id })\n }\n}\n\n/** Depth of a beam over `span` metres: `span / beamDepthRatio` up to a multiple of `beamStep`, not under `minimum`. */\nexport const beamDepthFor = (span: number, options: SlabPanelOptions, minimum = options.beamMinDepth): number => Math.max(minimum, ceilTo(span / options.beamDepthRatio, options.beamStep))\n\n/**\n * After the walls are cut at their windows: a bond beam over a wide opening spans it (the destruction world rests it on the piers, the nearest of its supports\n * to the ground), so it gets the depth and the width of a beam of that span. Returns copies of the parts it changes.\n */\nexport function deepenBondBeams(input: PartsAndSupports, structure: Structure, options: SlabPanelOptions): PartsAndSupports {\n const frame = structure.construction.frame\n if (!frame.rebar) return input\n const dist = distances(input.parts, input.supports)\n const context = { parts: input.parts } as Context\n let changed = false\n const parts = input.parts.map((part) => {\n if (!isBondBeam(part, frame.beams) || !dist.has(part.id)) return part\n const dir: 'u' | 'v' = part.aabb[2] - part.aabb[0] >= part.aabb[3] - part.aabb[1] ? 'u' : 'v'\n const line = lineOf(part.aabb, dir)\n const width = dir === 'u' ? part.aabb[3] - part.aabb[1] : part.aabb[2] - part.aabb[0]\n const span = beamSpan(line.to - line.from, heldBy(line, width, propsUnder(context, dist, part.y0, part.y1, part.floor)).intervals).span\n if (!(span > 1.5) || !Number.isFinite(span)) return part\n const depth = Math.max(part.y1 - part.y0, beamDepthFor(span, options))\n const wide = Math.max(width, round2(depth / options.beamWidthRatio))\n const grow = (wide - width) / 2\n changed = true\n const aabb: Rect = dir === 'u' ? [part.aabb[0], part.aabb[1] - grow, part.aabb[2], part.aabb[3] + grow] : [part.aabb[0] - grow, part.aabb[1], part.aabb[2] + grow, part.aabb[3]]\n return make({ ...part, aabb, y0: part.y1 - depth })\n })\n return changed ? { parts, supports: input.supports } : input\n}\n\n/** Adds the pillars a concrete bond beam needs under it (a frame whose walls only close has none between its corners) and deepens it over a wide span. */\nfunction supportBondBeam(context: Context, plate: StructurePart): void {\n const { options } = context\n const dir: 'u' | 'v' = plate.aabb[2] - plate.aabb[0] >= plate.aabb[3] - plate.aabb[1] ? 'u' : 'v'\n const line = lineOf(plate.aabb, dir)\n const width = dir === 'u' ? plate.aabb[3] - plate.aabb[1] : plate.aabb[2] - plate.aabb[0]\n const dist = distancesOf(context)\n const floor = plate.floor\n const props = propsUnder(context, dist, plate.y0, plate.y1, floor)\n const storey = { floor, below: floor >= 1 ? `slab_${floor}` : undefined, bottom: context.structure.levels[floor] ?? 0 }\n const spots: Array<Spot & { dist: number }> = []\n const near = props.length ? Math.min(...props.map((p) => p.dist)) : pillarDist(context, dist, storey)\n const held = pillarsFor(line, width, props, spots, near, options, false)\n const span = beamSpan(line.to - line.from, held).span\n if (span > 1.5) {\n const depth = Math.max(plate.y1 - plate.y0, beamDepthFor(Math.min(span, options.maxSpan), options))\n plate.y0 = round2(plate.y1 - depth)\n plate.mass = Math.max(1, Math.round((plate.aabb[2] - plate.aabb[0]) * (plate.aabb[3] - plate.aabb[1]) * depth * densityOf(plate.material)))\n }\n for (const spot of spots) {\n const pillar = addPillar(context, spot, storey.bottom, plate.y0 + PLAN_TOLERANCE, floor, storey.below, plate.id)\n rest(context, pillar, plate, 'rebar')\n }\n}\n\n/**\n * The slabs of concrete cut into panels with beams (`SlabPanelOptions`): see `T10-estrutura-real.md` §12. `input` is the structure as\n * `toDestructibleSpec` has it (walls with their roles), and the result has the panels, the beams, the pillars they need and the supports re-pointed.\n */\nexport function applySlabPanels(input: PartsAndSupports, structure: Structure, options: SlabPanelOptions): PartsAndSupports {\n const frame = structure.construction.frame\n const system = CONSTRUCTION_SYSTEMS.get(structure.construction.system)\n if (!frame.rebar || !system || system.timber || structure.levels.length > options.maxStoreys) return input\n const parts = input.parts.map((p) => ({ ...p }))\n const slabs = parts.filter((p) => isConcreteSlab(p, frame.slabs))\n const bonds = parts.filter((p) => isBondBeam(p, frame.beams))\n if (!slabs.length && !bonds.length) return input\n const firstColumn = input.supports.find((s) => /^(column_0_|building_column_)/.test(s.part) && !/^(column_0_|building_column_)/.test(s.on))\n const context: Context = {\n structure, options, beamMaterial: frame.beams, pillarMaterial: frame.pillars, joint: system.joints.slab, wallThickness: (structure.construction.walls.thickness as number | undefined) ?? 0.15,\n parts, supports: input.supports.slice(), panelsOf: new Map(), pillars: 0, groundBase: firstColumn?.on ?? GROUND,\n }\n const walls = parts.filter((p) => /^wall_/.test(p.id) && (p.role === 'wall' || p.role === 'partition'))\n const jobs = [...bonds.map((part) => ({ part, bond: true })), ...slabs.map((part) => ({ part, bond: false }))].sort((a, b) => a.part.y0 - b.part.y0 || Number(b.bond) - Number(a.bond))\n for (const job of jobs) {\n if (job.bond) {\n supportBondBeam(context, job.part)\n continue\n }\n const slab = job.part\n const boxes = walls.filter((w) => (w.y0 >= slab.y1 - 0.1 && w.y0 <= slab.y1 + 0.4) || (w.y1 >= slab.y0 - 0.4 && w.y1 <= slab.y0 + 0.1 && w.y0 < slab.y0)).map((w) => w.aabb)\n cutSlab(context, slab, boxes)\n }\n if (structure.construction.foundation.type === 'building') anchorBalconies(context)\n return { parts: context.parts, supports: context.supports }\n}\n\n/**\n * A unit of a building stands high above the ground, and the balcony of its plan comes with a pillar of its own that starts at the ground floor: the\n * pillar would be five storeys of a single column under one corner. The balcony is a cantilever of the unit's slab (`slab_base`) and the pillar goes.\n */\nfunction anchorBalconies(context: Context): void {\n const base = context.panelsOf.get('slab_base')\n if (!base) return\n const decks = context.parts.filter((p) => p.role === 'slab' && /^slab_\\d+_/.test(p.id) && context.supports.some((s) => s.part === p.id && /^balcony_column_/.test(s.on)))\n for (const deck of decks) {\n const pillars = new Set(context.supports.filter((s) => s.part === deck.id && /^balcony_column_/.test(s.on)).map((s) => s.on))\n context.supports = context.supports.filter((s) => s.part !== deck.id && !pillars.has(s.part) && !pillars.has(s.on))\n context.parts = context.parts.filter((p) => !pillars.has(p.id))\n for (const panel of panelsUnder(context, 'slab_base', deck.aabb)) rest(context, panel, deck)\n }\n}\n\n/**\n * The panels `toDestructibleSpec` makes of the slabs of a structure (named as it names them), for a renderer that draws the floor of each room apart:\n * `panels` (each with `slab`, the id of the slab it was cut from), `replaced` (those slabs, which the spec no longer has) and the `supports` that touch the panels.\n */\nexport function slabPanelView(structure: Structure, options: SlabPanelOptions): { panels: StructurePart[]; replaced: string[]; supports: Support[] } {\n const out = applySlabPanels({ parts: structure.parts, supports: structure.supports }, structure, options)\n const panels = out.parts.filter((p) => p.slab !== undefined && p.role === 'slab')\n const ids = new Set(panels.map((p) => p.id))\n return { panels, replaced: [...new Set(panels.map((p) => p.slab!))], supports: out.supports.filter((s) => ids.has(s.part) || ids.has(s.on)) }\n}\n\n/** The panels of `slabPanelView`, alone. */\nexport const slabPanelsOf = (structure: Structure, options: SlabPanelOptions): StructurePart[] => slabPanelView(structure, options).panels\n","/**\n * How a concrete slab of a house is cut into panels with beams under their edges, and where pillars are added so that every beam spans a\n * reasonable distance (design T10-estrutura-real.md §12). Every number is a choice of the design and can be changed per call\n * (`toDestructibleSpec({ slabPanels: { maxSpan: 4 } })`).\n */\nexport interface SlabPanelOptions {\n /** Longest side of a panel and longest stretch of a beam or bond beam without a support, metres (default 5). */\n maxSpan: number\n /** A cut never leaves a piece narrower than this, metres (default 1.5). */\n minPanel: number\n /** Share of a line of the panel a wall must cover (doors included) for the line to be a room boundary the panel is cut along (default 0.6). */\n lineCoverage: number\n /** A gap in a line of walls up to this wide is a door and counts as wall, metres (default 1.3). */\n doorGap: number\n /** Walls whose lines are this close are one line, metres (default 0.2). */\n lineTolerance: number\n /** A panel with less than this share of its area inside the footprint of the slab is left out (default 0.5). */\n footprintShare: number\n /** Thickness of a panel is its short side over this (default 40: `h = L/40`). */\n thicknessRatio: number\n /** Thinnest floor slab, metres (default 0.10). */\n floorMinThickness: number\n /** Thinnest roof slab, metres (default 0.08). */\n roofMinThickness: number\n /** Depth of a beam is its span over this (default 10: `h = L/10`, a simply supported beam of NBR 6118, and deep enough for the frame to carry the loss of one pillar; continuous beams are L/12). */\n beamDepthRatio: number\n /** Shallowest beam, metres (default 0.25). */\n beamMinDepth: number\n /** Depth of beams and bond beams is rounded up to a multiple of this, metres (default 0.05). */\n beamStep: number\n /** Width of a beam is the thickness of the wall it hides in, or its depth over this when that is wider (default 3). */\n beamWidthRatio: number\n /** Side of the pillars that are added, metres (default 0.20; NBR 6118 13.2.3 asks for 19 cm). */\n columnSide: number\n /**\n * Most storeys of a building that gets panels (default 8). A tall building is a frame of its own (`buildTower`, the skyscraper presets), and cutting its 40 slabs and\n * sizing every pillar for the loss of each other one is quadratic: minutes for the 40-storey tower of the plan engine. It keeps its slabs whole, and the steel is not declared.\n */\n maxStoreys: number\n}\n\nexport const SLAB_PANEL_DEFAULTS: Readonly<SlabPanelOptions> = {\n maxSpan: 5, minPanel: 1.5, lineCoverage: 0.6, doorGap: 1.3, lineTolerance: 0.2, footprintShare: 0.5, thicknessRatio: 40, floorMinThickness: 0.1, roofMinThickness: 0.08,\n beamDepthRatio: 10, beamMinDepth: 0.25, beamStep: 0.05, beamWidthRatio: 3, columnSide: 0.2, maxStoreys: 8,\n}\n\nexport const resolveSlabPanels = (options?: boolean | Partial<SlabPanelOptions>): SlabPanelOptions | undefined => {\n if (options === false) return undefined\n const given = options === true || options === undefined ? {} : options\n const out = { ...SLAB_PANEL_DEFAULTS }\n for (const key of Object.keys(given) as (keyof SlabPanelOptions)[]) if (given[key] !== undefined) out[key] = given[key]!\n return out\n}\n","import { touches } from '../geometry'\nimport type { Rect, StructurePart, Support } from '../types'\nimport type { WallSplit } from './panels'\n\nexport interface PartsAndSupports {\n parts: StructurePart[]\n supports: Support[]\n}\n\n/** Replaces each part that has a split by its pieces, and re-points what rested on it or what it rested on (the pieces touching the part resting on it get the load). */\nexport function applySplits(input: PartsAndSupports, splits: ReadonlyMap<string, WallSplit>): PartsAndSupports {\n if (!splits.size) return input\n const boxes = new Map<string, Rect>(input.parts.map((part) => [part.id, part.aabb]))\n const pieceBox = new Map<string, Rect>()\n for (const split of splits.values()) for (const piece of split.pieces) pieceBox.set(piece.id, piece.aabb)\n const parts = input.parts.flatMap((part) => splits.get(part.id)?.pieces ?? [part])\n const supports: Support[] = []\n for (const support of input.supports) {\n const own = splits.get(support.part)\n const host = splits.get(support.on)\n const resting = boxes.get(support.part)\n const targets = host ? host.top.filter((id) => resting && touches(pieceBox.get(id)!, resting, 0.05)) : [support.on]\n const carriers = host ? (targets.length ? targets : host.top) : targets\n for (const part of own ? own.base : [support.part]) for (const on of carriers) supports.push({ ...support, part, on })\n }\n for (const split of splits.values()) supports.push(...split.internal)\n return { parts, supports }\n}\n","import type { JointKind } from '@adatechnology/game-contracts'\n\nimport { round2 } from '../geometry'\nimport type { Opening, Rect, StructurePart, Support } from '../types'\nimport type { WallSplit } from './panels'\n\nexport interface CourseSpec {\n rowHeight: number\n /** Length of a unit along the wall; without it a course is one piece per stretch (a log). */\n unitLength?: number\n bond: 'running' | 'stack'\n /** Joint of a unit on the units under it. */\n joint: JointKind\n assembly: string\n}\n\nconst MIN_UNIT = 0.02\n\ninterface Cell {\n from: number\n to: number\n row: number\n y0: number\n y1: number\n}\n\nfunction cutAt(from: number, to: number, openings: readonly Opening[], y0: number, y1: number): [number, number][] {\n let stretches: [number, number][] = [[from, to]]\n for (const opening of openings.filter((o) => o.y0 < y1 - MIN_UNIT && o.y1 > y0 + MIN_UNIT)) {\n stretches = stretches.flatMap(([a, b]): [number, number][] => {\n if (opening.to <= a || opening.from >= b) return [[a, b]]\n return [[a, Math.min(b, opening.from)], [Math.max(a, opening.to), b]].filter(([x, y]) => (y as number) - (x as number) > MIN_UNIT) as [number, number][]\n })\n }\n return stretches\n}\n\nfunction unitsOf(from: number, to: number, row: number, spec: CourseSpec): [number, number][] {\n const length = spec.unitLength\n if (!length) return [[from, to]]\n const offset = spec.bond === 'running' && row % 2 === 1 ? length / 2 : 0\n const cuts: number[] = [from]\n for (let at = from + (offset || length); at < to - MIN_UNIT; at += length) cuts.push(at)\n cuts.push(to)\n return cuts.slice(0, -1).map((start, k): [number, number] => [start, cuts[k + 1]!]).filter(([a, b]) => b - a > MIN_UNIT)\n}\n\n/**\n * Cuts a wall into courses of units (bricks laid in bond, or logs): each course is cut at the openings it meets, and each unit rests on the units of the course\n * below that it overlaps. A wall whose lowest course goes loses every course above it. The mass of the wall is shared among the units by volume.\n */\nexport function splitIntoCourses(wall: StructurePart, openings: readonly Opening[], spec: CourseSpec): WallSplit {\n const alongU = wall.aabb[2] - wall.aabb[0] >= wall.aabb[3] - wall.aabb[1]\n const from = alongU ? wall.aabb[0] : wall.aabb[1]\n const to = alongU ? wall.aabb[2] : wall.aabb[3]\n const cross: [number, number] = alongU ? [wall.aabb[1], wall.aabb[3]] : [wall.aabb[0], wall.aabb[2]]\n const rows = Math.max(1, Math.round((wall.y1 - wall.y0) / spec.rowHeight))\n const rowHeight = (wall.y1 - wall.y0) / rows\n const cells: Cell[] = []\n for (let row = 0; row < rows; row++) {\n const y0 = wall.y0 + row * rowHeight\n const y1 = wall.y0 + (row + 1) * rowHeight\n for (const [a, b] of cutAt(from, to, openings.filter((o) => o.wall === wall.id), y0, y1)) for (const [x0, x1] of unitsOf(a, b, row, spec)) cells.push({ from: x0, to: x1, row, y0, y1 })\n }\n const total = cells.reduce((sum, cell) => sum + (cell.to - cell.from) * (cell.y1 - cell.y0), 0)\n const box = (cell: Cell): Rect => (alongU ? [cell.from, cross[0], cell.to, cross[1]] : [cross[0], cell.from, cross[1], cell.to])\n const pieces = cells.map((cell, index): StructurePart => ({\n id: `${wall.id}_${spec.unitLength ? 'u' : 'log'}${cell.row}_${index}`, role: wall.role, material: wall.material, aabb: box(cell), y0: cell.y0, y1: cell.y1, floor: wall.floor,\n mass: round2(Math.max(0.1, (wall.mass * (cell.to - cell.from) * (cell.y1 - cell.y0)) / total)), host: wall.id, assembly: spec.assembly, unit: true,\n }))\n const internal: Support[] = []\n cells.forEach((cell, index) => {\n if (cell.row === 0) return\n const below = cells.map((other, k) => ({ other, k })).filter(({ other }) => other.row === cell.row - 1 && Math.min(other.to, cell.to) - Math.max(other.from, cell.from) > MIN_UNIT)\n for (const { k } of below) internal.push({ part: pieces[index]!.id, on: pieces[k]!.id, joint: spec.joint })\n })\n return { pieces, internal, base: pieces.filter((_, i) => cells[i]!.row === 0).map((p) => p.id), top: pieces.filter((_, i) => cells[i]!.row === rows - 1).map((p) => p.id) }\n}\n","import type { JointKind } from '@adatechnology/game-contracts'\n\nimport { round2 } from '../geometry'\nimport type { Opening, Rect, StructurePart, Support } from '../types'\n\nexport interface PanelStyle {\n lintelMaterial: string\n lintelAssembly?: string\n /** Joint of a lintel on its piers and of the wall above it on the lintel. */\n lintelJoint: JointKind\n wallJoint: JointKind\n /** Depth of the lintel over an opening of the given width, metres (default `LINTEL_DEPTH`): a wide opening needs a deeper beam. */\n lintelDepth?: (span: number) => number\n}\n\nexport interface WallSplit {\n pieces: StructurePart[]\n /** What the pieces rest on among themselves (lintel on piers, spandrel on lintel). */\n internal: Support[]\n /** Pieces that rest on what the wall rests on. */\n base: string[]\n /** Pieces that carry what rests on the wall. */\n top: string[]\n}\n\nexport const LINTEL_DEPTH = 0.2\nexport const LINTEL_BEARING = 0.2\nconst MIN_PIECE = 0.05\n\ninterface Frame {\n alongU: boolean\n from: number\n to: number\n cross: [number, number]\n}\n\nconst frameOf = (wall: StructurePart): Frame => {\n const alongU = wall.aabb[2] - wall.aabb[0] >= wall.aabb[3] - wall.aabb[1]\n return alongU ? { alongU, from: wall.aabb[0], to: wall.aabb[2], cross: [wall.aabb[1], wall.aabb[3]] } : { alongU, from: wall.aabb[1], to: wall.aabb[3], cross: [wall.aabb[0], wall.aabb[2]] }\n}\n\nconst boxOf = (frame: Frame, from: number, to: number): Rect => (frame.alongU ? [from, frame.cross[0], to, frame.cross[1]] : [frame.cross[0], from, frame.cross[1], to])\n\ninterface Draft {\n id: string\n role: StructurePart['role']\n material: string\n assembly?: string\n from: number\n to: number\n y0: number\n y1: number\n /** Volume that counts for the mass share (pieces tile the wall: a lintel keeps the bearing it shares with the piers). */\n volume: number\n}\n\n/**\n * Cuts a wall at its windows: piers between them at full height, a sill wall under each window, a lintel over it that bears 0.2 m on the piers and the wall\n * above the lintel up to the top. The mass of the wall is shared among the pieces by volume, so the total is the wall's.\n */\nexport function splitIntoPanels(wall: StructurePart, openings: readonly Opening[], style: PanelStyle): WallSplit {\n const frame = frameOf(wall)\n const own = openings.filter((o) => o.wall === wall.id && o.to > frame.from + MIN_PIECE && o.from < frame.to - MIN_PIECE).sort((a, b) => a.from - b.from)\n if (!own.length) return { pieces: [wall], internal: [], base: [wall.id], top: [wall.id] }\n const drafts: Draft[] = []\n const piers: Draft[] = []\n const lintels: Draft[] = []\n const spandrels: (Draft | undefined)[] = []\n const height = wall.y1 - wall.y0\n let cursor = frame.from\n const roleOf = wall.role\n const addPier = (to: number): void => {\n if (to - cursor < MIN_PIECE) return\n piers.push({ id: `${wall.id}_pier_${piers.length}`, role: roleOf, material: wall.material, from: cursor, to, y0: wall.y0, y1: wall.y1, volume: (to - cursor) * height })\n }\n own.forEach((opening, k) => {\n addPier(Math.max(cursor, opening.from))\n const lintelTop = Math.min(wall.y1, opening.y1 + Math.max(LINTEL_DEPTH, style.lintelDepth?.(opening.to - opening.from) ?? 0))\n const lintelFrom = Math.max(frame.from, opening.from - LINTEL_BEARING)\n const lintelTo = Math.min(frame.to, opening.to + LINTEL_BEARING)\n const lintelHeight = lintelTop - opening.y1\n if (opening.y0 - wall.y0 > MIN_PIECE) drafts.push({ id: `${wall.id}_sill_${k}`, role: 'partition', material: wall.material, from: opening.from, to: opening.to, y0: wall.y0, y1: opening.y0, volume: (opening.to - opening.from) * (opening.y0 - wall.y0) })\n lintels.push({ id: `${wall.id}_lintel_${k}`, role: 'beam', material: style.lintelMaterial, from: lintelFrom, to: lintelTo, y0: opening.y1, y1: lintelTop, volume: (lintelTo - lintelFrom) * lintelHeight })\n spandrels.push(wall.y1 - lintelTop > MIN_PIECE ? { id: `${wall.id}_spandrel_${k}`, role: roleOf, material: wall.material, from: opening.from, to: opening.to, y0: lintelTop, y1: wall.y1, volume: (opening.to - opening.from) * (wall.y1 - lintelTop) } : undefined)\n cursor = opening.to\n })\n addPier(frame.to)\n // the piers give the bearing zone of each lintel to it\n for (const pier of piers) {\n for (const lintel of lintels) {\n const overlap = Math.max(0, Math.min(pier.to, lintel.to) - Math.max(pier.from, lintel.from))\n pier.volume -= overlap * (lintel.y1 - lintel.y0)\n }\n }\n const all = [...piers, ...drafts, ...lintels, ...spandrels.filter((d): d is Draft => d !== undefined)]\n const total = all.reduce((sum, d) => sum + d.volume, 0)\n const pieces = all.map((d): StructurePart => ({\n id: d.id, role: d.role, material: d.material, aabb: boxOf(frame, d.from, d.to), y0: d.y0, y1: d.y1, floor: wall.floor, mass: round2(Math.max(0.1, (wall.mass * d.volume) / total)), host: wall.id,\n ...(d.role === 'beam' ? (style.lintelAssembly ? { assembly: style.lintelAssembly } : {}) : wall.assembly ? { assembly: wall.assembly } : {}),\n }))\n const internal: Support[] = []\n lintels.forEach((lintel, k) => {\n for (const pier of piers) if (Math.min(pier.to, lintel.to) - Math.max(pier.from, lintel.from) > 0) internal.push({ part: lintel.id, on: pier.id, joint: style.lintelJoint })\n const spandrel = spandrels[k]\n if (spandrel) internal.push({ part: spandrel.id, on: lintel.id, joint: style.wallJoint })\n })\n const base = [...piers, ...drafts.filter((d) => d.id.includes('_sill_'))].map((d) => d.id)\n const top = [...piers.map((p) => p.id), ...lintels.map((l, k) => spandrels[k]?.id ?? l.id)]\n return { pieces, internal, base, top }\n}\n","import { getAssembly } from '@adatechnology/game-destruction'\n\nimport type { Construction, Rect, Structure, StructurePart, WallDetail } from '../types'\nimport { applySplits } from './apply'\nimport type { PartsAndSupports } from './apply'\nimport { splitIntoCourses } from './courses'\nimport type { CourseSpec } from './courses'\nimport { splitIntoPanels } from './panels'\nimport type { WallSplit } from './panels'\nimport { CONSTRUCTION_SYSTEMS } from '../registry'\n\nconst LOG_DIAMETER = 0.26\nconst isWall = (part: StructurePart): boolean => part.id.startsWith('wall_') && part.assembly !== undefined && (part.role === 'wall' || part.role === 'partition')\n\nfunction logSpec(construction: Construction, part: StructurePart): CourseSpec {\n const diameter = (construction.walls.logDiameter as number | undefined) ?? LOG_DIAMETER\n return { rowHeight: diameter, bond: 'stack', joint: CONSTRUCTION_SYSTEMS.get(construction.system)!.joints.wall, assembly: part.assembly! }\n}\n\n/** Walls cut at their windows (piers, sills, lintels, spandrels); the walls of logs as courses of logs. */\nfunction panelSplits(input: PartsAndSupports, structure: Structure, lintelDepth?: (span: number) => number): Map<string, WallSplit> {\n const { construction } = structure\n const system = CONSTRUCTION_SYSTEMS.get(construction.system)!\n const splits = new Map<string, WallSplit>()\n for (const part of input.parts.filter(isWall)) {\n if (construction.system === 'log') {\n splits.set(part.id, splitIntoCourses(part, structure.openings, logSpec(construction, part)))\n continue\n }\n const split = splitIntoPanels(part, structure.openings, {\n lintelMaterial: system.timber ? construction.frame.timber : 'concrete', ...(system.timber ? {} : { lintelAssembly: 'reinforced_concrete' }), lintelJoint: system.joints.beam, wallJoint: system.joints.wall, ...(lintelDepth && !system.timber ? { lintelDepth } : {}),\n })\n if (split.pieces.length > 1) splits.set(part.id, split)\n }\n return splits\n}\n\n/** Splits the walls the way `detail` says: `coarse` keeps one part per wall, `panels` cuts them at the windows, `units` goes on to bricks and blocks. */\nexport function applyPanels(input: PartsAndSupports, structure: Structure, detail: WallDetail, lintelDepth?: (span: number) => number): PartsAndSupports {\n if (detail === 'coarse') return input\n return applySplits(input, panelSplits(input, structure, lintelDepth))\n}\n\nexport interface Sized extends PartsAndSupports {\n capacities: Map<string, number>\n}\n\n/** Cuts each wall piece that its assembly lays in units (bricks, blocks, concrete panels) into those units; a unit takes the share of the piece's capacity its width has (it carries its column of the wall). */\nexport function applyUnits(input: Sized, structure: Structure): Sized {\n const splits = new Map<string, WallSplit>()\n for (const part of input.parts) {\n if (part.unit || !part.assembly || part.role === 'beam' || part.role === 'none') continue\n const units = getAssembly(part.assembly)?.units\n if (!units) continue\n const joint = CONSTRUCTION_SYSTEMS.get(structure.construction.system)!.joints.wall\n splits.set(part.id, splitIntoCourses(part, [], { rowHeight: units.size[1], unitLength: units.size[0], bond: units.bond, joint: units.mortar === 'concrete' ? 'mortar' : joint, assembly: part.assembly }))\n }\n const next = applySplits(input, splits)\n const capacities = new Map(input.capacities)\n for (const [id, split] of splits) {\n const capacity = input.capacities.get(id)\n capacities.delete(id)\n if (capacity === undefined) continue\n const along = (box: Rect): number => Math.max(box[2] - box[0], box[3] - box[1])\n const length = along(input.parts.find((part) => part.id === id)!.aabb)\n for (const piece of split.pieces) capacities.set(piece.id, Math.max(1, (capacity * along(piece.aabb)) / length))\n }\n return { ...next, capacities }\n}\n","import type { DestructibleSpec, JointSpec, PartSpec, PileSpec, SoilProfile, StructureRole } from '@adatechnology/game-contracts'\nimport { GRAVITY, MATERIALS, SOILS, assemblyPart, partMass, pileLength, profileOf, sizeRebar } from '@adatechnology/game-destruction'\nimport type { SoilDef } from '@adatechnology/game-destruction'\nimport { sizeCapacities } from './loads'\nimport { GROUND } from './types'\nimport { resolveSlabPanels } from './slab-panels'\nimport type { SlabPanelOptions } from './slab-panels'\nimport { applySlabPanels, beamDepthFor, deepenBondBeams } from './slab-panels'\nimport { applyPanels, applyUnits } from './wall-detail'\nimport type { FoundationType, PartRole, Structure, StructurePart, WallDetail } from './types'\n\nexport interface DestructibleSpecOptions {\n /** Fraction of its capacity a pillar or bearing wall uses at rest (default 0.65). */\n safety?: number\n /** After losing any other pillar or bearing wall, the most of its capacity one of them uses (default 0.97: the house holds one loss and falls with two). */\n redundancy?: number\n /** Fraction of capacity beams, slabs, roofs, stairs and partitions use at rest (default 0.45). */\n safetyOthers?: number\n /** Bearing walls close but do not carry: a frame of pillars and beams carries the building. Default: for a framed building unless the detail is `coarse`. */\n portico?: boolean\n /** How finely the walls are split (default `panels`; `coarse` is one part per wall as the Visor de casas 3D builds it). */\n wallDetail?: WallDetail\n /**\n * Cuts the concrete slabs into panels with a beam under each edge, and adds the pillars those beams and the bond beams need (design T10 §12): `true` for\n * `SLAB_PANEL_DEFAULTS`, options to change them, `false` for the slab as one piece, as the Visor de casas 3D describes it. Default `true`.\n */\n slabPanels?: boolean | Partial<SlabPanelOptions>\n /** Name of the spec (default `house`). */\n name?: string\n /** Leaves parts out (and what rests on them is dropped from the joints). */\n filter?: (part: StructurePart) => boolean\n /** `false` keeps the capacity of the material instead of sizing it from the load. */\n sized?: boolean\n /** Metres the anchored terrain slab reaches beyond the parts (default 6). */\n terrainMargin?: number\n /**\n * Declares the tension steel of the concrete beams, slabs, roofs and stairs of a construction with rebar (`structure.rebar.ratio`), so the destruction\n * world bends them (`structure.flexure` of game-destruction): `true` for the default ratios (`REBAR_RATIOS`), or ratios per role. When the spec is\n * sized the steel is sized too (`sizeRebar`: at rest at `safetyOthers`, after the loss of any pillar or bearing wall under `redundancy`). On by\n * default (a house of concrete is reinforced concrete, with the slab in panels on real beams, `slabPanels`); `false` leaves the concrete plain, as the\n * Visor de casas 3D describes it.\n */\n rebar?: boolean | Partial<Record<'beam' | 'slab' | 'roof' | 'stair', number>>\n /**\n * The ground the house stands on (`DestructibleSpec.soil` of game-contracts: a soil class id such as `clay_stiff`, or a profile of layers). With it\n * the foundations bear on the soil (game-destruction `soil`): the house settles, and tips over where the soil cannot carry it. A raft foundation\n * (`raft`, `basement`, `building`) becomes a concrete raft under the footprint (`RAFT_THICKNESS`) instead of the anchored terrain; any other\n * foundation keeps the terrain and every wall and pillar on it bears on a footing at least `footingWidth` wide. Off by default.\n */\n soil?: string | SoilProfile\n /** Foundation used with `soil` (default the construction's `foundation.type`). */\n foundation?: FoundationType\n /**\n * Deep concrete piles under the raft (a piled raft; with `soil` only). `length` omitted: each pile goes down to where it carries its share of the\n * house with the NBR 6122 safety (`pileLength`). Defaults: diameter 0.4 m, one pile per `PILE_AREA` m² of raft, at least 4, bored.\n */\n piles?: true | Partial<PileSpec>\n /** Soil classes beyond `SOILS` that `soil` names (the same ones given to the destruction world in `soil.soils`). */\n soils?: readonly SoilDef[]\n}\n\n/** Thickness of the raft of a house on the soil, metres (usual 0.20 to 0.30 m). */\nexport const RAFT_THICKNESS = 0.25\n/** Raft area per pile when the count is not given, m² (a 3 x 3 m grid). */\nexport const PILE_AREA = 9\n/** Metres the raft reaches beyond the walls. */\nconst RAFT_MARGIN = 0.15\nconst RAFT_FOUNDATIONS: ReadonlySet<FoundationType> = new Set(['raft', 'basement', 'building'])\n\n/**\n * Tension steel ratio a concrete member starts with before sizing, `As / (b d)`: beams 0.8%, slabs and roof slabs 0.25%, stairs 0.4% (inside the\n * usual ranges of NBR 6118; the minimum for C25 is 0.15%).\n */\nexport const REBAR_RATIOS: Readonly<Record<'beam' | 'slab' | 'roof' | 'stair', number>> = { beam: 0.008, slab: 0.0025, roof: 0.0025, stair: 0.004 }\n\nconst CONTRACT_ROLE: Record<PartRole, StructureRole> = { column: 'column', beam: 'beam', slab: 'slab', wall: 'wall', partition: 'partition', roof: 'roof', stair: 'stair', none: 'none' }\n\nconst TERRAIN_MARGIN = 6\nconst TERRAIN_THICKNESS = 0.5\n\nconst boxSpec = (part: StructurePart, capacity: number | undefined): PartSpec => {\n const [u0, v0, u1, v1] = part.aabb\n return {\n id: part.id, material: part.material, shape: { kind: 'box', size: [Math.max(0.01, u1 - u0), Math.max(0.01, part.y1 - part.y0), Math.max(0.01, v1 - v0)] },\n position: [(u0 + u1) / 2, (part.y0 + part.y1) / 2, (v0 + v1) / 2], mass: Math.max(0.1, part.mass || 1),\n structure: capacity === undefined ? { role: CONTRACT_ROLE[part.role] } : { role: CONTRACT_ROLE[part.role], capacity },\n }\n}\n\n/** A wall piece as its assembly builds it (layers, rebar, units, breach), with the mass the structure gave it. A brick or log is the unit itself, so it keeps no units or breach. */\nconst assemblySpec = (part: StructurePart, capacity: number | undefined): PartSpec => {\n const [u0, v0, u1, v1] = part.aabb\n const alongU = u1 - u0 >= v1 - v0\n const spec = assemblyPart(part.assembly!, {\n id: part.id, width: alongU ? u1 - u0 : v1 - v0, height: part.y1 - part.y0, position: [(u0 + u1) / 2, (part.y0 + part.y1) / 2, (v0 + v1) / 2], ...(alongU ? {} : { rotation: [0, Math.PI / 2, 0] }),\n structure: capacity === undefined ? { role: CONTRACT_ROLE[part.role] } : { role: CONTRACT_ROLE[part.role], capacity }, extra: { mass: Math.max(0.1, part.mass || 1) },\n })\n if (part.unit) {\n delete spec.units\n delete spec.breach\n }\n return spec\n}\n\nconst partSpecOf = (part: StructurePart, capacity: number | undefined, detailed: boolean): PartSpec => (detailed && part.assembly ? assemblySpec(part, capacity) : boxSpec(part, capacity))\n\n/**\n * The structure as a `DestructibleSpec` in the space of the house (x = u, y = height, z = v; the ground is y = 0), one box per part and a terrain slab\n * that anchors it. Capacities are sized from the loads at rest, as a designer would: a house stands whole, holds the loss of one pillar or bearing wall\n * and falls with two.\n */\nexport function toDestructibleSpec(structure: Structure, options: DestructibleSpecOptions = {}): DestructibleSpec {\n const { safety = 0.65, redundancy = 0.97, safetyOthers = 0.45 } = options\n const kept = structure.parts.filter((part) => !options.filter || options.filter(part))\n const portico = options.portico ?? (options.wallDetail !== 'coarse' && structure.framed)\n const roled = portico ? kept.map((part): StructurePart => (part.role === 'wall' ? { ...part, role: 'partition' } : part)) : kept\n const ids = new Set(roled.map((part) => part.id))\n const filtered = structure.supports.filter((support) => !options.filter || (ids.has(support.part) && (support.on === GROUND || ids.has(support.on))))\n const detail = options.wallDetail ?? 'panels'\n const resolved = resolveSlabPanels(options.slabPanels ?? true)\n const slabOptions = resolved && structure.levels.length <= resolved.maxStoreys ? resolved : undefined\n const slabbed = slabOptions ? applySlabPanels({ parts: roled, supports: filtered }, structure, slabOptions) : { parts: roled, supports: filtered }\n const walled = applyPanels(slabbed, structure, detail, slabOptions && structure.construction.frame.rebar ? (span) => beamDepthFor(span, slabOptions) : undefined)\n const panels = slabOptions && detail !== 'coarse' ? deepenBondBeams(walled, structure, slabOptions) : walled\n const sizing = { safety, redundancy, safetyOthers }\n const sized = { ...panels, capacities: options.sized === false ? new Map<string, number>() : sizeCapacities(panels.parts, panels.supports, sizing) }\n const { parts, supports, capacities } = detail === 'units' ? applyUnits(sized, structure) : sized\n const specs = parts.map((part) => partSpecOf(part, capacities.get(part.id), detail !== 'coarse'))\n const margin = options.terrainMargin ?? TERRAIN_MARGIN\n const x0 = Math.min(...parts.map((part) => part.aabb[0]))\n const z0 = Math.min(...parts.map((part) => part.aabb[1]))\n const x1 = Math.max(...parts.map((part) => part.aabb[2]))\n const z1 = Math.max(...parts.map((part) => part.aabb[3]))\n if (parts.length) specs.push({ id: GROUND, material: 'concrete', shape: { kind: 'box', size: [x1 - x0 + margin, TERRAIN_THICKNESS, z1 - z0 + margin] }, position: [(x0 + x1) / 2, -TERRAIN_THICKNESS / 2, (z0 + z1) / 2], hp: 1e12, structure: { role: 'foundation' }, anchored: true, tags: ['terrain'] })\n const present = new Set([...parts.map((part) => part.id), GROUND])\n // in a frame (`portico`) the walls only close: a beam rests on the pillars, not on the wall under it, and is sized for the span between pillars (a wall that is lost does not bring the beam down)\n const infill = new Set(portico && slabOptions ? kept.filter((part) => part.role === 'wall').map((part) => part.id) : [])\n const beams = new Set(parts.filter((part) => part.role === 'beam' && (part.beamKind === 'bond_beam' || part.slab !== undefined)).map((part) => part.id))\n const joints: JointSpec[] = supports.filter((s) => present.has(s.part) && present.has(s.on)).map((s) => ({ id: `${s.part}~${s.on}`, a: s.part, b: s.on, kind: s.joint, bears: s.bears === false || (beams.has(s.part) && infill.has(s.on)) ? false : 'a_on_b' }))\n const spec: DestructibleSpec = { name: options.name ?? 'house', parts: specs, joints, tags: ['structure', 'house'] }\n return onSoil(withRebar(spec, structure, options, portico, slabOptions !== undefined), structure, options)\n}\n\nfunction withRebar(spec: DestructibleSpec, structure: Structure, options: DestructibleSpecOptions, portico: boolean, panelled: boolean): DestructibleSpec {\n const { redundancy = 0.97, safetyOthers = 0.45 } = options\n const rebar = options.rebar ?? panelled\n if (!rebar || !structure.construction.frame.rebar) return spec\n const ratios = { ...REBAR_RATIOS, ...(rebar === true ? {} : rebar) }\n for (const part of spec.parts) {\n const role = part.structure?.role\n if (!role || !(role in ratios) || part.structure!.rebar || !MATERIALS.find((m) => m.id === part.material)?.strength?.tensileMPa) continue\n part.structure = { ...part.structure!, rebar: { ratio: ratios[role as keyof typeof ratios] } }\n }\n if (options.sized === false) return spec\n return sizeRebar(spec, { safety: safetyOthers, redundancy, redundancyRoles: portico ? ['column'] : ['column', 'wall'] })\n}\n\n/** Puts the house on its soil: the raft (with its piles) in place of the terrain, or the terrain with a footing under each part on it. */\nfunction onSoil(spec: DestructibleSpec, structure: Structure, options: DestructibleSpecOptions): DestructibleSpec {\n if (options.soil === undefined) return spec\n const out: DestructibleSpec = { ...spec, soil: options.soil }\n const type = options.foundation ?? structure.construction.foundation.type\n const ground = out.parts.findIndex((p) => p.id === GROUND)\n if (ground < 0 || (!RAFT_FOUNDATIONS.has(type) && !options.piles)) return out\n const house = out.parts.filter((p) => p.id !== GROUND)\n // the raft is under what stands on the ground (walls, pillars, the ground floor), not under the eaves\n const onGround = new Set((out.joints ?? []).filter((j) => j.b === GROUND).map((j) => j.a))\n const footprint = house.filter((p) => onGround.has(p.id))\n const half = (p: PartSpec, k: number) => (p.shape.kind === 'box' ? p.shape.size[k] / 2 : p.shape.kind === 'cylinder' ? (k === 1 ? p.shape.height / 2 : p.shape.radius) : p.shape.radius)\n const under = footprint.length ? footprint : house\n const x0 = Math.min(...under.map((p) => p.position[0] - half(p, 0))) - RAFT_MARGIN, x1 = Math.max(...under.map((p) => p.position[0] + half(p, 0))) + RAFT_MARGIN\n const z0 = Math.min(...under.map((p) => p.position[2] - half(p, 2))) - RAFT_MARGIN, z1 = Math.max(...under.map((p) => p.position[2] + half(p, 2))) + RAFT_MARGIN\n const raft: PartSpec = {\n id: GROUND, material: 'concrete', shape: { kind: 'box', size: [x1 - x0, RAFT_THICKNESS, z1 - z0] }, position: [(x0 + x1) / 2, -RAFT_THICKNESS / 2, (z0 + z1) / 2],\n structure: { role: 'foundation' }, tags: ['raft'],\n }\n if (options.piles) {\n const given = options.piles === true ? {} : options.piles\n const count = given.count ?? Math.max(4, Math.ceil(((x1 - x0) * (z1 - z0)) / PILE_AREA))\n const diameter = given.diameter ?? 0.4\n const method = given.method ?? 'bored'\n const materials = new Map(MATERIALS.map((m) => [m.id, m]))\n const mass = [...house, raft].reduce((sum, p) => sum + (p.mass ?? partMass(p, materials.get(p.material)!)), 0)\n const soils = new Map(SOILS.map((d) => [d.id, d]))\n for (const d of options.soils ?? []) soils.set(d.id, d)\n const length = given.length ?? pileLength(profileOf(options.soil), { load: (mass * GRAVITY) / count, diameter, top: RAFT_THICKNESS, method, soils })\n raft.structure = { role: 'foundation', pile: { length, diameter, count, method } }\n }\n out.parts = out.parts.map((p, i) => (i === ground ? raft : p))\n return out\n}\n","import type { DestructibleSpec } from '@adatechnology/game-contracts'\nimport { assemblyDepth, assemblyPart, getAssembly } from '@adatechnology/game-destruction'\n\nimport { GROUND } from './types'\nimport { constructionOfSystem } from './presets'\nimport { CONSTRUCTION_SYSTEMS } from './registry'\nimport { toDestructibleSpec } from './to-destructible-spec'\nimport type { Opening, StructureSource, WallDetail } from './types'\n\nexport interface WallSpecimenOptions {\n /** Wall assembly of `game-destruction` (`brick_wall_plastered`, `concrete_block_wall`, `reinforced_concrete`, `drywall`, `wood_frame_wall`, `log_wall`, `sheet_metal_shack`...). */\n assembly: string\n /** Width and height in metres (the test area uses 2.4 x 2.1). */\n w: number\n h: number\n opening?: 'door' | 'window' | null\n /** Default `panels`: piers, lintel with its 0.2 m bearing, sill, plaster and rebar; `units` also lays the bricks, blocks or concrete panels one by one. */\n detail?: WallDetail\n}\n\nconst SYSTEM_OF_ASSEMBLY: Record<string, string> = { log_wall: 'log', wood_frame_wall: 'wood_frame', sheet_metal_shack: 'improvised' }\nconst DOOR_WIDTH = 0.9\nconst WINDOW_WIDTH = 1.0\n\nfunction openingOf(kind: 'door' | 'window', height: number): Opening {\n return kind === 'door'\n ? { id: 'door', kind, wall: 'wall_specimen', from: -DOOR_WIDTH / 2, to: DOOR_WIDTH / 2, y0: 0, y1: height * 0.8 }\n : { id: 'window', kind, wall: 'wall_specimen', from: -WINDOW_WIDTH / 2, to: WINDOW_WIDTH / 2, y0: height * 0.33, y1: height * 0.8 }\n}\n\n/**\n * A test wall as its assembly builds it, standing on a plinth: in `panels` the piers beside the opening, the lintel over it (reinforced concrete bearing 0.2 m on\n * the piers; a header in timber walls), the sill under a window and the wall above; with the plaster coat and the rebar of the assembly. The mass is the\n * assembly's for the whole w x h, whatever the detail.\n */\nexport function buildWallSpecimen(options: WallSpecimenOptions): DestructibleSpec {\n const { assembly, w, h, opening = null, detail = 'panels' } = options\n const def = getAssembly(assembly)\n if (!def) throw new Error(`unknown assembly \"${assembly}\"`)\n const system = SYSTEM_OF_ASSEMBLY[assembly] ?? 'masonry'\n const depth = assemblyDepth(def)\n const mass = assemblyPart(assembly, { id: 'wall_specimen', width: w, height: h, position: [0, h / 2, 0] }).mass ?? 1\n const construction = constructionOfSystem(system, { facade: {}, floors: [], rooms: [], walls: [], doors: [], items: [], w, d: depth } as StructureSource)!\n const joint = CONSTRUCTION_SYSTEMS.get(system)!.joints.wall\n const structure = {\n parts: [{ id: 'wall_specimen', role: 'wall' as const, material: def.core.material, aabb: [-w / 2, -depth / 2, w / 2, depth / 2] as [number, number, number, number], y0: 0, y1: h, floor: 0, mass, assembly }],\n supports: [{ part: 'wall_specimen', on: GROUND, joint }],\n openings: opening ? [openingOf(opening, h)] : [],\n levels: [0], elevation: 0, construction, framed: false,\n roof: { shape: 'slab' as const, covering: '', material: '', pitch: 0, bearingFloor: 0, panes: [], trusses: 0 },\n }\n return toDestructibleSpec(structure, { wallDetail: detail, sized: false, terrainMargin: 0.6, name: `wall_${assembly}` })\n}\n","import type { DestructibleSpec, JointSpec, PartSpec, Vec3, WindExposure } from '@adatechnology/game-contracts'\nimport { MATERIALS, buildFrame, partMass, sizeStructure } from '@adatechnology/game-destruction'\nimport type { FrameOptions, SizeStructureOptions, WindOptions } from '@adatechnology/game-destruction'\n\n/**\n * Building systems of a multi-storey building, as parts added to a frame spec: the rigid concrete core (shear-wall tube with the stairs and the\n * elevator shafts inside), the glass curtain wall hung from the slab edges, the flat roof (screed sloped to the drains and a waterproofing\n * membrane) and the mechanical floor under it (elevator machines, the water tank, chillers). Every number is an option with a real default; see the\n * design T10-estrutura-real.md §9.\n */\n\n/** The frame the systems are added to, in metres: what `buildFrame` was given. */\nexport interface TowerGeometry {\n floors: number\n /** Clear height of a storey (`buildFrame` `height`). */\n height: number\n /** Slab thickness. */\n slab: number\n spanX: number\n spanZ: number\n columnSize: number\n /** Columns along x and z (`buildFrame` `columnsX`, `columnsZ`; default 3 and 4, as `TOWER_DEFAULTS`). */\n columnsX?: number\n columnsZ?: number\n /** Depth of the beams (`buildFrame` `beamHeight`; default 0.6 m, as `TOWER_DEFAULTS`). */\n beamHeight?: number\n /** The top slab is a roof (`roof` id) instead of `slab_<floors-1>`. */\n roof: boolean\n}\n\nconst slabId = (g: TowerGeometry, f: number): string => (f === g.floors - 1 && g.roof ? 'roof' : `slab_${f}`)\n/** Bottom of storey `f` (top of the slab under it; storey 0 starts at the ground). */\nconst storeyBase = (g: TowerGeometry, f: number): number => f * (g.height + g.slab)\n/** Half sizes of the slabs (`buildFrame` makes them the span plus a column and 0.1 m each side). */\nconst slabHalf = (g: TowerGeometry): [number, number] => [(g.spanX + g.columnSize + 0.2) / 2, (g.spanZ + g.columnSize + 0.2) / 2]\n\nconst box = (size: Vec3) => ({ kind: 'box' as const, size })\nconst rests = (joints: JointSpec[], a: string, b: string, kind: JointSpec['kind'], bears: JointSpec['bears'] = 'a_on_b') => joints.push({ id: `${a}~${b}`, a, b, kind, bears })\n\n// -------------------------------------------------------------------------------------------------------------------------------------------------\n// Rigid core\n// -------------------------------------------------------------------------------------------------------------------------------------------------\n\nexport interface CoreOptions {\n /** Centre of the core in plan, object-local `[x, z]` (default `[0, 0]`). */\n center?: [number, number]\n /** Thickness of the outer walls of the tube (default 0.35 m: 30 to 60 cm in high-rise cores; at least h/25, NBR 6118 18.5 / EN 1992-1-1 9.6). */\n wallThickness?: number\n /** Thickness of the walls inside it, between the stair and the shafts and between shafts (default 0.2 m). */\n innerThickness?: number\n /** Elevator shafts (default 2), each `shaft` wide along z and `shaftDepth` deep along x. */\n elevators?: number\n shaft?: number\n shaftDepth?: number\n /** Stair compartment: width along x (two flights of 1.2 m side by side) and length along z (default 2.6 x 4.8 m, NBR 9077). */\n stairWidth?: number\n stairLength?: number\n /** Concrete of the walls (default `concrete`). */\n material?: string\n /** Rebar cage of the walls: bars of `diameter` every `spacing` (default 12.5 mm every 0.15 m: about 0.5% of the section, above the 0.2% of EN 1992-1-1 9.6.2). */\n rebar?: { spacing?: number; diameter?: number }\n /** Thickness of the mat foundation under the core when the frame has no raft (default 1.2 m). */\n matThickness?: number\n}\n\nexport const CORE_DEFAULTS = {\n wallThickness: 0.35, innerThickness: 0.2, elevators: 2, shaft: 2.2, shaftDepth: 2.4, stairWidth: 2.6, stairLength: 4.8, material: 'concrete',\n rebar: { spacing: 0.15, diameter: 0.0125 }, matThickness: 1.2,\n} as const\n\n/** Outer size of the core in plan, `[x, z]`, from its options: the stair compartment beside the row of shafts. */\nexport const coreSize = (o: CoreOptions = {}): [number, number] => {\n const c = { ...CORE_DEFAULTS, ...o }\n const shafts = c.elevators * c.shaft + Math.max(0, c.elevators - 1) * c.innerThickness\n return [2 * c.wallThickness + c.stairWidth + c.innerThickness + c.shaftDepth, 2 * c.wallThickness + Math.max(c.stairLength, shafts)]\n}\n\n/**\n * Adds the concrete core: four shear walls per storey forming a tube, the wall between the stair and the shafts and the walls between shafts, each\n * resting on the one below (continuous from the foundation to the roof) with its rebar cage, the slab of each storey resting on the tube, two\n * flights and a landing of stairs per storey inside, and an elevator car parked at the bottom of each shaft. Part ids: `core_<f>_<n|s|e|w|stair|shaft_k>`,\n * `stair_<f>_a|b`, `landing_<f>`, `elevator_<k>`, `core_mat`.\n */\nexport function addCore(spec: DestructibleSpec, g: TowerGeometry, options: CoreOptions = {}): DestructibleSpec {\n const c = { ...CORE_DEFAULTS, ...options, rebar: { ...CORE_DEFAULTS.rebar, ...options.rebar } }\n const [cx, cz] = options.center ?? [0, 0]\n const [W, L] = coreSize(options)\n const t = c.wallThickness, ti = c.innerThickness\n const x0 = cx - W / 2, z0 = cz - L / 2\n const parts: PartSpec[] = [...spec.parts]\n const joints: JointSpec[] = [...(spec.joints ?? [])]\n const reinforcement = { material: 'steel', spacing: c.rebar.spacing, diameter: c.rebar.diameter }\n const raft = parts.find((p) => p.id === 'raft')\n let base = raft?.id\n if (!base) {\n base = 'core_mat'\n parts.push({ id: base, material: c.material, shape: box([W + 1, c.matThickness, L + 1]), position: [cx, -c.matThickness / 2, cz], structure: { role: 'foundation' }, anchored: true })\n }\n const innerX = x0 + t + c.stairWidth + ti / 2\n for (let f = 0; f < g.floors; f++) {\n const yb = storeyBase(g, f), H = g.height\n const wall = (name: string, size: Vec3, pos: [number, number]) => {\n const id = `core_${f}_${name}`\n parts.push({ id, material: c.material, shape: box(size), position: [pos[0], yb + H / 2, pos[1]], structure: { role: 'wall' }, reinforcement, tags: ['core'] })\n rests(joints, id, f === 0 ? base! : `core_${f - 1}_${name}`, 'rebar')\n return id\n }\n const tube = [\n wall('w', [t, H, L], [x0 + t / 2, cz]),\n wall('e', [t, H, L], [x0 + W - t / 2, cz]),\n wall('n', [W - 2 * t, H, t], [cx, z0 + L - t / 2]),\n wall('s', [W - 2 * t, H, t], [cx, z0 + t / 2]),\n ]\n wall('stair', [ti, H, L - 2 * t], [innerX, cz])\n for (let k = 1; k < c.elevators; k++) {\n wall(`shaft_${k}`, [c.shaftDepth, H, ti], [innerX + ti / 2 + c.shaftDepth / 2, z0 + t + k * c.shaft + (k - 1) * ti + ti / 2])\n }\n for (const w of tube) rests(joints, slabId(g, f), w, 'rebar')\n // the stairs: two flights of half the storey each and the landing between them, cast into the walls of the tube\n const rise = (H + g.slab) / 2\n const flightWidth = (c.stairWidth - 0.2) / 2\n const landing = 1.2\n const run = c.stairLength - 2 * landing\n const angle = Math.atan2(rise, run)\n const length = Math.hypot(rise, run)\n const sx = x0 + t\n const landingId = `landing_${f}`\n parts.push({ id: landingId, material: c.material, shape: box([c.stairWidth, 0.15, landing]), position: [sx + c.stairWidth / 2, yb + rise - 0.075, z0 + t + c.stairLength - landing / 2], structure: { role: 'stair' }, tags: ['stair'] })\n rests(joints, landingId, `core_${f}_w`, 'rebar')\n rests(joints, landingId, `core_${f}_stair`, 'rebar')\n const zMid = z0 + t + landing + run / 2\n for (const [k, side] of [['a', 0], ['b', 1]] as const) {\n const id = `stair_${f}_${k}`\n const up = side === 0 ? 1 : -1\n parts.push({\n id, material: c.material, shape: box([flightWidth, 0.15, length]), position: [sx + flightWidth / 2 + side * (flightWidth + 0.2), yb + rise / 2 + side * rise, zMid],\n rotation: [up * angle * -1, 0, 0], structure: { role: 'stair' }, tags: ['stair'],\n })\n rests(joints, id, landingId, 'rebar')\n rests(joints, id, side === 0 ? `core_${f}_w` : `core_${f}_stair`, 'rebar')\n }\n }\n // a car at the bottom of each shaft (it hangs from its machine on the mechanical floor; parked, it rests on the pit)\n for (let k = 0; k < c.elevators; k++) {\n const id = `elevator_${k}`\n parts.push({\n id, material: 'steel', shape: box([c.shaftDepth - 0.6, 2.3, c.shaft - 0.6]), position: [innerX + ti / 2 + c.shaftDepth / 2, 1.15 + 0.05, z0 + t + k * (c.shaft + ti) + c.shaft / 2],\n fill: 0.03, mass: 1500, tags: ['elevator_car'],\n })\n rests(joints, id, base, 'resting', false)\n }\n return { ...spec, parts, joints }\n}\n\n// -------------------------------------------------------------------------------------------------------------------------------------------------\n// Curtain wall\n// -------------------------------------------------------------------------------------------------------------------------------------------------\n\nexport interface CurtainWallOptions {\n /** Width of a panel (default 1.5 m). */\n panel?: number\n /** Glass of the panels (default `glass`: annealed or laminated glass that breaks in large shards; `tempered_glass` breaks in small cubes). */\n material?: string\n /** Glass thickness in metres: the two panes of an insulated unit (default 0.012, 6 + 6 mm). */\n thickness?: number\n /** Mass of the aluminium frame per m² of facade (default 10 kg/m²). */\n frameKgM2?: number\n /** Size of the pieces a broken panel falls in (default 0.6 m: a laminated pane breaks in large shards held by the interlayer). */\n shard?: number\n /** Gap from the slab edge to the glass (default 0.1 m). */\n offset?: number\n /** Storeys without glass (the mechanical floor has louvres): default none. */\n skip?: (floor: number) => boolean\n}\n\nexport const CURTAIN_DEFAULTS = { panel: 1.5, material: 'glass', thickness: 0.012, frameKgM2: 10, shard: 0.6, offset: 0.1 } as const\n\n/**\n * Adds a glass curtain wall around the frame: one panel per bay and storey, floor to floor, hung from the edge of the slab above it (`bolt`, carries\n * nothing: role none). In a blast the panels shatter into `shard`-sized pieces (`units`) that fall from the facade; a panel whose slab falls goes\n * with it. Part ids: `glass_<f>_<side>_<k>` with side `n`, `s`, `e`, `w`.\n */\nexport function addCurtainWall(spec: DestructibleSpec, g: TowerGeometry, options: CurtainWallOptions = {}): DestructibleSpec {\n const c = { ...CURTAIN_DEFAULTS, ...options }\n const parts: PartSpec[] = [...spec.parts]\n const joints: JointSpec[] = [...(spec.joints ?? [])]\n const [hx, hz] = slabHalf(g)\n const h = g.height + g.slab\n const sides = [\n { name: 'n', along: 0, length: 2 * hx, fixed: hz + c.offset, axis: 2 },\n { name: 's', along: 0, length: 2 * hx, fixed: -hz - c.offset, axis: 2 },\n { name: 'e', along: 2, length: 2 * hz, fixed: hx + c.offset, axis: 0 },\n { name: 'w', along: 2, length: 2 * hz, fixed: -hx - c.offset, axis: 0 },\n ]\n for (let f = 0; f < g.floors; f++) {\n if (c.skip?.(f)) continue\n const yb = storeyBase(g, f)\n for (const s of sides) {\n const n = Math.max(1, Math.round(s.length / c.panel))\n const w = s.length / n\n for (let k = 0; k < n; k++) {\n const id = `glass_${f}_${s.name}_${k}`\n const at = -s.length / 2 + (k + 0.5) * w\n const size: Vec3 = s.axis === 2 ? [w - 0.01, h - 0.01, c.thickness] : [c.thickness, h - 0.01, w - 0.01]\n const position: Vec3 = s.axis === 2 ? [at, yb + h / 2, s.fixed] : [s.fixed, yb + h / 2, at]\n parts.push({\n id, material: c.material, shape: box(size), position, mass: (2500 * c.thickness + c.frameKgM2) * w * h, thickness: c.thickness,\n units: { size: [c.shard, c.shard, c.thickness], bond: 'stack', mortar: 'plastic' }, tags: ['curtain_wall', 'glass'],\n })\n rests(joints, id, slabId(g, f), 'bolt', false)\n }\n }\n }\n return { ...spec, parts, joints }\n}\n\n// -------------------------------------------------------------------------------------------------------------------------------------------------\n// Punched facade\n// -------------------------------------------------------------------------------------------------------------------------------------------------\n\nexport interface PunchedFacadeOptions {\n /** Material of the infill wall (default `brick`: a masonry or block wall between the columns, as the residential towers are built). */\n material?: string\n /** Thickness of the wall in metres (default 0.2). */\n thickness?: number\n /** Width of the window as a share of the clear bay (default 0.6). */\n window?: number\n /** Sill and head of the window above the floor of the storey (default 0.9 and 2.4 m; the head is kept under the beam). */\n sill?: number\n head?: number\n /** Glass of the window and its thickness (default `glass`, 12 mm: an insulated unit). */\n glass?: string\n glassThickness?: number\n /** Storeys without infill (louvres on a mechanical floor): default none. */\n skip?: (floor: number) => boolean\n}\n\nexport const PUNCHED_DEFAULTS = { material: 'brick', thickness: 0.2, window: 0.6, sill: 0.9, head: 2.4, glass: 'glass', glassThickness: 0.012 } as const\n\n/**\n * Closes the perimeter bays of every storey with an infill wall that has a window in it (the alternative to the curtain wall): a sill wall under the\n * window, a wall over it and a pier at each side, all resting on the columns of the bay (role partition: they load the columns and carry nothing, as the\n * walls of `buildFrame`), and the glass in the opening, which rests on the sill and carries nothing. Part ids: `infill_<f>_<side>_<k>_sill|head|pl|pr`,\n * `glass_<f>_<side>_<k>` with side `n`, `s`, `e`, `w` (the same ids as the curtain wall, so the two exclude each other).\n */\nexport function addPunchedFacade(spec: DestructibleSpec, g: TowerGeometry, options: PunchedFacadeOptions = {}): DestructibleSpec {\n const c = { ...PUNCHED_DEFAULTS, ...options }\n const parts: PartSpec[] = [...spec.parts]\n const joints: JointSpec[] = [...(spec.joints ?? [])]\n const nx = Math.max(2, g.columnsX ?? 3), nz = Math.max(2, g.columnsZ ?? 4)\n const xs = Array.from({ length: nx }, (_, i) => -g.spanX / 2 + (i * g.spanX) / (nx - 1))\n const zs = Array.from({ length: nz }, (_, j) => -g.spanZ / 2 + (j * g.spanZ) / (nz - 1))\n const beamUnder = g.beamHeight ?? TOWER_DEFAULTS.beamHeight\n for (let f = 0; f < g.floors; f++) {\n if (c.skip?.(f)) continue\n const yb = storeyBase(g, f)\n const room = g.height - beamUnder\n const head = Math.min(c.head, room - 0.3), sill = Math.min(c.sill, head - 0.6)\n const wall = (id: string, size: Vec3, position: Vec3, on: string[]) => {\n parts.push({ id, material: c.material, shape: box(size), position, structure: { role: 'partition' }, tags: ['infill'] })\n for (const o of on) rests(joints, id, o, 'mortar')\n }\n const bay = (side: string, k: number, along: 0 | 2, centre: number, fixed: number, length: number, c1: string, c2: string) => {\n const clear = length - g.columnSize\n const win = clear * c.window\n const pier = (clear - win) / 2\n const at = (u: number): Vec3 => (along === 0 ? [u, 0, fixed] : [fixed, 0, u])\n const size = (u: number, h: number): Vec3 => (along === 0 ? [u, h, c.thickness] : [c.thickness, h, u])\n const put = (name: string, u: number, h: number, y: number, centreU: number, on: string[]) => {\n const p = at(centreU)\n wall(`infill_${f}_${side}_${k}_${name}`, size(u, h), [p[0], y, p[2]], on)\n }\n const id = (name: string) => `infill_${f}_${side}_${k}_${name}`\n put('sill', clear, sill, yb + sill / 2, centre, [c1, c2])\n put('pl', pier, head - sill, yb + sill + (head - sill) / 2, centre - clear / 2 + pier / 2, [c1, id('sill')])\n put('pr', pier, head - sill, yb + sill + (head - sill) / 2, centre + clear / 2 - pier / 2, [c2, id('sill')])\n put('head', clear, room - head, yb + head + (room - head) / 2, centre, [c1, c2])\n const gp = at(centre)\n const gid = `glass_${f}_${side}_${k}`\n parts.push({\n id: gid, material: c.glass, shape: box(size(win - 0.01, head - sill)), position: [gp[0], yb + sill + (head - sill) / 2, gp[2]], thickness: c.glassThickness,\n units: { size: [0.6, 0.6, c.glassThickness], bond: 'stack', mortar: 'plastic' }, tags: ['window', 'glass'],\n })\n rests(joints, gid, id('sill'), 'glue', false)\n }\n for (const [side, j] of [['s', 0], ['n', nz - 1]] as const) {\n for (let i = 0; i < nx - 1; i++) bay(side, i, 0, (xs[i] + xs[i + 1]) / 2, zs[j], xs[i + 1] - xs[i], `column_${f}_${i}_${j}`, `column_${f}_${i + 1}_${j}`)\n }\n for (const [side, i] of [['w', 0], ['e', nx - 1]] as const) {\n for (let j = 0; j < nz - 1; j++) bay(side, j, 2, (zs[j] + zs[j + 1]) / 2, xs[i], zs[j + 1] - zs[j], `column_${f}_${i}_${j}`, `column_${f}_${i}_${j + 1}`)\n }\n }\n return { ...spec, parts, joints }\n}\n\n// -------------------------------------------------------------------------------------------------------------------------------------------------\n// Flat roof\n// -------------------------------------------------------------------------------------------------------------------------------------------------\n\nexport interface FlatRoofOptions {\n /** Slope of the screed to the drains (default 0.01: 1%, the minimum of NBR 9575 for flat roofs). */\n slope?: number\n /** Screed thickness at the drains (default 0.02 m). */\n screedMin?: number\n /** Density of the screed (default 2000 kg/m³, cement and sand). */\n screedDensity?: number\n /** Membrane material and thickness (default `rubber` 1.5 mm: an EPDM sheet). */\n membrane?: string\n membraneThickness?: number\n /** Drains (default one per 150 m² of roof, at least 2, on the long centre line). */\n drains?: number\n /** Water standing on the membrane in metres (default 0.005: 5 mm of a storm on its way to the drains); set it in game with `setLiters`. */\n water?: number\n}\n\nexport const FLAT_ROOF_DEFAULTS = { slope: 0.01, screedMin: 0.02, screedDensity: 2000, membrane: 'rubber', membraneThickness: 0.0015, water: 0.005, areaPerDrain: 150 } as const\n\n/**\n * Turns the top slab into a flat roof: a screed sloped to the drains (its weight from the mean thickness `screedMin + slope * run / 2`), the\n * waterproofing membrane over it with the rain water on it (`contains` water, running down through a puncture: `outflow` [0, -1, 0], so a shot through\n * the membrane is a `leak` into the floor below) and the drains (tag `drain`). Screed and membrane load the roof slab (role partition: carried,\n * carry nothing). Part ids: `roof_screed`, `roof_membrane`, `roof_drain_<k>`.\n */\nexport function addFlatRoof(spec: DestructibleSpec, g: TowerGeometry, options: FlatRoofOptions = {}): DestructibleSpec {\n const c = { ...FLAT_ROOF_DEFAULTS, ...options }\n const parts: PartSpec[] = [...spec.parts]\n const joints: JointSpec[] = [...(spec.joints ?? [])]\n const top = slabId(g, g.floors - 1)\n const slab = parts.find((p) => p.id === top)\n if (!slab || slab.shape.kind !== 'box') return spec\n const [sx, sy, sz] = slab.shape.size\n const area = sx * sz\n const longX = sx >= sz\n const count = c.drains ?? Math.max(2, Math.ceil(area / c.areaPerDrain))\n const long = longX ? sx : sz\n const spacing = long / count\n // the farthest point from a drain: half the spacing along the line and half the width across it\n const run = Math.hypot(spacing / 2, (longX ? sz : sx) / 2)\n const screed = c.screedMin + (c.slope * run) / 2\n const y = slab.position[1] + sy / 2\n parts.push({\n id: 'roof_screed', material: 'concrete', shape: box([sx, screed, sz]), position: [slab.position[0], y + screed / 2, slab.position[2]], mass: c.screedDensity * screed * area,\n structure: { role: 'partition' }, tags: ['roof_screed'],\n })\n rests(joints, 'roof_screed', top, 'mortar')\n const my = y + screed + c.membraneThickness / 2\n parts.push({\n id: 'roof_membrane', material: c.membrane, shape: box([sx, c.membraneThickness, sz]), position: [slab.position[0], my, slab.position[2]], thickness: c.membraneThickness,\n structure: { role: 'partition' }, contains: { fluid: 'water', liters: c.water * area * 1000, outflow: [0, -1, 0] }, tags: ['roof_membrane', 'waterproofing'],\n })\n rests(joints, 'roof_membrane', top, 'glue')\n for (let k = 0; k < count; k++) {\n const at = -long / 2 + (k + 0.5) * spacing\n const id = `roof_drain_${k}`\n parts.push({\n id, material: 'plastic', shape: { kind: 'cylinder', radius: 0.05, height: 0.1 }, position: longX ? [slab.position[0] + at, my, slab.position[2]] : [slab.position[0], my, slab.position[2] + at],\n fill: 0.2, tags: ['drain'],\n })\n rests(joints, id, top, 'glue', false)\n }\n return { ...spec, parts, joints }\n}\n\n// -------------------------------------------------------------------------------------------------------------------------------------------------\n// Mechanical floor\n// -------------------------------------------------------------------------------------------------------------------------------------------------\n\nexport interface MechanicalFloorOptions {\n /** Elevator machines: one per elevator, over its shaft (default from the core; 2). */\n elevators?: number\n /** Where the shafts are, object-local `[x, z]` of each (default from the core layout). */\n shafts?: Array<[number, number]>\n /** Mass of a traction machine with its frame (default 2500 kg) and of what hangs from it: car, counterweight, rated load (default 1500 + 2000 + 1000 kg). */\n machineMass?: number\n suspendedMass?: number\n /** Water tank in litres (default: `occupants` per storey x 200 L a day x 40% stored up high, NBR 5626, plus a fire reserve of 6000 L, NBR 13714). */\n waterLiters?: number\n occupants?: number\n fireReserve?: number\n /** Chillers on the floor (default 2 of 3500 kg). */\n chillers?: number\n chillerMass?: number\n /** Material and wall thickness of the tank (default `plastic` 10 mm: a fibreglass or polyethylene reservoir). */\n tankMaterial?: string\n tankWall?: number\n /** Where the tank goes, `[x, z]` (default the middle of the bay at -x, away from the core). */\n tankAt?: [number, number]\n /**\n * Storey the equipment stands on (default the top one, under the roof). On any other storey the part ids end in `_<floor>` (`water_tank_20`,\n * `chiller_0_20`), so a tower can carry a mechanical floor every few storeys (design T10 §11).\n */\n floor?: number\n}\n\nexport const MECHANICAL_DEFAULTS = { tankMaterial: 'plastic', tankWall: 0.01, machineMass: 2500, suspendedMass: 4500, occupants: 16, litersPerPerson: 200, storedFraction: 0.4, fireReserve: 6000, chillers: 2, chillerMass: 3500 } as const\n\n/** Litres of the water tank of a building of `storeys` occupied storeys (NBR 5626 consumption, the fire reserve of NBR 13714). */\nexport const towerWater = (storeys: number, o: Pick<MechanicalFloorOptions, 'occupants' | 'fireReserve'> = {}): number =>\n Math.round((o.occupants ?? MECHANICAL_DEFAULTS.occupants) * MECHANICAL_DEFAULTS.litersPerPerson * MECHANICAL_DEFAULTS.storedFraction * storeys + (o.fireReserve ?? MECHANICAL_DEFAULTS.fireReserve))\n\n/**\n * Makes the top storey the mechanical floor: the elevator machines over the shafts, the water tank (with its water: `contains`, a shot makes it leak)\n * and the chillers, on the slab under the roof (role partition: their weight goes into the structure). Part ids: `machine_<k>`, `water_tank`,\n * `chiller_<k>`.\n */\nexport function addMechanicalFloor(spec: DestructibleSpec, g: TowerGeometry, options: MechanicalFloorOptions = {}): DestructibleSpec {\n const c = { ...MECHANICAL_DEFAULTS, ...options }\n if (g.floors < 2) return spec\n const level = options.floor ?? g.floors - 1\n if (level < 1 || level > g.floors - 1) return spec\n const sfx = level === g.floors - 1 ? '' : `_${level}`\n const parts: PartSpec[] = [...spec.parts]\n const joints: JointSpec[] = [...(spec.joints ?? [])]\n const floor = `slab_${level - 1}`\n const y = storeyBase(g, level)\n const shafts = options.shafts ?? []\n const put = (id: string, material: string, size: Vec3, at: [number, number], mass: number, extra: Partial<PartSpec> = {}) => {\n parts.push({ id: id + sfx, material, shape: box(size), position: [at[0], y + size[1] / 2, at[1]], mass, fill: 0.2, structure: { role: 'partition' }, tags: ['mechanical'], ...extra })\n rests(joints, id + sfx, floor, 'bolt')\n }\n shafts.forEach((at, k) => put(`machine_${k}`, 'steel', [1.2, 1.0, 0.8], at, c.machineMass + c.suspendedMass, { tags: ['mechanical', 'elevator_machine'] }))\n const liters = options.waterLiters ?? towerWater(level, options)\n const depth = 2\n const side = Math.sqrt(liters / 1000 / depth)\n const [hx] = slabHalf(g)\n const tankAt = options.tankAt ?? [-hx / 2, 0]\n const shell = 4 * side * depth + 2 * side * side\n put('water_tank', c.tankMaterial, [side, depth, side], tankAt, liters + 1100 * c.tankWall * shell, {\n fill: (shell * c.tankWall) / (side * side * depth), thickness: c.tankWall, contains: { fluid: 'water', liters }, tags: ['mechanical', 'water_tank'],\n })\n for (let k = 0; k < c.chillers; k++) put(`chiller_${k}`, 'steel', [3, 2, 1.5], [-hx + 2 + k * 3.5, -(slabHalf(g)[1] - 2)], c.chillerMass, { tags: ['mechanical', 'chiller'] })\n return { ...spec, parts, joints }\n}\n\n// -------------------------------------------------------------------------------------------------------------------------------------------------\n// Tuned mass damper\n// -------------------------------------------------------------------------------------------------------------------------------------------------\n\nexport interface DamperOptions {\n /** Mass of the damper in kg (default: `ratio` of the modal mass of the building, estimated as `modalShare` of its mass). */\n mass?: number\n /** Mass ratio, damper over the modal mass of the building (default 0.01: 0.5 to 2% is the usual range). */\n ratio?: number\n /** Share of the building's mass that is its modal mass in the first mode, tip at 1 (default 0.25, a uniform cantilever). */\n modalShare?: number\n /** Frequency in Hz and damping ratio of the damper (default: tuned by the world to the building, `wind.tuning`). */\n frequency?: number\n damping?: number\n /** Where it stands on the mechanical floor, object-local `[x, z]` (default on the beam end beside the column nearest to 35% of the depth at +z, clear of the machines: its weight goes straight to the beam and the column). */\n at?: [number, number]\n /** Material of the mass (default `steel`; the real ones are steel or lead-filled blocks and concrete). */\n material?: string\n /** Tallest the block may be, metres (default 2.5: it stands inside the mechanical floor). */\n maxHeight?: number\n}\n\nexport const DAMPER_DEFAULTS = { ratio: 0.01, modalShare: 0.25, material: 'steel', maxHeight: 2.5 } as const\n\n/** Mass in kg of a damper for a structure: `ratio` of `modalShare` of the mass of everything above the foundations (curtain wall, roof and equipment included). */\nexport const damperMass = (spec: DestructibleSpec, o: Pick<DamperOptions, 'ratio' | 'modalShare'> = {}): number => {\n const byId = new Map(MATERIALS.map((m) => [m.id, m]))\n let total = 0\n for (const p of spec.parts) {\n const m = byId.get(p.material)\n if (!m || p.structure?.role === 'foundation' || p.damper) continue\n total += partMass(p, m)\n }\n return total * (o.modalShare ?? DAMPER_DEFAULTS.modalShare) * (o.ratio ?? DAMPER_DEFAULTS.ratio)\n}\n\n/**\n * Adds a tuned mass damper to the mechanical floor: a block of `material` on the slab under the roof (role partition: its mass loads the slab and\n * goes down to the core and the columns like the machines), with `PartSpec.damper` so the world tunes it to the building and moves it against the\n * sway (Den Hartog). Part id: `damper`.\n */\nexport function addTunedMassDamper(spec: DestructibleSpec, g: TowerGeometry, options: DamperOptions = {}): DestructibleSpec {\n const c = { ...DAMPER_DEFAULTS, ...options }\n if (g.floors < 2) return spec\n const mat = MATERIALS.find((m) => m.id === c.material)\n if (!mat) throw new Error(`unknown material \"${c.material}\" for the damper`)\n const mass = options.mass ?? damperMass(spec, c)\n const volume = mass / mat.density\n const height = Math.min(c.maxHeight, Math.cbrt(volume))\n const side = Math.sqrt(volume / height)\n const column = (span: number, n: number | undefined, want: number) => {\n const k = Math.max(2, n ?? 0) - 1\n return n === undefined ? want : Math.round((want + span / 2) / (span / k)) * (span / k) - span / 2\n }\n const colZ = column(g.spanZ, g.columnsZ, g.spanZ * 0.35)\n // on the beam end beside the column, so the slab hands its weight straight to the beam, which hands it to the column\n const at = options.at ?? [column(g.spanX, g.columnsX, 0), colZ - Math.sign(colZ || 1) * (g.columnSize / 2 + 0.1)]\n const y = storeyBase(g, g.floors - 1)\n const floor = `slab_${g.floors - 2}`\n const part: PartSpec = {\n id: 'damper', material: c.material, shape: box([side, height, side]), position: [at[0], y + height / 2, at[1]], mass, structure: { role: 'partition' }, tags: ['mechanical', 'tuned_mass_damper'],\n damper: { ...(c.frequency !== undefined ? { frequency: c.frequency } : {}), ...(c.damping !== undefined ? { damping: c.damping } : {}) },\n }\n const joints: JointSpec[] = [...(spec.joints ?? [])]\n rests(joints, part.id, floor, 'bolt')\n return { ...spec, parts: [...spec.parts, part], joints }\n}\n\n// -------------------------------------------------------------------------------------------------------------------------------------------------\n// Tower\n// -------------------------------------------------------------------------------------------------------------------------------------------------\n\nexport interface TowerMechanicalOptions {\n /**\n * Another mechanical floor every this many storeys (design T10 §11): storeys `every`, `2 * every`... below the top one, each with its own\n * relay water tank for the storeys it serves and its chillers, and without glass. Default none: only the top storey.\n */\n every?: number\n}\n\n/** Indices of the intermediate mechanical storeys of a tower of `floors` storeys with one every `every` (none below `every / 2` storeys of the top one). */\nexport const mechanicalStoreys = (floors: number, every?: number): number[] => {\n if (!every || every < 2) return []\n const out: number[] = []\n for (let k = every; k < floors - 1; k += every) if (floors - 1 - k >= every / 2) out.push(k)\n return out\n}\n\nexport interface TowerOptions extends Omit<FrameOptions, 'walls' | 'roof' | 'continuousColumns'> {\n /** The core (default on); `false` for a frame alone. */\n core?: CoreOptions | false\n /** The curtain wall (default on, without glass on the mechanical floor). */\n facade?: CurtainWallOptions | false\n /** A punched facade (infill walls with windows) instead of the curtain wall: turn the curtain wall off (`facade: false`) when you use it. Default off. */\n punched?: PunchedFacadeOptions | false\n /** The flat roof (default on). */\n flatRoof?: FlatRoofOptions | false\n /** The mechanical floor under the roof (default on). */\n mechanical?: (MechanicalFloorOptions & TowerMechanicalOptions) | false\n /** A tuned mass damper on the mechanical floor (default off: `{}` adds one of 1% of the modal mass). */\n damper?: DamperOptions | false\n /**\n * The wind the tower is made for (default none: the tower is sized for its weight only). Its `speed`, `terrain`, `class`... size the walls, columns\n * and core bars for the wind (`sizeStructure({ wind })`), and the fields of `WindExposure` (terrain, class, topography, statistical, drag, damping)\n * go into `DestructibleSpec.wind`, where the building stands. The world still needs its own `wind` for the wind to blow.\n */\n wind?: WindOptions | false\n /** Size the structure (`sizeStructure`, default `{}`); `false` keeps the material capacities. */\n sizing?: SizeStructureOptions | false\n}\n\n/** The fields of the wind options that describe the place and the shape of one building (`DestructibleSpec.wind`). */\nexport const windExposureOf = (w: WindOptions): WindExposure => {\n const out: WindExposure = {}\n if (w.terrain !== undefined) out.terrain = w.terrain\n if (w.class !== undefined) out.class = w.class\n if (w.topography !== undefined) out.topography = w.topography\n if (w.statistical !== undefined) out.statistical = w.statistical\n if (w.drag !== undefined) out.drag = w.drag\n if (w.damping !== undefined) out.damping = w.damping\n return out\n}\n\n/** Defaults of the frame of a tower: 16 x 24 m on a 8 m grid, 12 storeys of 3 m, 60 cm columns caged with 20 mm bars, 60 cm beams, continuous columns. */\nexport const TOWER_DEFAULTS = {\n spanX: 16, spanZ: 24, columnsX: 3, columnsZ: 4, floors: 12, height: 3, columnSize: 0.6, beamHeight: 0.6, slabThickness: 0.2,\n columnCage: { material: 'steel', spacing: 0.15, diameter: 0.02 },\n} as const\n\n/**\n * A multi-storey building with real structure: a frame with continuous columns, the concrete core in the bay at +x of the centre, the curtain wall,\n * the flat roof and the mechanical floor, sized as a designer would. Every system can be turned off or configured.\n */\nexport function buildTower(options: TowerOptions = {}): DestructibleSpec {\n const { core, facade, punched, flatRoof, mechanical, damper, wind, sizing, ...frame } = options\n const f = { ...TOWER_DEFAULTS, ...frame, columnCage: { ...TOWER_DEFAULTS.columnCage, ...frame.columnCage } }\n const g: TowerGeometry = { floors: f.floors, height: f.height, slab: f.slabThickness, spanX: f.spanX, spanZ: f.spanZ, columnSize: f.columnSize, columnsX: f.columnsX, columnsZ: f.columnsZ, beamHeight: f.beamHeight, roof: true }\n const { every, ...mech } = mechanical || {}\n const relays = mechanical === false ? [] : mechanicalStoreys(f.floors, every)\n const noGlass = (fl: number) => mechanical !== false && (fl === g.floors - 1 || relays.includes(fl))\n let spec = buildFrame({ roofThickness: f.slabThickness, ...f, roof: true, continuousColumns: true })\n spec = { ...spec, name: 'tower', tags: ['structure', 'tower'] }\n let shafts: Array<[number, number]> = []\n if (core !== false) {\n const bayX = f.spanX / (Math.max(2, f.columnsX) - 1)\n const center = core?.center ?? [bayX / 2, 0]\n spec = addCore(spec, g, { ...core, center })\n const c = { ...CORE_DEFAULTS, ...core }\n const [W, L] = coreSize(core || {})\n const sx = center[0] - W / 2 + c.wallThickness + c.stairWidth + c.innerThickness + c.shaftDepth / 2\n shafts = Array.from({ length: c.elevators }, (_, k) => [sx, center[1] - L / 2 + c.wallThickness + k * (c.shaft + c.innerThickness) + c.shaft / 2] as [number, number])\n }\n if (facade !== false && !punched) spec = addCurtainWall(spec, g, { skip: noGlass, ...facade })\n if (punched) spec = addPunchedFacade(spec, g, { skip: noGlass, ...punched })\n if (flatRoof !== false) spec = addFlatRoof(spec, g, flatRoof || {})\n if (mechanical !== false) {\n spec = addMechanicalFloor(spec, g, { shafts, ...mech })\n // the intermediate floors hold the plant of the zone below them: no elevator machines (they are on the top floor), a relay tank and the chillers\n for (const floor of relays) spec = addMechanicalFloor(spec, g, { ...mech, shafts: [], floor, waterLiters: mech.waterLiters ?? towerWater(every ?? floor, mech) })\n }\n if (damper) spec = addTunedMassDamper(spec, g, damper)\n if (wind) {\n const exposure = windExposureOf(wind)\n if (Object.keys(exposure).length) spec = { ...spec, wind: exposure }\n }\n if (sizing === false) return spec\n return sizeStructure(spec, wind && sizing?.wind === undefined ? { ...sizing, wind } : sizing ?? {})\n}\n","import type { DestructibleSpec, PartSpec, PileSpec, SoilProfile } from '@adatechnology/game-contracts'\nimport { GRAVITY, MATERIALS, SOILS, createDestruction, partMass, pileLength, profileOf } from '@adatechnology/game-destruction'\nimport type { SizeStructureOptions, WindOptions } from '@adatechnology/game-destruction'\n\nimport {\n CORE_DEFAULTS, TOWER_DEFAULTS, buildTower, coreSize, mechanicalStoreys,\n} from './tower'\nimport type { CoreOptions, CurtainWallOptions, DamperOptions, FlatRoofOptions, MechanicalFloorOptions, PunchedFacadeOptions, TowerMechanicalOptions, TowerOptions } from './tower'\n\n/**\n * The skyscraper as a recipe: a few numbers (storeys, bay, core ratio, facade, mechanical floors, damper, wind, soil and piles) that `skyscraperLayout`\n * turns into the sizes of a `buildTower` and `buildSkyscraper` turns into a destructible spec on deep piles. The typologies that use it\n * (`game-floorplan-commercial` office tower, `game-floorplan-residential` residential tower) bring their own defaults and the rooms of the plan; the\n * structure is the same one. Design T10-estrutura-real.md §11.\n */\n\n/** Deep foundation of a tower: bored piles under the raft, taken down to firm ground (`pileLength`) by the load each one carries. */\nexport interface PileDesign {\n /** Diameter in metres (default 1.2: the bored piles of high-rise foundations are 0.8 to 2.0 m). */\n diameter?: number\n /** Grid pitch as a multiple of the diameter (default 3.5; the usual minimum is 2.5 to 3). */\n pitch?: number\n method?: PileSpec['method']\n /** Longest pile in metres (default 60); when the load does not fit, the piles are put closer. */\n maxLength?: number\n /** Fixed length and count (default: from the load and the soil). */\n length?: number\n count?: number\n}\n\nexport const PILE_DEFAULTS = { diameter: 1.2, pitch: 3.5, method: 'bored', maxLength: 60 } as const\n\n/**\n * Most storeys a skyscraper has by default (owner decision 2026-10-25): above about 60 the drift at the top passes H/500, because the engine has no outrigger\n * or perimeter tube. A default, not a physical constant: `SkyscraperOptions.range` (or a preset with another `range`) raises it.\n */\nexport const SKYSCRAPER_MAX_STOREYS = 60\n\n/** Numbers that describe one typology of skyscraper. Every one is an option of `skyscraperLayout`. */\nexport interface SkyscraperPreset {\n /** Storeys: the default and the range the typology accepts (the top storey is the mechanical floor). */\n storeys: number\n range: readonly [number, number]\n /** Clear height of a storey in metres (the storey pitch is this plus the slab). */\n height: number\n /** Column spacing in metres along x and z. */\n bay: readonly [number, number]\n /** Bays along x and z (z always odd: the core stands in the middle bay, between two rows of beams). */\n bays: readonly [number, number]\n /** Tallest the tower may be over its narrowest side (default 9: Taipei 101 is 8.3, the Burj Khalifa 8); the bays are widened to keep it. `false` leaves them as given. */\n slenderness: number | false\n /** Target share of the floor plate taken by the concrete core (tube footprint over plate); the number of elevators follows, as far as the bay allows. */\n coreRatio: number\n facade: 'curtain' | 'punched'\n /** Another mechanical floor every this many storeys; `false` none (only the top one). */\n mechanicalEvery: number | false\n /** Total height in metres from which a tuned mass damper is added on the top mechanical floor; `false` never. */\n damperAbove: number | false\n /** The wind the tower is designed for (`buildTower({ wind })`). */\n wind: WindOptions | false\n /** The ground: a soil class id or a profile of layers; `false` leaves the tower on anchored ground. */\n soil: string | SoilProfile | false\n /** Deep piles under the raft (only with `soil`); `false` leaves a shallow raft. */\n piles: PileDesign | false\n /**\n * Sizes the lateral system by height (default on): a tower taller than `above` metres whose design drift at the requested storeys is over the limit of\n * the wind (`driftLimit`, default H/500: NBR 6118 serviceability) gets wider bays, and with them a larger plate and core, in steps of 0.5 m up to `maxBay`\n * until it passes. `false` keeps the layout as given (and then a 60-storey tower is `drift`).\n */\n sizeForWind?: boolean | { above?: number; maxBay?: number }\n /** Dead load per m² of floor besides the slab itself, kg/m² (facade, partitions, finishes, equipment), used to size the columns. */\n superimposed: number\n}\n\n/** Defaults of a generic skyscraper: a 40-storey tower on 12 m bays with a curtain wall, a plant floor every 20 storeys, a damper above 150 m, in a city wind, on piles to the sand under soft clay. */\nexport const SKYSCRAPER_DEFAULTS: SkyscraperPreset = {\n storeys: 40,\n range: [20, SKYSCRAPER_MAX_STOREYS],\n height: 3.6,\n bay: [12, 12],\n bays: [3, 3],\n slenderness: 9,\n coreRatio: 0.08,\n facade: 'curtain',\n mechanicalEvery: 20,\n damperAbove: 150,\n wind: { speed: 40, terrain: 'IV' },\n soil: { layers: [{ soil: 'clay_soft', thickness: 10 }, { soil: 'sand_dense' }] },\n piles: {},\n superimposed: 450,\n}\n\nexport interface SkyscraperOptions extends Partial<Omit<SkyscraperPreset, 'bay' | 'bays'>> {\n bay?: number | readonly [number, number]\n bays?: readonly [number, number]\n /** Sizes derived from the load and the height unless given: columns, beam depth and slab thickness in metres. */\n columnSize?: number\n beamHeight?: number\n slabThickness?: number\n /** The core (`false`: a frame alone); `wallThickness` and `elevators` are derived unless given. */\n core?: CoreOptions | false\n curtain?: CurtainWallOptions\n punchedFacade?: PunchedFacadeOptions\n flatRoof?: FlatRoofOptions | false\n mechanical?: (MechanicalFloorOptions & TowerMechanicalOptions) | false\n damper?: DamperOptions\n sizing?: SizeStructureOptions | false\n}\n\nexport interface SkyscraperLayout {\n storeys: number\n /** Clear height, slab and storey pitch in metres. */\n height: number\n slab: number\n pitch: number\n /** Height from the ground to the roof. */\n total: number\n bay: [number, number]\n /** Distance between the outer column axes. */\n span: [number, number]\n columnsX: number\n columnsZ: number\n columnSize: number\n beamHeight: number\n /** Size of the floor slab, `[x, z]`, centred on the origin of the spec. */\n plate: [number, number]\n core: { center: [number, number]; size: [number, number]; wallThickness: number; elevators: number; stairWidth: number; shaftDepth: number } | null\n /** Footprint of the core over the plate. */\n coreRatio: number\n facade: 'curtain' | 'punched'\n /** Storeys with plant (the intermediate ones and the top one), ascending. */\n mechanical: number[]\n damper: boolean\n /** The options `buildTower` is called with. */\n tower: TowerOptions\n}\n\nconst ceilTo = (v: number, step: number): number => Math.ceil(v / step - 1e-9) * step\nconst round2 = (v: number): number => Math.round(v * 100) / 100\n/** Bearing stress used to size columns: 0.85 fck of a C25 concrete, in kg/m² (the cage steel is the margin), with the 0.65 utilisation of the sizing. */\nconst COLUMN_KG_M2 = (0.85 * 25e6) / GRAVITY * 0.65\n/** Share of the gravity load the columns carry; the core and its walls take the rest. */\nconst COLUMN_SHARE = 0.5\n/** Clear space kept between the core and the columns and beams around it, metres. */\nconst CORE_CLEARANCE = 0.4\n/** A core wall is as thick as the total height over this, in metres per metre (40 cm at 80 m, 1.55 m at 312 m; real cores run 30 cm to 1.5 m). */\nconst WALL_SLENDER = 200\n\n/** Sizing by wind below this height (metres) is skipped: every tower up to 40 storeys passes H/500 as laid out. */\nexport const WIND_SIZING_DEFAULTS = { above: 180, maxBay: 20 } as const\n\nconst sizedCache = new Map<string, SkyscraperLayout>()\n\n/** The design drift (deflection over height) of the tower of a layout, in the wind it is designed for. */\nconst driftOf = (layout: SkyscraperLayout, wind: WindOptions): number => {\n const w = createDestruction({ wind })\n return w.state(w.add(buildTower(layout.tower)))?.wind?.drift ?? 0\n}\n\n/**\n * Resolves the numbers of a skyscraper from a preset and the options. Without `sizeForWind: false`, a tall tower that would drift past H/500 gets wider\n * bays (so a larger plate and core) until it does not: the way real towers thicken the core and widen the footprint with height. Memoised, because it\n * builds the tower to measure it.\n */\nexport function skyscraperLayout(options: SkyscraperOptions = {}, preset: SkyscraperPreset = SKYSCRAPER_DEFAULTS): SkyscraperLayout {\n const raw = rawLayout(options, preset)\n const o = { ...preset, ...Object.fromEntries(Object.entries(options).filter(([, v]) => v !== undefined)) } as SkyscraperPreset & SkyscraperOptions\n const cfg = { ...WIND_SIZING_DEFAULTS, ...(typeof o.sizeForWind === 'object' ? o.sizeForWind : {}) }\n if (o.sizeForWind === false || !o.wind || o.core === false || raw.total < cfg.above) return raw\n const key = JSON.stringify([options, preset])\n const hit = sizedCache.get(key)\n if (hit) return hit\n const limit = o.wind.driftLimit ?? 1 / 500\n let layout = raw\n for (let i = 0; i < 6; i++) {\n const drift = driftOf(layout, o.wind)\n const widest = Math.max(...layout.bay)\n if (drift <= limit || widest >= cfg.maxBay) break\n // drift falls about with the cube of the bay (the plate, the core and the lever arm grow together)\n const k = Math.max(1.02, Math.pow(drift / limit, 1 / 3) * 1.02)\n const bay = layout.bay.map((b) => Math.min(cfg.maxBay, round2(ceilTo(b * k, 0.5)))) as [number, number]\n layout = rawLayout({ ...options, bay }, preset)\n }\n sizedCache.set(key, layout)\n return layout\n}\n\nfunction rawLayout(options: SkyscraperOptions, preset: SkyscraperPreset): SkyscraperLayout {\n const o = { ...preset, ...Object.fromEntries(Object.entries(options).filter(([, v]) => v !== undefined)) } as SkyscraperPreset & SkyscraperOptions\n const range = o.range\n const storeys = Math.max(range[0], Math.min(range[1], Math.round(o.storeys)))\n const given: [number, number] = typeof o.bay === 'number' ? [o.bay, o.bay] : [o.bay[0], o.bay[1]]\n const oddZ = (n: number) => (Math.round(n) % 2 === 1 ? Math.round(n) : Math.round(n) + 1)\n const bays: [number, number] = [Math.max(1, Math.round(o.bays[0])), oddZ(Math.max(1, o.bays[1]))]\n const slabOf = (b: number) => Math.max(TOWER_DEFAULTS.slabThickness, round2(ceilTo(b / 32, 0.05)))\n // too slender for its plate: the bays grow until the narrowest side is a ninth of the height (the slab, and so the height, follow the bay)\n let bay: [number, number] = given\n for (let i = 0; i < 4 && o.slenderness !== false; i++) {\n const total = storeys * (o.height + (o.slabThickness ?? slabOf(Math.max(...bay))))\n const narrow = Math.min(bays[0] * bay[0], bays[1] * bay[1])\n if (narrow >= total / o.slenderness) break\n const k = total / o.slenderness / narrow\n bay = [round2(ceilTo(bay[0] * k, 0.5)), round2(ceilTo(bay[1] * k, 0.5))]\n }\n const span: [number, number] = [bays[0] * bay[0], bays[1] * bay[1]]\n const slab = o.slabThickness ?? slabOf(Math.max(...bay))\n const beamHeight = o.beamHeight ?? Math.max(TOWER_DEFAULTS.beamHeight, round2(ceilTo(Math.max(...bay) / 14, 0.1)))\n const pitch = o.height + slab\n const total = storeys * pitch\n const tributary = bay[0] * bay[1]\n const load = COLUMN_SHARE * tributary * storeys * (o.superimposed + slab * 2500)\n const columnSize = o.columnSize ?? Math.max(TOWER_DEFAULTS.columnSize, round2(ceilTo(Math.sqrt(load / COLUMN_KG_M2), 0.1)))\n const plate: [number, number] = [round2(span[0] + columnSize + 0.2), round2(span[1] + columnSize + 0.2)]\n const mech = o.mechanicalEvery === false ? undefined : o.mechanicalEvery\n const relays = o.mechanical === false ? [] : mechanicalStoreys(storeys, o.mechanical === undefined ? mech : o.mechanical.every ?? mech)\n const mechanical = o.mechanical === false ? [] : [...relays, storeys - 1]\n\n let coreLayout: SkyscraperLayout['core'] = null\n let coreOptions: CoreOptions | false = false\n if (o.core !== false) {\n const given = o.core ?? {}\n // a wall thicker than a third of its height is a block, not a plate, to the engine: it would hold no vertical bars (and no pull)\n const maxWall = Math.floor((o.height / 3 - 0.05) * 20) / 20\n const wallThickness = given.wallThickness ?? Math.max(CORE_DEFAULTS.wallThickness, Math.min(maxWall, round2(ceilTo(total / WALL_SLENDER, 0.05))))\n const ti = given.innerThickness ?? CORE_DEFAULTS.innerThickness\n const shaft = given.shaft ?? CORE_DEFAULTS.shaft\n // the most elevators whose row of shafts fits between the beams on each side of the middle bay\n const fit = Math.max(1, Math.floor((bay[1] - 2 * CORE_CLEARANCE - 0.2 - 2 * wallThickness + ti) / (shaft + ti)))\n const probe = coreSize({ ...given, wallThickness, elevators: 2 })\n const wanted = given.elevators ?? Math.max(2, Math.ceil((o.coreRatio * plate[0] * plate[1] / probe[0] - 2 * wallThickness + ti) / (shaft + ti)))\n const elevators = Math.max(1, Math.min(wanted, fit))\n // what the ratio asks beyond the elevators the bay holds goes into the width: deeper cars and service space beside the shafts, as far as the bay allows\n const narrow = coreSize({ ...given, wallThickness, elevators })\n const room = bay[0] - columnSize - 2 * CORE_CLEARANCE - narrow[0]\n const extra = given.shaftDepth !== undefined ? 0 : Math.max(0, Math.min(room, (o.coreRatio * plate[0] * plate[1]) / narrow[1] - narrow[0]))\n // the middle bay in z has no row of columns; in x the core stands in the middle bay too, or in the first half bay when the count is even\n const xs = Array.from({ length: bays[0] + 1 }, (_, i) => -span[0] / 2 + i * bay[0])\n const middle = Math.floor(bays[0] / 2)\n const center: [number, number] = given.center ?? [bays[0] % 2 === 1 ? (xs[middle] + xs[middle + 1]) / 2 : xs[middle] + bay[0] / 2, 0]\n // a high-rise core is caged tighter than a house wall: 10 cm between bars, 7.5 cm above 50 storeys (the pull at the top of a tall core needs the steel)\n const rebar = { spacing: storeys > 50 ? 0.075 : 0.1, ...given.rebar }\n coreOptions = { ...given, wallThickness, elevators, center, rebar, shaftDepth: (given.shaftDepth ?? CORE_DEFAULTS.shaftDepth) + round2(extra) }\n const size = coreSize(coreOptions)\n coreLayout = { center, size, wallThickness, elevators, stairWidth: given.stairWidth ?? CORE_DEFAULTS.stairWidth, shaftDepth: coreOptions.shaftDepth! }\n }\n const damperOn = o.damperAbove !== false && total >= o.damperAbove && o.mechanical !== false\n const tower: TowerOptions = {\n floors: storeys, height: o.height, spanX: span[0], spanZ: span[1], columnsX: bays[0] + 1, columnsZ: bays[1] + 1, columnSize, beamHeight, slabThickness: slab,\n roofThickness: round2(slab + 0.1), columnCage: { ...TOWER_DEFAULTS.columnCage }, core: coreOptions,\n facade: o.facade === 'curtain' ? (o.curtain ?? {}) : false, punched: o.facade === 'punched' ? (o.punchedFacade ?? {}) : false,\n flatRoof: o.flatRoof ?? {}, mechanical: o.mechanical === false ? false : { every: o.mechanicalEvery === false ? undefined : mech, ...o.mechanical },\n damper: damperOn ? (o.damper ?? {}) : false, wind: o.wind === false ? false : o.wind, sizing: o.sizing ?? {},\n raft: true,\n }\n return {\n storeys, height: o.height, slab, pitch, total, bay, span, columnsX: bays[0] + 1, columnsZ: bays[1] + 1, columnSize, beamHeight, plate, core: coreLayout,\n coreRatio: coreLayout ? (coreLayout.size[0] * coreLayout.size[1]) / (plate[0] * plate[1]) : 0, facade: o.facade, mechanical, damper: damperOn, tower,\n }\n}\n\n/** Mass in kg of everything above the raft's top face in a spec, plus the raft itself. */\nconst totalMass = (spec: DestructibleSpec): number => {\n const byId = new Map(MATERIALS.map((m) => [m.id, m]))\n return spec.parts.reduce((sum, part) => sum + (part.mass ?? partMass(part, byId.get(part.material)!)), 0)\n}\n\n/**\n * Piles under the raft, by the load: a grid of `pitch` diameters over the raft, each as long as it needs to carry its share of the tower with the\n * NBR 6122 safety (`pileLength`); when that is longer than `maxLength` the grid is closed up and tried again, down to a pitch of 2.5 diameters.\n */\nexport function pilesFor(spec: DestructibleSpec, soil: string | SoilProfile, design: PileDesign = {}): PileSpec {\n const raft = spec.parts.find((p) => p.id === 'raft')\n if (!raft || raft.shape.kind !== 'box') throw new Error('Piles go under a raft: the spec has none')\n const d = { ...PILE_DEFAULTS, ...design }\n const [sx, sy, sz] = raft.shape.size\n const profile = profileOf(soil)\n const soils = new Map(SOILS.map((s) => [s.id, s]))\n const weight = totalMass(spec) * GRAVITY\n if (design.length !== undefined || design.count !== undefined) {\n const count = design.count ?? Math.max(4, Math.ceil((sx * sz) / (d.pitch * d.diameter) ** 2))\n const length = design.length ?? pileLength(profile, { load: weight / count, diameter: d.diameter, top: sy, method: d.method, maxLength: d.maxLength, soils })\n return { length, diameter: d.diameter, count, method: d.method }\n }\n let pitch: number = d.pitch\n for (;;) {\n const count = Math.max(4, Math.ceil(sx / (pitch * d.diameter)) * Math.ceil(sz / (pitch * d.diameter)))\n const length = pileLength(profile, { load: weight / count, diameter: d.diameter, top: sy, method: d.method, maxLength: d.maxLength, soils })\n if (length < d.maxLength || pitch <= 2.5) return { length, diameter: d.diameter, count, method: d.method }\n pitch = Math.max(2.5, pitch - 0.25)\n }\n}\n\n/** The tower of a layout: `buildTower` on a raft, then the soil and, with it, the deep piles sized by the load. */\nexport function buildSkyscraper(options: SkyscraperOptions = {}, preset: SkyscraperPreset = SKYSCRAPER_DEFAULTS): DestructibleSpec {\n const layout = skyscraperLayout(options, preset)\n const o = { ...SKYSCRAPER_DEFAULTS, ...preset, ...Object.fromEntries(Object.entries(options).filter(([, v]) => v !== undefined)) } as SkyscraperPreset\n const built = buildTower(layout.tower)\n const spec: DestructibleSpec = { ...built, name: 'skyscraper', tags: [...(built.tags ?? []), 'skyscraper'] }\n if (o.soil === false) return spec\n const parts: PartSpec[] = spec.parts.map((part) => {\n if (part.id !== 'raft') return part\n return o.piles === false ? { ...part, structure: { ...part.structure!, role: 'foundation' } } : { ...part, structure: { ...part.structure!, role: 'foundation', pile: pilesFor(spec, o.soil as string | SoilProfile, o.piles) } }\n })\n return { ...spec, parts, soil: o.soil }\n}\n","import type { DoorDef, FloorDef, RoomDef, WindowDef } from '@adatechnology/game-floorplan'\n\nimport type { SkyscraperLayout } from './skyscraper'\nimport enLocale from './locales/en.json'\nimport ptBrLocale from './locales/pt-BR.json'\n\n/**\n * The floor plan of a skyscraper at room level, shared by every typology: a central core (stairs, elevator shafts and a service shaft) inside a ring of\n * corridors, with the four strips of the perimeter left for the typology (office suites, apartments) to fill. The plate and the core come from the\n * same `SkyscraperLayout` as the structure (`buildSkyscraper`), so a room of the plan stands where the structure has its slab and its core. The plan is in\n * the space of `game-floorplan` (`u` to the right, `v` to the back, from the front-left corner); the structure is centred (`planToSpace`). Design\n * T10-estrutura-real.md §11.5.\n */\n\n/** `[u0, v0, u1, v1]`. */\nexport type PlateRect = [number, number, number, number]\n\nexport interface PlateOptions {\n /** Width of the corridors around the core (default 1.8 m). */\n corridor?: number\n /** Width of the elevator lobby beside the shafts (default 3 m). */\n lobby?: number\n /** Narrowest the stair room is made (default 3.4 m): the stairs need more than the tube's clear width. */\n stairWidth?: number\n}\n\nexport const PLATE_DEFAULTS = { corridor: 1.8, lobby: 3, stairWidth: 3.4 } as const\n\nexport type StripId = 'south' | 'north' | 'west' | 'east'\n\n/** One of the four bands of the perimeter, where the typology puts its rooms. */\nexport interface PlateStrip {\n id: StripId\n /** Side of the building the outer edge is on, as `game-floorplan` names it. */\n side: 'front' | 'back' | 'left' | 'right'\n rect: PlateRect\n /** The strip runs along `u` (south and north) or along `v` (west and east). */\n alongU: boolean\n /** Length along the perimeter and depth from the outer wall to the circulation, metres. */\n length: number\n depth: number\n /** Id (without the storey suffix) of the circulation room the inner edge touches: `corridor_s`, `corridor_n`, `corridor_w` or `lobby`. */\n circulation: string\n}\n\nexport interface TowerPlate {\n w: number\n d: number\n core: PlateRect\n stairs: PlateRect\n service: PlateRect | null\n shafts: PlateRect[]\n lobby: PlateRect\n corridors: { s: PlateRect; n: PlateRect; w: PlateRect }\n strips: PlateStrip[]\n}\n\nconst r2 = (v: number): number => Math.round(v * 100) / 100\n\n/** The plate of a layout: where the core, its rooms, the circulation and the four strips stand. */\nexport function towerPlate(layout: SkyscraperLayout, options: PlateOptions = {}): TowerPlate {\n const o = { ...PLATE_DEFAULTS, ...options }\n const [w, d] = layout.plate\n const core = layout.core\n if (!core) throw new Error('A tower plan needs a core (turn the core on)')\n const t = core.wallThickness\n const [W, L] = core.size\n const u = w / 2 + core.center[0], v = d / 2 + core.center[1]\n const rect: PlateRect = [r2(u - W / 2), r2(v - L / 2), r2(u + W / 2), r2(v + L / 2)]\n const [x0, z0, x1, z1] = rect\n const split = r2(Math.min(x1 - 1.8, x0 + Math.max(o.stairWidth, t + core.stairWidth + 0.1)))\n const stairEnd = r2(z0 + Math.min(L, Math.max(5.4, 2 * t + 4.8)))\n const merged = z1 - stairEnd < 1.6\n const stairs: PlateRect = [x0, z0, split, merged ? z1 : stairEnd]\n const service: PlateRect | null = merged ? null : [x0, stairEnd, split, z1]\n const n = core.elevators\n const shafts = Array.from({ length: n }, (_, k): PlateRect => [split, r2(z0 + (k * L) / n), x1, r2(z0 + ((k + 1) * L) / n)])\n const lobby: PlateRect = [x1, z0, r2(x1 + o.lobby), z1]\n const west: PlateRect = [r2(x0 - o.corridor), z0, x0, z1]\n const south: PlateRect = [0, r2(z0 - o.corridor), w, z0]\n const north: PlateRect = [0, z1, w, r2(z1 + o.corridor)]\n const strip = (id: StripId, side: PlateStrip['side'], r: PlateRect, alongU: boolean, circulation: string): PlateStrip => ({\n id, side, rect: r, alongU, length: r2(alongU ? r[2] - r[0] : r[3] - r[1]), depth: r2(alongU ? r[3] - r[1] : r[2] - r[0]), circulation,\n })\n return {\n w, d, core: rect, stairs, service, shafts, lobby, corridors: { s: south, n: north, w: west },\n strips: [\n strip('south', 'front', [0, 0, w, south[1]], true, 'corridor_s'),\n strip('north', 'back', [0, north[3], w, d], true, 'corridor_n'),\n strip('west', 'left', [0, z0, west[0], z1], false, 'corridor_w'),\n strip('east', 'right', [lobby[2], z0, w, z1], false, 'lobby'),\n ],\n }\n}\n\n/** A point of the plan (`u`, `v`) in the space of the structure (centred on the plate, `x` right, `z` back). */\nexport const planToSpace = (layout: SkyscraperLayout, [u, v]: [number, number]): [number, number] => [r2(u - layout.plate[0] / 2), r2(v - layout.plate[1] / 2)]\n\nexport type StoreyKind = 'ground' | 'typical' | 'mechanical'\n\n/** What kind each storey is: the first is the ground floor, the mechanical ones are the plant floors of the layout, the rest are typical. */\nexport const storeyKinds = (layout: SkyscraperLayout): StoreyKind[] =>\n Array.from({ length: layout.storeys }, (_, f) => (f === 0 ? 'ground' : layout.mechanical.includes(f) ? 'mechanical' : 'typical'))\n\nexport interface StoreyContext {\n floor: number\n kind: StoreyKind\n layout: SkyscraperLayout\n plate: TowerPlate\n /** Floor to floor, metres: the ceiling of the plan floor. */\n ceiling: number\n}\n\nexport interface StripFill {\n rooms: RoomDef[]\n doors: DoorDef[]\n windows: WindowDef[]\n}\n\n/** Fills one strip of a storey with rooms. Room ids must be unique in the whole tower: end them with the storey (`_${floor}`). */\nexport type StripFiller = (strip: PlateStrip, storey: StoreyContext) => StripFill\n\nexport interface TowerPlanOptions extends PlateOptions {\n /** The perimeter of the typical storeys. */\n typical: StripFiller\n /** The ground floor (default: the typical filler). */\n ground?: StripFiller\n /** The plant floors (default: one plant room per strip, no windows). */\n mechanical?: StripFiller\n}\n\n/** Cuts a strip into `count` equal parts along its length. */\nexport const splitStrip = (strip: PlateStrip, count: number): PlateRect[] => {\n const [u0, v0, u1, v1] = strip.rect\n return Array.from({ length: Math.max(1, count) }, (_, k): PlateRect => {\n const a = k / Math.max(1, count), b = (k + 1) / Math.max(1, count)\n return strip.alongU ? [r2(u0 + (u1 - u0) * a), v0, r2(u0 + (u1 - u0) * b), v1] : [u0, r2(v0 + (v1 - v0) * a), u1, r2(v0 + (v1 - v0) * b)]\n })\n}\n\nconst EDGE = 1e-6\n\n/**\n * Windows on every outside wall of a room of the plate, `spacing` metres apart (at least one a wall); `y0`, `y1` the sill and head (default 0.3 and the\n * ceiling less 0.5 m, a glass facade).\n */\nexport function exteriorWindows(id: string, rect: PlateRect, plate: TowerPlate, ceiling: number, o: { spacing?: number; width?: number; y0?: number; y1?: number } = {}): WindowDef[] {\n const [u0, v0, u1, v1] = rect\n const spacing = o.spacing ?? 3\n const out: WindowDef[] = []\n const add = (side: string, length: number) => {\n const n = Math.max(1, Math.round(length / spacing))\n out.push({ room: id, side, n, width: Math.min(o.width ?? 2.4, (length / n) * 0.8), y0: o.y0 ?? 0.3, y1: o.y1 ?? r2(ceiling - 0.5) })\n }\n if (Math.abs(v0) < EDGE) add('front', u1 - u0)\n if (Math.abs(v1 - plate.d) < EDGE) add('back', u1 - u0)\n if (Math.abs(u0) < EDGE) add('left', v1 - v0)\n if (Math.abs(u1 - plate.w) < EDGE) add('right', v1 - v0)\n return out\n}\n\n/** The door from a room of a strip to the circulation it touches. */\nexport const stripDoor = (id: string, strip: PlateStrip, floor: number, width = 1): DoorDef => ({ a: id, b: `${strip.circulation}_${floor}`, width, opensTo: id })\n\n/** The default fill of a plant floor: a plant room on each strip, with a door to the circulation and no windows (the facade has louvres there). */\nconst plantRooms: StripFiller = (strip, { floor }) => {\n const id = `plant_${floor}_${strip.id}`\n return { rooms: [{ id, type: 'storage', label: 'plant_room', rect: [...strip.rect] }], doors: [stripDoor(id, strip, floor, 1.2)], windows: [] }\n}\n\n/** The core and the circulation of a storey: the stairs, the shafts, the service shaft, the lobby and the three corridors, with their doors. */\nfunction coreRooms(plate: TowerPlate, floor: number, storeys: number): { rooms: RoomDef[]; doors: DoorDef[]; openPairs: [string, string][] } {\n const id = (name: string) => `${name}_${floor}`\n const link = floor < storeys - 1 ? [floor, floor + 1] : [floor - 1, floor]\n const rooms: RoomDef[] = [\n { id: id('stairs'), type: 'stairs', label: 'stairs', rect: [...plate.stairs], link },\n ...(plate.service ? [{ id: id('service'), type: 'storage', label: 'service_shaft', rect: [...plate.service] }] : []),\n ...plate.shafts.map((rect, k): RoomDef => ({ id: id(`elevator_${k}`), type: 'elevator', label: 'elevator', rect: [...rect] })),\n { id: id('lobby'), type: 'hall', label: 'elevator_lobby', rect: [...plate.lobby] },\n { id: id('corridor_w'), type: 'corridor', label: 'corridor', rect: [...plate.corridors.w] },\n { id: id('corridor_s'), type: 'corridor', label: 'corridor', rect: [...plate.corridors.s] },\n { id: id('corridor_n'), type: 'corridor', label: 'corridor', rect: [...plate.corridors.n] },\n ]\n const doors: DoorDef[] = [\n { a: id('stairs'), b: id('corridor_w'), width: 1, opensTo: id('corridor_w') },\n ...(plate.service ? [{ a: id('service'), b: id('corridor_w'), width: 0.8, opensTo: id('service') }] : []),\n ...plate.shafts.map((_, k): DoorDef => ({ a: id(`elevator_${k}`), b: id('lobby'), width: 1.2, opensTo: id('lobby') })),\n ]\n const openPairs: [string, string][] = [[id('lobby'), id('corridor_s')], [id('lobby'), id('corridor_n')], [id('corridor_w'), id('corridor_s')], [id('corridor_w'), id('corridor_n')]]\n return { rooms, doors, openPairs }\n}\n\n/**\n * The storeys of a tower as `FloorDef`s for `TemplateDef.floorsFn`: each has the core and the circulation, the strips filled by the typology for its\n * kind of storey (ground, typical, plant), `ceiling` the storey pitch of the structure. The template's size must be the plate (`layout.plate`).\n */\nexport function towerFloors(layout: SkyscraperLayout, plan: TowerPlanOptions): FloorDef[] {\n const plate = towerPlate(layout, plan)\n const fillers: Record<StoreyKind, StripFiller> = { ground: plan.ground ?? plan.typical, typical: plan.typical, mechanical: plan.mechanical ?? plantRooms }\n return storeyKinds(layout).map((kind, floor): FloorDef => {\n const context: StoreyContext = { floor, kind, layout, plate, ceiling: layout.pitch }\n const fills = plate.strips.map((strip) => fillers[kind](strip, context))\n const core = coreRooms(plate, floor, layout.storeys)\n return {\n label: kind === 'ground' ? 'ground_floor' : kind === 'mechanical' ? 'mechanical_floor' : 'typical_floor',\n ceiling: layout.pitch,\n openPairs: core.openPairs,\n rooms: () => [...core.rooms, ...fills.flatMap((f) => f.rooms)],\n doors: () => [...core.doors, ...fills.flatMap((f) => f.doors)],\n windows: () => fills.flatMap((f) => f.windows),\n }\n })\n}\n\n/** The names of the rooms and storeys the plan helpers make (`elevator_lobby`, `plant_room`, `typical_floor`...), for the packs that fill the strips to register with `engine.registerLocale`. */\nexport const towerLocales = { en: { labels: enLocale.labels }, 'pt-BR': { labels: ptBrLocale.labels } } as const\n"],"mappings":"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Ae;MACf,SAAW;QACV,OAAS;QACT,UAAY;QACZ,cAAgB;QAChB,cAAgB;MACjB;MACA,QAAU;QACT,OAAS;MACV;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,kBAAoB;MACpB,kBAAoB;MACpB,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;QACT,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,kBAAoB;MACpB,kBAAoB;MACpB,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,kBAAoB;MACpB,kBAAoB;MACpB,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,kBAAoB;MACpB,kBAAoB;MACpB,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;QACT,SAAW;MACZ;MACA,WAAa;MACb,aAAe;MACf,aAAe;MACf,SAAW;QACV,OAAS;QACT,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,eAAiB;MAClB;MACA,QAAU;QACT,OAAS;QACT,aAAe;MAChB;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,WAAa;MACb,aAAe;MACf,aAAe;MACf,SAAW;QACV,OAAS;QACT,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,eAAiB;MAClB;MACA,QAAU;QACT,OAAS;QACT,aAAe;MAChB;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;MACf,aAAe;QACd,SAAW;MACZ;IACD;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,cAAgB;QAChB,cAAgB;QAChB,eAAiB;MAClB;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,kBAAoB;MACpB,kBAAoB;MACpB,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,WAAa;MACd;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,cAAgB;QAChB,cAAgB;MACjB;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;MACf,UAAY;QACX,gBAAkB;QAClB,YAAc;QACd,YAAc;MACf;IACD;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,kBAAoB;MACpB,kBAAoB;MACpB,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,cAAgB;QAChB,cAAgB;MACjB;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;MACf,UAAY;QACX,gBAAkB;QAClB,YAAc;QACd,YAAc;MACf;IACD;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,kBAAoB;MACpB,kBAAoB;MACpB,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,cAAgB;QAChB,cAAgB;MACjB;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,kBAAoB;MACpB,kBAAoB;MACpB,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,cAAgB;QAChB,cAAgB;MACjB;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,OAAS;QACT,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;QACT,WAAa;MACd;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;QACT,WAAa;MACd;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,kBAAoB;MACpB,kBAAoB;MACpB,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;QACT,WAAa;MACd;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;QACA;MACD;MACA,aAAe;QACd,OAAS;MACV;MACA,WAAa;MACb,aAAe;MACf,SAAW;QACV,WAAa;QACb,QAAU;QACV,cAAgB;QAChB,UAAY;QACZ,cAAgB;QAChB,cAAgB;QAChB,OAAS;MACV;MACA,QAAU;QACT,WAAa;MACd;MACA,MAAQ;QACP;QACA;QACA;MACD;MACA,aAAe;IAChB;IACA;MACC,IAAM;MACN,SAAW;MACX,SAAW;MACX,aAAe;MACf,WAAa;MACb,UAAY;MACZ,cAAgB;QACf;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","names":["addFlatRoof","onSoil","box","box","box","at","box","box","at","frame","item","flight","box","box","part","box","entry","entry","round2","round2","round2","round2","round2","distance","box","absolute","round2","round2","box","DOOR_HEIGHT","frame","round2","box","distance","clamp","n0","n1","a","c","t0","t1","dy","inside","sign","clamp","n","b","th","u","v","distance","bar","rest","s","definedOf","rest","totalMass","z","clamp","pos","at","holds","box","world","nx","nz","lean","unitsOf","round","entry","dmg","opening","energyOf","spread","rest","densityOf","slabId","rest","without","distance","EPS","at","best","runsOf","EPS","at","box","runsOf","frame","opening","at","box","LINTEL_DEPTH","LINTEL_BEARING","frame","roleOf","opening","box","raft","DOOR_WIDTH","opening","raft","at","addFlatRoof","frame","ceilTo","round2","total","given","raft","merged"]}