@adatechnology/game-terrain 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/catalog.ts","../src/debris.ts","../src/marks.ts","../src/random.ts","../src/terrain.ts","../src/impl.ts","../src/types.ts"],"sourcesContent":["import type { TerrainMaterial, TerrainProfile } from './types'\n\n// Specific energies are what the marks of real blows imply: a 500 J pistol round leaves about 120 cm³ in soil and 3 cm³ in concrete, an 800 kJ grenade a 1.3 m crater in soil and a 25 cm spall on a slab.\nexport const TERRAIN_MATERIALS: readonly TerrainMaterial[] = [\n {\n id: 'turf',\n debris: 'clods',\n rimShare: 0.25,\n reposeDegrees: 55,\n color: [0.09, 0.2, 0.04],\n pattern: 'grass',\n hits: {\n ballistic: { specificEnergy: 3e6, aspect: 0.6 },\n blunt: { specificEnergy: 2e6, aspect: 0.2, thresholdJoules: 60 },\n slash: { specificEnergy: 3e5, aspect: 0.5 },\n explosive: { specificEnergy: 3e6, aspect: 0.45 },\n },\n fire: { maxScorch: 1, scorchPerSecond: 0.45, flammable: true },\n },\n {\n id: 'soil',\n debris: 'clods',\n rimShare: 0.35,\n reposeDegrees: 40,\n color: [0.2, 0.12, 0.06],\n pattern: 'soil',\n hits: {\n ballistic: { specificEnergy: 4e6, aspect: 0.6 },\n blunt: { specificEnergy: 2e6, aspect: 0.2, thresholdJoules: 60 },\n slash: { specificEnergy: 3e5, aspect: 0.5 },\n explosive: { specificEnergy: 4e6, aspect: 0.45 },\n },\n fire: { maxScorch: 0.6, scorchPerSecond: 0.15 },\n },\n {\n id: 'sand',\n debris: 'dust',\n rimShare: 0.5,\n reposeDegrees: 33,\n color: [0.62, 0.5, 0.3],\n pattern: 'sand',\n hits: {\n ballistic: { specificEnergy: 2.5e6, aspect: 0.5 },\n blunt: { specificEnergy: 1e6, aspect: 0.2, thresholdJoules: 30 },\n slash: { specificEnergy: 1.5e5, aspect: 0.5 },\n explosive: { specificEnergy: 3e6, aspect: 0.35 },\n },\n fire: { maxScorch: 0.2, scorchPerSecond: 0.05 },\n },\n {\n id: 'gravel',\n debris: 'chips',\n rimShare: 0.3,\n reposeDegrees: 38,\n color: [0.27, 0.25, 0.22],\n pattern: 'stone',\n hits: {\n ballistic: { specificEnergy: 8e6, aspect: 0.4 },\n blunt: { specificEnergy: 8e6, aspect: 0.2, thresholdJoules: 200 },\n slash: { specificEnergy: 3e7, aspect: 0.3, thresholdJoules: 400 },\n explosive: { specificEnergy: 1e7, aspect: 0.35 },\n },\n fire: { maxScorch: 0.3, scorchPerSecond: 0.06 },\n },\n {\n id: 'asphalt',\n debris: 'chips',\n color: [0.05, 0.05, 0.055],\n pattern: 'asphalt',\n hits: {\n ballistic: { specificEnergy: 3e7, aspect: 0.2, minRadius: 0.03 },\n blunt: { specificEnergy: 1e8, aspect: 0.1, thresholdJoules: 400 },\n slash: { specificEnergy: 3e8, aspect: 0.2, thresholdJoules: 400 },\n explosive: { specificEnergy: 2e8, aspect: 0.12 },\n },\n fire: { maxScorch: 0.85, scorchPerSecond: 0.1, burnsAway: 0.00005 },\n },\n {\n id: 'concrete',\n debris: 'chips',\n color: [0.33, 0.33, 0.31],\n pattern: 'concrete',\n hits: {\n ballistic: { specificEnergy: 1.5e8, aspect: 0.14, minRadius: 0.018 },\n blunt: { specificEnergy: 3e8, aspect: 0.08, thresholdJoules: 800 },\n slash: { specificEnergy: 1e9, aspect: 0.2, thresholdJoules: 800 },\n explosive: { specificEnergy: 2.7e9, aspect: 0.12 },\n },\n fire: { maxScorch: 0.45, scorchPerSecond: 0.08 },\n },\n {\n id: 'mortar',\n debris: 'chips',\n color: [0.42, 0.4, 0.36],\n pattern: 'plain',\n hits: {\n ballistic: { specificEnergy: 4e7, aspect: 0.2 },\n blunt: { specificEnergy: 8e7, aspect: 0.1, thresholdJoules: 300 },\n slash: { specificEnergy: 3e8, aspect: 0.2, thresholdJoules: 300 },\n explosive: { specificEnergy: 8e8, aspect: 0.14 },\n },\n fire: { maxScorch: 0.45, scorchPerSecond: 0.08 },\n },\n {\n id: 'ceramic',\n debris: 'shards',\n color: [0.72, 0.7, 0.66],\n pattern: 'tile',\n hits: {\n ballistic: { specificEnergy: 8e6, aspect: 0.1, minRadius: 0.05 },\n blunt: { specificEnergy: 1e7, aspect: 0.08, thresholdJoules: 80, minRadius: 0.06 },\n slash: { specificEnergy: 2e8, aspect: 0.1, thresholdJoules: 200, minRadius: 0.03 },\n explosive: { specificEnergy: 1e8, aspect: 0.03, minRadius: 0.12 },\n },\n fire: { maxScorch: 0.5, scorchPerSecond: 0.08 },\n },\n {\n id: 'wood_hard',\n debris: 'splinters',\n color: [0.3, 0.16, 0.07],\n pattern: 'planks',\n hits: {\n ballistic: { specificEnergy: 2.5e7, aspect: 0.35, minRadius: 0.012 },\n blunt: { specificEnergy: 8e7, aspect: 0.1, thresholdJoules: 120 },\n slash: { specificEnergy: 1.5e7, aspect: 0.4, thresholdJoules: 15 },\n explosive: { specificEnergy: 2e8, aspect: 0.1, minRadius: 0.1 },\n },\n fire: { maxScorch: 1, scorchPerSecond: 0.2, burnsAway: 0.0012, flammable: true },\n },\n {\n id: 'stone',\n debris: 'chips',\n color: [0.23, 0.22, 0.2],\n pattern: 'stone',\n hits: {\n ballistic: { specificEnergy: 2.5e8, aspect: 0.12, minRadius: 0.015 },\n blunt: { specificEnergy: 5e8, aspect: 0.08, thresholdJoules: 1500 },\n slash: { specificEnergy: 2e9, aspect: 0.2, thresholdJoules: 1500 },\n explosive: { specificEnergy: 4e9, aspect: 0.14 },\n },\n fire: { maxScorch: 0.4, scorchPerSecond: 0.06 },\n },\n]\n\nexport const TERRAIN_PROFILES: readonly TerrainProfile[] = [\n { id: 'lawn', strata: [{ material: 'turf', thickness: 0.05 }, { material: 'soil', thickness: 1.5 }, { material: 'stone', thickness: 0.5 }] },\n { id: 'dirt', strata: [{ material: 'soil', thickness: 1.8 }, { material: 'stone', thickness: 0.5 }] },\n { id: 'sand', strata: [{ material: 'sand', thickness: 2.5 }] },\n { id: 'road', strata: [{ material: 'asphalt', thickness: 0.05 }, { material: 'gravel', thickness: 0.25 }, { material: 'soil', thickness: 1.5 }] },\n { id: 'concrete_slab', strata: [{ material: 'concrete', thickness: 0.12, reinforcement: { material: 'steel', cover: 0.03, spacing: 0.15, resistance: 4 } }] },\n { id: 'suspended_slab', drop: 3, strata: [{ material: 'concrete', thickness: 0.12, reinforcement: { material: 'steel', cover: 0.03, spacing: 0.15, resistance: 4 } }] },\n { id: 'tile_floor', strata: [{ material: 'ceramic', thickness: 0.008 }, { material: 'mortar', thickness: 0.03 }, { material: 'concrete', thickness: 0.1, reinforcement: { material: 'steel', cover: 0.03, spacing: 0.15, resistance: 4 } }] },\n { id: 'wood_floor', strata: [{ material: 'wood_hard', thickness: 0.022 }, { material: 'mortar', thickness: 0.03 }, { material: 'concrete', thickness: 0.1, reinforcement: { material: 'steel', cover: 0.03, spacing: 0.15, resistance: 4 } }] },\n { id: 'stone_paving', strata: [{ material: 'stone', thickness: 0.08 }, { material: 'gravel', thickness: 0.2 }, { material: 'soil', thickness: 1.2 }] },\n]\n\n/** About twelve grenades (200 kJ) on the same spot of bare bars. */\nexport const DEFAULT_BAR_YIELD_JOULES = 2_400_000\n\n/** The profile of a floor with nothing else said: a plain slab. */\nexport const DEFAULT_PROFILE = 'concrete_slab'\n","import type { TerrainDebris, TerrainDebrisKind } from './types'\n\nconst REST_SPEED = 0.6\nconst RESTITUTION = 0.25\nconst FRICTION = 0.55\nconst MAX_BOUNCES = 2\nconst REST_GAP = 0.01\n\nexport interface DebrisWorld {\n heightAt(x: number, z: number): number\n gravity: number\n /** Soft pieces join the ground where they stop; a false keeps the piece as loose rubble. */\n settle(piece: TerrainDebris): boolean\n}\n\n/** Pieces thrown by blows: they fly, hit the deformed ground, and come to rest. Past `max` the oldest at rest goes first. */\nexport interface DebrisStore {\n readonly list: TerrainDebris[]\n throwPiece(spec: { material: string; kind: TerrainDebrisKind; radius: number; position: [number, number, number]; velocity: [number, number, number]; spin: [number, number, number] }): void\n update(dt: number, world: DebrisWorld): void\n clear(): void\n}\n\nexport function createDebrisStore(max: () => number): DebrisStore {\n const list: TerrainDebris[] = []\n let serial = 0\n\n function makeRoom(): void {\n if (list.length < max()) return\n let at = 0\n let oldest = Infinity\n let oldestResting = -1\n let restingBorn = Infinity\n list.forEach((piece, index) => {\n if (piece.born < oldest) {\n oldest = piece.born\n at = index\n }\n if (piece.atRest && piece.born < restingBorn) {\n restingBorn = piece.born\n oldestResting = index\n }\n })\n list.splice(oldestResting >= 0 ? oldestResting : at, 1)\n }\n\n return {\n list,\n throwPiece(spec) {\n makeRoom()\n list.push({ ...spec, id: ++serial, born: serial, atRest: false, bounces: 0 })\n },\n update(dt, world) {\n for (let i = list.length - 1; i >= 0; i--) {\n const piece = list[i]!\n if (piece.atRest) {\n // what it lay on was dug away or heaped over: it falls again, or rides up\n const under = world.heightAt(piece.position[0], piece.position[2]) + piece.radius * 0.6\n if (piece.position[1] > under + REST_GAP) piece.atRest = false\n else if (piece.position[1] < under - REST_GAP) piece.position[1] = under\n if (piece.atRest) continue\n }\n const { position, velocity } = piece\n velocity[1] -= world.gravity * dt\n position[0] += velocity[0] * dt\n position[1] += velocity[1] * dt\n position[2] += velocity[2] * dt\n const ground = world.heightAt(position[0], position[2]) + piece.radius * 0.6\n if (position[1] > ground) continue\n position[1] = ground\n const speed = Math.hypot(velocity[0], velocity[1], velocity[2])\n if (speed < REST_SPEED || piece.bounces >= MAX_BOUNCES) {\n piece.atRest = true\n if (world.settle(piece)) list.splice(i, 1)\n continue\n }\n piece.bounces++\n velocity[1] = Math.abs(velocity[1]) * RESTITUTION\n velocity[0] *= FRICTION\n velocity[2] *= FRICTION\n }\n },\n clear() {\n list.length = 0\n },\n }\n}\n","import type { TerrainBudget, TerrainMark } from './types'\n\n/** Two marks at this fraction of their radii or closer are one hole. */\nconst SAME_HOLE = 0.75\n\n/** Fine marks under a budget per area and a global one: past the budget the closest two of the area become one, and past the global one the oldest goes. */\nexport interface MarkStore {\n readonly list: TerrainMark[]\n add(spec: Omit<TerrainMark, 'id' | 'count' | 'born'>): TerrainMark\n near(x: number, z: number, radius: number): TerrainMark | undefined\n depthAt(x: number, z: number): number\n remove(mark: TerrainMark): void\n removeInside(x: number, z: number, radius: number): void\n clear(): void\n load(marks: readonly TerrainMark[]): void\n readonly version: number\n}\n\nexport function createMarkStore(budget: TerrainBudget): MarkStore {\n const list: TerrainMark[] = []\n const areas = new Map<number, TerrainMark[]>()\n let serial = 0\n let version = 0\n const areaKey = (x: number, z: number): number => Math.floor(x / budget.markAreaSize) * 100003 + Math.floor(z / budget.markAreaSize)\n\n function detach(mark: TerrainMark): void {\n const key = areaKey(mark.x, mark.z)\n const area = areas.get(key)\n if (area) {\n const at = area.indexOf(mark)\n if (at >= 0) area.splice(at, 1)\n if (area.length === 0) areas.delete(key)\n }\n const at = list.indexOf(mark)\n if (at >= 0) list.splice(at, 1)\n version++\n }\n\n function attach(mark: TerrainMark): void {\n const key = areaKey(mark.x, mark.z)\n const area = areas.get(key)\n if (area) area.push(mark)\n else areas.set(key, [mark])\n list.push(mark)\n version++\n }\n\n function mergeClosestPair(area: TerrainMark[]): void {\n let bestA = area[0]!\n let bestB = area[1]!\n let best = Infinity\n for (let i = 0; i < area.length; i++) {\n for (let j = i + 1; j < area.length; j++) {\n const distance = Math.hypot(area[i]!.x - area[j]!.x, area[i]!.z - area[j]!.z)\n if (distance < best) {\n best = distance\n bestA = area[i]!\n bestB = area[j]!\n }\n }\n }\n const weight = bestA.radius ** 2 + bestB.radius ** 2\n const shareB = weight > 0 ? bestB.radius ** 2 / weight : 0.5\n detach(bestB)\n bestA.x += (bestB.x - bestA.x) * shareB\n bestA.z += (bestB.z - bestA.z) * shareB\n bestA.radius = Math.sqrt(weight)\n bestA.depth = Math.max(bestA.depth, bestB.depth)\n bestA.count += bestB.count\n version++\n }\n\n return {\n list,\n add(spec) {\n const mark: TerrainMark = { ...spec, id: ++serial, count: 1, born: serial }\n attach(mark)\n const area = areas.get(areaKey(mark.x, mark.z))!\n if (area.length > budget.maxMarksPerArea) mergeClosestPair(area)\n if (list.length > budget.maxMarks) detach(list.reduce((oldest, candidate) => (candidate.born < oldest.born ? candidate : oldest)))\n return mark\n },\n near(x, z, radius) {\n let found: TerrainMark | undefined\n let best = Infinity\n const reach = Math.ceil((radius + 0.5) / budget.markAreaSize)\n const baseX = Math.floor(x / budget.markAreaSize)\n const baseZ = Math.floor(z / budget.markAreaSize)\n for (let dx = -reach; dx <= reach; dx++) {\n for (let dz = -reach; dz <= reach; dz++) {\n for (const mark of areas.get((baseX + dx) * 100003 + baseZ + dz) ?? []) {\n const distance = Math.hypot(mark.x - x, mark.z - z)\n if (distance < best && distance < Math.max(mark.radius, radius) * SAME_HOLE) {\n best = distance\n found = mark\n }\n }\n }\n }\n return found\n },\n depthAt(x, z) {\n let depth = 0\n for (const mark of areas.get(areaKey(x, z)) ?? []) {\n const distance = Math.hypot(mark.x - x, mark.z - z)\n if (distance < mark.radius) depth = Math.max(depth, mark.depth * (1 - (distance / mark.radius) ** 2))\n }\n return depth\n },\n remove: detach,\n removeInside(x, z, radius) {\n for (const mark of [...list]) if (Math.hypot(mark.x - x, mark.z - z) + mark.radius * 0.5 < radius) detach(mark)\n },\n clear() {\n list.length = 0\n areas.clear()\n version++\n },\n load(marks) {\n this.clear()\n for (const mark of marks) {\n attach({ ...mark })\n serial = Math.max(serial, mark.id)\n }\n },\n get version() {\n return version\n },\n }\n}\n","/** A small seeded stream: the same seed digs the same crater, so a blow of a few bytes draws the same on every client. */\nexport function createRandom(seed: number): () => number {\n let state = seed | 0\n return () => {\n state = (state + 0x6d2b79f5) | 0\n let mixed = Math.imul(state ^ (state >>> 15), 1 | state)\n mixed = (mixed + Math.imul(mixed ^ (mixed >>> 7), 61 | mixed)) ^ mixed\n return ((mixed ^ (mixed >>> 14)) >>> 0) / 4294967296\n }\n}\n","import type { Hit } from '@adatechnology/game-contracts'\nimport { DEFAULT_BAR_YIELD_JOULES, DEFAULT_PROFILE, TERRAIN_MATERIALS, TERRAIN_PROFILES } from './catalog'\nimport { createDebrisStore } from './debris'\nimport { createMarkStore } from './marks'\nimport { createRandom } from './random'\nimport type { GroundLayout, Terrain, TerrainBlow, TerrainBlowResult, TerrainBudget, TerrainChunk, TerrainColumn, TerrainDebris, TerrainMark, TerrainMaterial, TerrainOptions, TerrainProfile, TerrainRegion, TerrainSnapshot, TerrainStratum } from './types'\n\nexport const DEFAULT_TERRAIN_BUDGET: TerrainBudget = {\n markAreaSize: 2,\n maxMarksPerArea: 24,\n maxMarks: 800,\n maxDirtyChunksPerFrame: 6,\n maxDebris: 400,\n maxDebrisPerBlow: 36,\n maxSlideCellsPerFrame: 2500,\n maxBurningCells: 300,\n}\n\nconst GRAVITY = 9.81\n/** A bowl narrower than this many cells cannot be drawn by the height field: it stays a fine mark. */\nconst FINE_CELLS = 1.5\n/** A hole deeper than this many cells is no longer a mark on the surface. */\nconst FINE_DEPTH_CELLS = 0.4\nconst RIGID_WIDENING = 2.5\n/** Bars alone do not drop a slab that still has this share of its concrete to lose. */\nconst COLLAPSE_DEPTH_SHARE = 0.75\nconst COLLAPSE_SPREAD_BEND = 0.5\nconst RIM_REACH = 1.45\n/** Under this temperature (°C) a flame does nothing to the ground. */\nconst FLAME_MINIMUM = 200\n/** How far over the ground a flame still touches it, beyond its radius. */\nconst FLAME_REACH = 0.6\n/** How far a blast above the ground still reaches it, as a share of its radius. */\nconst BLAST_HEIGHT_REACH = 0.35\n/** Share of a blow's energy that throws the pieces. */\nconst THROW_SHARE = 0.02\n/** Side of a square of ground that burns as one, in metres. */\nconst FIRE_CELL = 0.5\nconst FIRE_SECONDS = 7\nconst FIRE_SPREAD_PER_SECOND = 0.35\nconst SLIDE_SHARE = 0.4\nconst SLIDE_EPSILON = 0.002\n/** Radius of a thrown piece per kind: a clod is a fist of soil, a chip is a thumb of concrete. */\nconst PIECE_RADIUS: Record<TerrainMaterial['debris'], number> = { clods: 0.045, chips: 0.022, shards: 0.028, splinters: 0.02, dust: 0.012 }\n/** Metres per second the fastest piece of a blow leaves at: a blast throws, a dropped weight only kicks. */\nconst MAX_PIECE_SPEED: Record<TerrainBlow, number> = { explosive: 14, ballistic: 5, blunt: 2.5, slash: 1.5 }\n\nconst clampIndex = (value: number, max: number): number => Math.max(0, Math.min(max, value))\nconst sparse = (array: Float32Array): [number, number][] => {\n const entries: [number, number][] = []\n array.forEach((value, index) => {\n if (value !== 0) entries.push([index, value])\n })\n return entries\n}\nconst fillSparse = (array: Float32Array, entries: readonly (readonly [number, number])[]): void => {\n array.fill(0)\n for (const [index, value] of entries) array[index] = value\n}\n\n/** Layer a depth falls in; past the end, the last one. */\nfunction stratumAtDepth(profile: TerrainProfile, depth: number): { index: number; stratum: TerrainStratum; top: number } {\n let top = 0\n for (let index = 0; index < profile.strata.length; index++) {\n const stratum = profile.strata[index]!\n if (depth < top + stratum.thickness - 1e-6) return { index, stratum, top }\n top += stratum.thickness\n }\n const index = profile.strata.length - 1\n const stratum = profile.strata[index]!\n return { index, stratum, top: top - stratum.thickness }\n}\nconst totalThickness = (profile: TerrainProfile): number => profile.strata.reduce((sum, stratum) => sum + stratum.thickness, 0)\n\nexport function createTerrain(options: TerrainOptions): Terrain {\n const [x0, z0, x1, z1] = options.bounds\n const cellSize = options.cellSize ?? 0.1\n const chunkCells = options.chunkCells ?? 32\n const columns = Math.max(1, Math.ceil((x1 - x0) / cellSize))\n const rows = Math.max(1, Math.ceil((z1 - z0) / cellSize))\n const stride = columns + 1\n const vertexCount = stride * (rows + 1)\n const chunksX = Math.ceil(columns / chunkCells)\n const chunksZ = Math.ceil(rows / chunkCells)\n const budget: TerrainBudget = { ...DEFAULT_TERRAIN_BUDGET, ...options.budget }\n const gravity = options.gravity ?? GRAVITY\n const materials = new Map<string, TerrainMaterial>([...TERRAIN_MATERIALS, ...(options.materials ?? [])].map((material) => [material.id, material]))\n const profileMap = new Map<string, TerrainProfile>([...TERRAIN_PROFILES, ...(options.profiles ?? [])].map((profile) => [profile.id, profile]))\n const profileList = [...profileMap.values()]\n for (const profile of profileList) {\n for (const stratum of profile.strata) if (!materials.has(stratum.material)) throw new Error(`game-terrain: profile \"${profile.id}\" uses material \"${stratum.material}\", which has no ground behaviour`)\n }\n const indexOfProfile = new Map(profileList.map((profile, index) => [profile.id, index]))\n const maxDepthOf = profileList.map(totalThickness)\n\n const base = new Float32Array(vertexCount)\n if (options.baseHeight) {\n for (let row = 0; row <= rows; row++) for (let column = 0; column <= columns; column++) base[row * stride + column] = options.baseHeight(x0 + column * cellSize, z0 + row * cellSize)\n }\n const dug = new Float32Array(vertexCount)\n const loose = new Float32Array(vertexCount)\n const scorch = new Float32Array(vertexCount)\n const barBend = new Float32Array(vertexCount)\n const profileIndex = new Uint8Array(vertexCount)\n const touched = new Uint8Array(chunksX * chunksZ)\n const mixed = new Uint8Array(chunksX * chunksZ)\n const dirty = new Set<number>()\n const marks = createMarkStore(budget)\n const debrisStore = createDebrisStore(() => budget.maxDebris)\n const sliding = new Set<number>()\n const burning = new Map<number, number>()\n const random = createRandom(options.seed ?? 1)\n let currentLayout: GroundLayout = options.layout ?? { surface: DEFAULT_PROFILE }\n\n const deformListeners = new Set<(region: TerrainRegion) => void>()\n const emitDeform = (x: number, z: number, radius: number): void => {\n for (const listener of deformListeners) listener({ x, z, radius })\n }\n\n const chunkOfVertex = (column: number, row: number): number => Math.min(chunksZ - 1, Math.floor(row / chunkCells)) * chunksX + Math.min(chunksX - 1, Math.floor(column / chunkCells))\n /** A vertex on a chunk's edge belongs to its neighbours as well. */\n function touchVertex(column: number, row: number): void {\n const chunk = chunkOfVertex(column, row)\n touched[chunk] = 1\n dirty.add(chunk)\n if (column % chunkCells === 0 && column > 0) markChunk(chunk - 1)\n if (row % chunkCells === 0 && row > 0) markChunk(chunk - chunksX)\n if (column % chunkCells === 0 && row % chunkCells === 0 && column > 0 && row > 0) markChunk(chunk - chunksX - 1)\n }\n function markChunk(chunk: number): void {\n touched[chunk] = 1\n dirty.add(chunk)\n }\n\n const profileId = (id: string): number => indexOfProfile.get(id) ?? indexOfProfile.get(DEFAULT_PROFILE) ?? 0\n\n function applyLayout(layout: GroundLayout): void {\n currentLayout = layout\n profileIndex.fill(profileId(layout.surface))\n for (const zone of layout.zones ?? []) {\n const index = profileId(zone.surface)\n const [zx0, zz0, zx1, zz1] = zone.rect\n const column0 = clampIndex(Math.round((zx0 - x0) / cellSize), columns)\n const column1 = clampIndex(Math.round((zx1 - x0) / cellSize), columns)\n const row0 = clampIndex(Math.round((zz0 - z0) / cellSize), rows)\n const row1 = clampIndex(Math.round((zz1 - z0) / cellSize), rows)\n for (let row = row0; row <= row1; row++) profileIndex.fill(index, row * stride + column0, row * stride + column1 + 1)\n }\n for (let chunkZ = 0; chunkZ < chunksZ; chunkZ++) {\n for (let chunkX = 0; chunkX < chunksX; chunkX++) {\n const chunk = chunkZ * chunksX + chunkX\n const first = profileIndex[(chunkZ * chunkCells) * stride + chunkX * chunkCells]\n let isMixed = 0\n const lastRow = Math.min(rows, (chunkZ + 1) * chunkCells)\n const lastColumn = Math.min(columns, (chunkX + 1) * chunkCells)\n for (let row = chunkZ * chunkCells; row <= lastRow && !isMixed; row++) {\n for (let column = chunkX * chunkCells; column <= lastColumn; column++) {\n if (profileIndex[row * stride + column] !== first) {\n isMixed = 1\n break\n }\n }\n }\n mixed[chunk] = isMixed\n dirty.add(chunk)\n }\n }\n }\n\n const vertexHeight = (column: number, row: number): number => {\n const index = row * stride + column\n return base[index]! - dug[index]! + loose[index]!\n }\n const contains = (x: number, z: number): boolean => x >= x0 && x <= x1 && z >= z0 && z <= z1\n\n function heightAt(x: number, z: number): number {\n // beyond the terrain the ground is untouched: no blow can dig it and a piece thrown out lands on it\n if (!contains(x, z)) return options.baseHeight?.(x, z) ?? 0\n const fx = Math.max(0, Math.min(columns - 1e-6, (x - x0) / cellSize))\n const fz = Math.max(0, Math.min(rows - 1e-6, (z - z0) / cellSize))\n const column = fx | 0\n const row = fz | 0\n const tx = fx - column\n const tz = fz - row\n const index = row * stride + column\n const h = (i: number): number => base[i]! - dug[i]! + loose[i]!\n return (h(index) * (1 - tx) + h(index + 1) * tx) * (1 - tz) + (h(index + stride) * (1 - tx) + h(index + stride + 1) * tx) * tz\n }\n\n const vertexOf = (x: number, z: number): { column: number; row: number; index: number } => {\n const column = clampIndex(Math.round((x - x0) / cellSize), columns)\n const row = clampIndex(Math.round((z - z0) / cellSize), rows)\n return { column, row, index: row * stride + column }\n }\n\n function vertexMaterial(column: number, row: number): TerrainMaterial {\n const index = row * stride + column\n return materials.get(stratumAtDepth(profileList[profileIndex[index]!]!, dug[index]!).stratum.material)!\n }\n\n function columnAt(x: number, z: number): TerrainColumn {\n const { index } = vertexOf(x, z)\n const which = profileIndex[index]!\n const profile = profileList[which]!\n const depth = Math.min(maxDepthOf[which]!, dug[index]! + marks.depthAt(x, z))\n const layer = stratumAtDepth(profile, depth)\n return { profile: profile.id, material: layer.stratum.material, stratum: layer.index, depth, remaining: maxDepthOf[which]! - depth, scorch: scorch[index]!, loose: loose[index]! }\n }\n\n /** Removes from a vertex: what is heaped first, then the column, never past its limit. Returns what came off. */\n function removeFromVertex(index: number, amount: number): number {\n const fromLoose = Math.min(loose[index]!, amount)\n loose[index] = loose[index]! - fromLoose\n const fromColumn = Math.min(maxDepthOf[profileIndex[index]!]! - dug[index]!, amount - fromLoose)\n if (fromColumn > 0) dug[index] = dug[index]! + fromColumn\n return fromLoose + Math.max(0, fromColumn)\n }\n /** Adds to a vertex: a soft floor fills what was dug, then heaps; on a rigid one the rubble just heaps. */\n function addToVertex(index: number, amount: number, fillsColumn: boolean): void {\n const filled = fillsColumn ? Math.min(dug[index]!, amount) : 0\n dug[index] = dug[index]! - filled\n loose[index] = loose[index]! + amount - filled\n }\n const isSoftExposed = (index: number): boolean => materials.get(stratumAtDepth(profileList[profileIndex[index]!]!, dug[index]!).stratum.material)!.reposeDegrees !== undefined\n\n /** Digs a lobed bowl into the height field, heaps the rim share around it. */\n function stampBowl(x: number, z: number, radius: number, depth: number, rimVolume: number): void {\n const reach = radius * RIM_REACH\n const column0 = clampIndex(Math.floor((x - reach - x0) / cellSize), columns)\n const column1 = clampIndex(Math.ceil((x + reach - x0) / cellSize), columns)\n const row0 = clampIndex(Math.floor((z - reach - z0) / cellSize), rows)\n const row1 = clampIndex(Math.ceil((z + reach - z0) / cellSize), rows)\n const phaseA = random() * 6.283\n const phaseB = random() * 6.283\n const shapeOf = (px: number, pz: number): number => {\n const angle = Math.atan2(pz - z, px - x)\n return Math.hypot(px - x, pz - z) / (radius * (1 + 0.12 * Math.sin(angle * 5 + phaseA) + 0.06 * Math.sin(angle * 11 + phaseB)))\n }\n let rimWeight = 0\n if (rimVolume > 0) {\n for (let row = row0; row <= row1; row++) {\n for (let column = column0; column <= column1; column++) {\n const q = shapeOf(x0 + column * cellSize, z0 + row * cellSize)\n if (q >= 1 && q < RIM_REACH) rimWeight += Math.sin(((q - 1) / (RIM_REACH - 1)) * Math.PI)\n }\n }\n }\n const cellArea = cellSize * cellSize\n for (let row = row0; row <= row1; row++) {\n for (let column = column0; column <= column1; column++) {\n const q = shapeOf(x0 + column * cellSize, z0 + row * cellSize)\n const index = row * stride + column\n if (q < 1) {\n removeFromVertex(index, depth * (1 - q * q) * (0.92 + random() * 0.16))\n sliding.add(index)\n touchVertex(column, row)\n } else if (q < RIM_REACH && rimWeight > 0) {\n loose[index] = loose[index]! + (rimVolume * Math.sin(((q - 1) / (RIM_REACH - 1)) * Math.PI)) / (rimWeight * cellArea)\n sliding.add(index)\n touchVertex(column, row)\n }\n }\n }\n marks.removeInside(x, z, radius)\n emitDeform(x, z, reach)\n }\n\n function throwPieces(spec: { x: number; y: number; z: number; volume: number; material: TerrainMaterial; energy: number; direction?: readonly number[]; quota: number; bowlRadius: number; blow: TerrainBlow }): void {\n const radius = PIECE_RADIUS[spec.material.debris]\n const pieceVolume = (4 / 3) * Math.PI * radius ** 3\n const count = Math.min(spec.quota, Math.max(1, Math.round(spec.volume / pieceVolume)))\n const mass = Math.max(1e-3, spec.volume * 1500)\n const launch = Math.min(MAX_PIECE_SPEED[spec.blow], Math.sqrt((2 * spec.energy * THROW_SHARE) / mass))\n for (let i = 0; i < count; i++) {\n const angle = random() * 6.283\n const out = spec.bowlRadius * Math.sqrt(random()) * 0.8\n const speed = launch * (0.5 + random() * 0.7)\n const spread = 0.35 + random() * 0.65\n const backX = spec.direction ? -(spec.direction[0] ?? 0) * 0.4 : 0\n const backZ = spec.direction ? -(spec.direction[2] ?? 0) * 0.4 : 0\n debrisStore.throwPiece({\n material: spec.material.id,\n kind: spec.material.debris,\n radius: radius * (0.6 + random() * 0.9),\n position: [spec.x + Math.cos(angle) * out, spec.y + 0.03, spec.z + Math.sin(angle) * out],\n velocity: [(Math.cos(angle) * spread + backX) * speed, (0.6 + random() * 0.7) * speed, (Math.sin(angle) * spread + backZ) * speed],\n spin: [(random() - 0.5) * 14, (random() - 0.5) * 14, (random() - 0.5) * 14],\n })\n }\n }\n\n function strike(blow: TerrainBlow, spec: { x: number; z: number; energy: number; direction?: readonly number[]; contactRadius?: number }): TerrainBlowResult {\n const { x, z } = spec\n const start = columnAt(x, z)\n const profile = profileMap.get(start.profile)!\n const removed: { material: string; volume: number }[] = []\n const point: [number, number, number] = [x, heightAt(x, z), z]\n let energy = spec.energy\n let depth = start.depth\n let radius = 0\n let carved = 0\n const firstMaterial = materials.get(start.material)!\n if (start.loose <= 0) {\n for (;;) {\n const layer = stratumAtDepth(profile, depth)\n const bottom = layer.top + layer.stratum.thickness\n const room = bottom - depth\n if (room <= 1e-6) break\n const material = materials.get(layer.stratum.material)!\n const response = material.hits[blow]\n if (!response || energy < (response.thresholdJoules ?? 0)) break\n const bars = layer.stratum.reinforcement\n const pastCover = bars !== undefined && depth - layer.top >= bars.cover - 1e-6\n const specificEnergy = response.specificEnergy * (pastCover ? bars.resistance : 1)\n const limit = bars && !pastCover ? Math.min(room, layer.top + bars.cover - depth) : room\n const volume = energy / specificEnergy\n const wanted = Math.cbrt((2 * volume) / (Math.PI * response.aspect))\n const wantedDepth = wanted * response.aspect\n const takenDepth = Math.min(wantedDepth, limit)\n const takenRadius = takenDepth < wantedDepth ? takenDepth / response.aspect : wanted\n const takenVolume = (Math.PI * takenRadius * takenRadius * takenDepth) / 2\n energy -= takenVolume * specificEnergy\n depth += takenDepth\n carved += takenDepth\n radius = Math.max(radius, takenRadius, response.minRadius ?? 0, spec.contactRadius ?? 0)\n const last = removed[removed.length - 1]\n if (last?.material === material.id) (last as { volume: number }).volume += takenVolume\n else removed.push({ material: material.id, volume: takenVolume })\n if (energy <= 1e-6 || takenDepth >= wantedDepth - 1e-9) break\n }\n } else {\n // a loose heap has no strength: it takes the blow as soft ground before the column does\n const response = firstMaterial.hits[blow]\n if (response && energy >= (response.thresholdJoules ?? 0)) {\n const volume = energy / response.specificEnergy\n radius = Math.cbrt((2 * volume) / (Math.PI * response.aspect))\n carved = radius * response.aspect\n removed.push({ material: firstMaterial.id, volume })\n }\n }\n const collapsed = loadBars(blow, spec.energy, x, z, profile)\n if (radius <= 0) return { point, radius: 0, depth: 0, totalDepth: columnAt(x, z).depth, removed: [], exposed: start.material, atLimit: start.remaining <= 1e-6, rebarExposed: rebarShowing(profile, start.depth), collapsed, fine: true }\n\n // a rigid floor cannot go down any more where it is already deep: the next blow breaks the edge of the hole, so a hole in a slab opens as it deepens\n if (firstMaterial.reposeDegrees === undefined && start.loose <= 0) radius *= 1 + RIGID_WIDENING * (start.depth / maxDepthOfProfile(profile))\n\n const volumeTotal = removed.reduce((sum, entry) => sum + entry.volume, 0)\n const fine = radius < cellSize * FINE_CELLS\n if (fine) depositMark({ x, z, radius, depth: carved, blow, profile, cap: maxDepthOfProfile(profile) })\n else {\n const rimShare = materials.get(removed[0]!.material)!.rimShare ?? 0\n stampBowl(x, z, radius, carved, volumeTotal * rimShare)\n }\n let quota = budget.maxDebrisPerBlow\n for (const entry of removed) {\n const material = materials.get(entry.material)!\n const thrown = entry.volume * (1 - (fine ? 0 : (material.rimShare ?? 0)))\n if (thrown <= 0 || quota <= 0) continue\n const share = Math.max(1, Math.round((quota * entry.volume) / volumeTotal))\n throwPieces({ x, y: point[1], z, volume: thrown, material, energy: spec.energy * (entry.volume / volumeTotal), direction: spec.direction, quota: share, bowlRadius: radius, blow })\n quota -= share\n }\n const after = columnAt(x, z)\n return { point, radius, depth: carved, totalDepth: after.depth, removed, exposed: after.material, atLimit: after.remaining <= 1e-4, rebarExposed: rebarShowing(profile, after.depth), collapsed, fine }\n }\n\n /**\n * A blow loads the bars that are bare around it: they bend, and past their limit they give way. The bowl a blow would open tells how far it reaches. Where the slab has nothing under it, the floor goes with them.\n */\n function loadBars(blow: TerrainBlow, energy: number, x: number, z: number, profile: TerrainProfile): boolean {\n const bars = profile.strata.find((stratum) => stratum.reinforcement)\n if (!bars?.reinforcement) return false\n const response = materials.get(bars.material)!.hits[blow]\n if (!response || energy < (response.thresholdJoules ?? 0)) return false\n const yieldJoules = bars.reinforcement.yieldJoules ?? DEFAULT_BAR_YIELD_JOULES\n let cover = bars.reinforcement.cover\n for (const stratum of profile.strata) {\n if (stratum === bars) break\n cover += stratum.thickness\n }\n const reach = Math.max(cellSize * FINE_CELLS, Math.cbrt((2 * energy) / response.specificEnergy / (Math.PI * response.aspect)) * (1 + RIGID_WIDENING))\n const column0 = clampIndex(Math.floor((x - reach - x0) / cellSize), columns)\n const column1 = clampIndex(Math.ceil((x + reach - x0) / cellSize), columns)\n const row0 = clampIndex(Math.floor((z - reach - z0) / cellSize), rows)\n const row1 = clampIndex(Math.ceil((z + reach - z0) / cellSize), rows)\n const limit = maxDepthOfProfile(profile)\n let collapsed = false\n for (let row = row0; row <= row1; row++) {\n for (let column = column0; column <= column1; column++) {\n const index = row * stride + column\n if (dug[index]! < cover) continue\n const q = Math.hypot(x0 + column * cellSize - x, z0 + row * cellSize - z) / reach\n if (q >= 1) continue\n barBend[index] = barBend[index]! + (energy / yieldJoules) * (1 - q * q)\n touchVertex(column, row)\n if (barBend[index]! >= 1 && profile.drop !== undefined && dug[index]! >= limit * COLLAPSE_DEPTH_SHARE && dug[index]! < limit + profile.drop) {\n dug[index] = limit + profile.drop\n collapsed = true\n }\n }\n }\n if (collapsed) emitDeform(x, z, reach)\n // what gave way takes down what was already bending around it\n if (collapsed && profile.drop !== undefined) {\n for (let row = row0; row <= row1; row++) {\n for (let column = column0; column <= column1; column++) {\n const index = row * stride + column\n if (barBend[index]! >= COLLAPSE_SPREAD_BEND && dug[index]! < limit + profile.drop) {\n dug[index] = limit + profile.drop\n touchVertex(column, row)\n }\n }\n }\n }\n return collapsed\n }\n\n const maxDepthOfProfile = (profile: TerrainProfile): number => maxDepthOf[indexOfProfile.get(profile.id)!]!\n function rebarShowing(profile: TerrainProfile, depth: number): boolean {\n const layer = stratumAtDepth(profile, depth)\n return layer.stratum.reinforcement !== undefined && depth - layer.top >= layer.stratum.reinforcement.cover - 1e-6\n }\n\n function depositMark(spec: { x: number; z: number; radius: number; depth: number; blow: TerrainBlow; profile: TerrainProfile; cap: number }): void {\n const { x, z, radius, depth, blow, profile, cap } = spec\n const dugHere = dug[vertexOf(x, z).index]!\n const existing = marks.near(x, z, radius)\n let mark: TerrainMark\n if (existing) {\n existing.radius = Math.hypot(existing.radius, radius)\n existing.depth = Math.min(cap - dugHere, existing.depth + depth)\n existing.count++\n existing.blow = blow\n mark = existing\n } else {\n mark = marks.add({ x, z, radius, depth: Math.min(cap - dugHere, depth), blow, material: '' })\n }\n mark.material = stratumAtDepth(profile, dugHere + mark.depth - 1e-6).stratum.material\n if (mark.radius >= cellSize * FINE_CELLS || mark.depth >= cellSize * FINE_DEPTH_CELLS) {\n const bowlRadius = Math.max(mark.radius, cellSize * FINE_CELLS)\n const bowlDepth = mark.depth\n marks.remove(mark)\n stampBowl(mark.x, mark.z, bowlRadius, bowlDepth, 0)\n }\n }\n\n function burn(spec: { x: number; z: number; radius: number; temperature: number; seconds: number }): void {\n if (spec.temperature < FLAME_MINIMUM) return\n const column0 = clampIndex(Math.floor((spec.x - spec.radius - x0) / cellSize), columns)\n const column1 = clampIndex(Math.ceil((spec.x + spec.radius - x0) / cellSize), columns)\n const row0 = clampIndex(Math.floor((spec.z - spec.radius - z0) / cellSize), rows)\n const row1 = clampIndex(Math.ceil((spec.z + spec.radius - z0) / cellSize), rows)\n for (let row = row0; row <= row1; row++) {\n for (let column = column0; column <= column1; column++) {\n if (Math.hypot(x0 + column * cellSize - spec.x, z0 + row * cellSize - spec.z) > spec.radius) continue\n burnVertex(column, row, spec.seconds)\n }\n }\n }\n\n function burnVertex(column: number, row: number, seconds: number): void {\n const index = row * stride + column\n const material = vertexMaterial(column, row)\n const response = material.fire\n if (!response) return\n const before = scorch[index]!\n scorch[index] = Math.max(before, Math.min(response.maxScorch, before + response.scorchPerSecond * seconds))\n if (response.burnsAway) removeFromVertex(index, response.burnsAway * seconds)\n if (scorch[index] !== before || response.burnsAway) touchVertex(column, row)\n if (response.flammable) ignite(x0 + column * cellSize, z0 + row * cellSize)\n }\n\n const fireKey = (x: number, z: number): number => Math.floor((z - z0) / FIRE_CELL) * 65536 + Math.floor((x - x0) / FIRE_CELL)\n function ignite(x: number, z: number): void {\n const key = fireKey(x, z)\n if (burning.has(key) || burning.size >= budget.maxBurningCells) return\n const index = vertexOf(x, z).index\n if (scorch[index]! >= 1) return\n burning.set(key, FIRE_SECONDS)\n }\n\n function updateFire(dt: number): void {\n for (const [key, remaining] of [...burning]) {\n const cellRow = Math.floor(key / 65536)\n const cellColumn = key - cellRow * 65536\n const x = x0 + (cellColumn + 0.5) * FIRE_CELL\n const z = z0 + (cellRow + 0.5) * FIRE_CELL\n burn({ x, z, radius: FIRE_CELL * 0.75, temperature: 600, seconds: dt })\n if (random() < FIRE_SPREAD_PER_SECOND * dt) {\n const angle = Math.floor(random() * 4) * (Math.PI / 2)\n const nextX = x + Math.cos(angle) * FIRE_CELL\n const nextZ = z + Math.sin(angle) * FIRE_CELL\n if (contains(nextX, nextZ)) {\n const { column, row, index } = vertexOf(nextX, nextZ)\n if (vertexMaterial(column, row).fire?.flammable && scorch[index]! < 1) ignite(nextX, nextZ)\n }\n }\n if (remaining - dt <= 0) burning.delete(key)\n else burning.set(key, remaining - dt)\n }\n }\n\n function updateSlides(): void {\n if (sliding.size === 0) return\n let budgetLeft = budget.maxSlideCellsPerFrame\n let minX = Infinity\n let minZ = Infinity\n let maxX = -Infinity\n let maxZ = -Infinity\n for (const index of sliding) {\n if (budgetLeft-- <= 0) break\n sliding.delete(index)\n const column = index % stride\n const row = (index - column) / stride\n if (!isSoftExposed(index)) continue\n const material = vertexMaterial(column, row)\n const slope = Math.tan(((material.reposeDegrees ?? 90) * Math.PI) / 180) * cellSize\n const height = vertexHeight(column, row)\n const neighbours: [number, number][] = [[column - 1, row], [column + 1, row], [column, row - 1], [column, row + 1]]\n for (const [nextColumn, nextRow] of neighbours) {\n if (nextColumn < 0 || nextRow < 0 || nextColumn > columns || nextRow > rows) continue\n const excess = height - vertexHeight(nextColumn, nextRow) - slope\n if (excess <= SLIDE_EPSILON) continue\n const moved = removeFromVertex(index, excess * SLIDE_SHARE)\n if (moved <= 0) continue\n const next = nextRow * stride + nextColumn\n addToVertex(next, moved, isSoftExposed(next))\n sliding.add(index)\n sliding.add(next)\n touchVertex(column, row)\n touchVertex(nextColumn, nextRow)\n const px = x0 + column * cellSize\n const pz = z0 + row * cellSize\n minX = Math.min(minX, px)\n maxX = Math.max(maxX, px)\n minZ = Math.min(minZ, pz)\n maxZ = Math.max(maxZ, pz)\n }\n }\n if (minX <= maxX) emitDeform((minX + maxX) / 2, (minZ + maxZ) / 2, Math.hypot(maxX - minX, maxZ - minZ) / 2 + cellSize * 2)\n }\n\n /** A piece of soft ground joins the height where it stops, so that what is thrown out piles up and can be walked on. */\n function settle(piece: TerrainDebris): boolean {\n const material = materials.get(piece.material)\n if (!material || material.reposeDegrees === undefined) return false\n if (!contains(piece.position[0], piece.position[2])) return true\n const { index, column, row } = vertexOf(piece.position[0], piece.position[2])\n addToVertex(index, ((4 / 3) * Math.PI * piece.radius ** 3) / (cellSize * cellSize), false)\n sliding.add(index)\n touchVertex(column, row)\n return true\n }\n\n function applyHit(hit: Hit): TerrainBlowResult | null {\n const [x, y, z] = hit.point\n switch (hit.type) {\n case 'ballistic':\n case 'blunt':\n case 'slash': {\n if (!hit.energy) return null\n const contactRadius = hit.type === 'blunt' ? hit.radius : undefined\n return strike(hit.type, { x, z, energy: hit.energy, ...(hit.direction ? { direction: hit.direction } : {}), ...(contactRadius !== undefined ? { contactRadius } : {}) })\n }\n case 'explosive': {\n if (!hit.energy) return null\n const above = Math.max(0, y - heightAt(x, z))\n const reach = (hit.radius ?? 1) * BLAST_HEIGHT_REACH\n if (above >= reach) return null\n return strike('explosive', { x, z, energy: hit.energy * (1 - above / reach) ** 2 })\n }\n case 'fire':\n case 'heat':\n if (y - heightAt(x, z) > (hit.radius ?? 0.2) + FLAME_REACH) return null\n burn({ x, z, radius: hit.radius ?? 0.2, temperature: hit.temperature ?? 0, seconds: hit.duration ?? 0.016 })\n return null\n default:\n return null\n }\n }\n\n function raycast(origin: readonly number[], direction: readonly number[], maxDistance: number): { point: [number, number, number]; distance: number; normal: [number, number, number] } | null {\n const [ox = 0, oy = 0, oz = 0] = origin\n const [dx = 0, dy = 0, dz = 0] = direction\n const step = cellSize * 0.75\n let previous = 0\n for (let t = 0; t <= maxDistance; t += step) {\n const x = ox + dx * t\n const z = oz + dz * t\n if (contains(x, z) && oy + dy * t <= heightAt(x, z)) {\n let low = previous\n let high = t\n for (let i = 0; i < 6; i++) {\n const middle = (low + high) / 2\n if (oy + dy * middle <= heightAt(ox + dx * middle, oz + dz * middle)) high = middle\n else low = middle\n }\n const px = ox + dx * high\n const pz = oz + dz * high\n const gx = heightAt(px + cellSize, pz) - heightAt(px - cellSize, pz)\n const gz = heightAt(px, pz + cellSize) - heightAt(px, pz - cellSize)\n const length = Math.hypot(gx, 2 * cellSize, gz)\n return { point: [px, oy + dy * high, pz], distance: high, normal: [-gx / length, (2 * cellSize) / length, -gz / length] }\n }\n previous = t\n }\n return null\n }\n\n function chunk(index: number): TerrainChunk {\n const chunkZ = Math.floor(index / chunksX)\n const chunkX = index - chunkZ * chunksX\n return { index, column: chunkX * chunkCells, row: chunkZ * chunkCells, cells: chunkCells, pristine: !touched[index] && !mixed[index] && !options.baseHeight }\n }\n\n function reset(): void {\n dug.fill(0)\n loose.fill(0)\n scorch.fill(0)\n barBend.fill(0)\n touched.fill(0)\n marks.clear()\n debrisStore.clear()\n sliding.clear()\n burning.clear()\n applyLayout(currentLayout)\n }\n\n applyLayout(currentLayout)\n\n return {\n bounds: options.bounds,\n cellSize,\n columns,\n rows,\n stride,\n chunkCells,\n chunksX,\n chunksZ,\n budget,\n dug,\n loose,\n scorch,\n barBend,\n profileIndex,\n profileList,\n material: (id) => {\n const material = materials.get(id)\n if (!material) throw new Error(`game-terrain: unknown material \"${id}\"`)\n return material\n },\n layout: () => currentLayout,\n setLayout(layout) {\n currentLayout = layout\n reset()\n },\n heightAt,\n vertexHeight,\n vertexMaterial,\n columnAt,\n contains,\n raycast,\n strike,\n burn,\n applyHit,\n onDeform(listener) {\n deformListeners.add(listener)\n return () => deformListeners.delete(listener)\n },\n update(dt) {\n debrisStore.update(dt, { heightAt, gravity, settle })\n updateSlides()\n updateFire(dt)\n },\n drainDirtyChunks(max = budget.maxDirtyChunksPerFrame) {\n const taken: TerrainChunk[] = []\n for (const index of dirty) {\n if (taken.length >= max) break\n dirty.delete(index)\n taken.push(chunk(index))\n }\n return taken\n },\n chunk,\n marks: () => marks.list,\n debris: () => debrisStore.list,\n burningPoints: () => [...burning.keys()].map((key) => {\n const cellRow = Math.floor(key / 65536)\n const cellColumn = key - cellRow * 65536\n return [x0 + (cellColumn + 0.5) * FIRE_CELL, z0 + (cellRow + 0.5) * FIRE_CELL] as const\n }),\n get marksVersion() {\n return marks.version\n },\n stats: () => ({ marks: marks.list.length, debris: debrisStore.list.length, debrisMoving: debrisStore.list.filter((piece) => !piece.atRest).length, dirtyChunks: dirty.size, burning: burning.size }),\n reset,\n serialize(): TerrainSnapshot {\n return { layout: currentLayout, dug: sparse(dug), loose: sparse(loose), scorch: sparse(scorch), barBend: sparse(barBend), marks: marks.list.map((mark) => ({ ...mark })) }\n },\n load(snapshot) {\n currentLayout = snapshot.layout\n reset()\n fillSparse(dug, snapshot.dug)\n fillSparse(loose, snapshot.loose)\n fillSparse(scorch, snapshot.scorch)\n fillSparse(barBend, snapshot.barBend ?? [])\n marks.load(snapshot.marks)\n for (let chunkIndex = 0; chunkIndex < touched.length; chunkIndex++) markChunk(chunkIndex)\n },\n }\n}\n","import type { DestructibleImpl, DestructibleSpec, DestructionEvent, Hit, ObjectState } from '@adatechnology/game-contracts'\nimport type { Terrain, TerrainBlowResult } from './types'\n\nconst PART_ID = 'ground'\nconst PART_DEPTH = 3\nconst RAY_BACKOFF = 1\n\nexport interface TerrainImplOptions {\n readonly id: string\n readonly name?: string\n /** Every blow that left its mark, with what it did. */\n readonly onBlow?: (result: TerrainBlowResult, hit: Hit) => void\n}\n\n/**\n * The ground as an object of the destruction world (`DestructionWorld.register`): shots, blows, blasts and flames reach it through the world's own raycast and blast like anything else.\n * The collision part is a flat box; a ray that enters it goes on to the real surface, so a round fired into a crater lands on its floor.\n */\nexport function createTerrainImpl(terrain: Terrain, options: TerrainImplOptions): DestructibleImpl {\n const { id } = options\n const [x0, z0, x1, z1] = terrain.bounds\n const spec = (): DestructibleSpec => ({\n name: options.name ?? 'Ground',\n parts: [\n {\n id: PART_ID,\n material: terrain.columnAt((x0 + x1) / 2, (z0 + z1) / 2).material,\n shape: { kind: 'box', size: [x1 - x0, PART_DEPTH, z1 - z0] },\n position: [(x0 + x1) / 2, -PART_DEPTH / 2, (z0 + z1) / 2],\n hp: 1e12,\n anchored: true,\n tags: ['terrain'],\n },\n ],\n joints: [],\n })\n const resolve = (hit: Hit): Hit => {\n if (hit.type !== 'ballistic' && hit.type !== 'blunt' && hit.type !== 'slash') return hit\n if (!hit.direction) return { ...hit, point: [hit.point[0], terrain.heightAt(hit.point[0], hit.point[2]), hit.point[2]] }\n const [dx, dy, dz] = hit.direction\n const from = [hit.point[0] - dx * RAY_BACKOFF, hit.point[1] - dy * RAY_BACKOFF, hit.point[2] - dz * RAY_BACKOFF]\n const onGround = terrain.raycast(from, hit.direction, RAY_BACKOFF + PART_DEPTH)\n return onGround ? { ...hit, point: onGround.point } : hit\n }\n return {\n id,\n ...(options.name ? { name: options.name } : {}),\n describe: spec,\n hit(hit): DestructionEvent[] {\n const landed = resolve(hit)\n const result = terrain.applyHit(landed)\n if (!result || result.radius <= 0) return []\n options.onBlow?.(result, landed)\n return [{ type: 'damage', object: id, time: 0, part: PART_ID, amount: 0, hp: 1e12, damageType: hit.type, ...(hit.source ? { source: hit.source } : {}) }]\n },\n update(dt) {\n terrain.update(dt)\n return []\n },\n state(): ObjectState {\n return {\n id,\n position: [0, 0, 0],\n rotation: [0, 0, 0, 1],\n parts: [],\n joints: [],\n groups: [[PART_ID]],\n destroyed: false,\n }\n },\n reset: () => terrain.reset(),\n serialize: () => terrain.serialize(),\n load: (data) => terrain.load(data as ReturnType<Terrain['serialize']>),\n }\n}\n","import type { GroundLayout, Hit } from '@adatechnology/game-contracts'\n\nexport type { GroundLayout, GroundZone } from '@adatechnology/game-contracts'\n\n/** The blows that remove ground. Fire and heat char it instead (`TerrainMaterial.fire`). */\nexport type TerrainBlow = 'ballistic' | 'blunt' | 'slash' | 'explosive'\n\n/** What one kind of blow does to a material. */\nexport interface TerrainBlowResponse {\n /** Joules it takes to remove one cubic metre. */\n readonly specificEnergy: number\n /** Depth over radius of the bowl it leaves: a soft ground craters deep, a hard one spalls wide and shallow. */\n readonly aspect: number\n /** A blow under this many joules leaves nothing (a punch on a slab). */\n readonly thresholdJoules?: number\n /** The bowl is never narrower: a tile comes off as a piece, not as the size of the bullet. */\n readonly minRadius?: number\n}\n\nexport type TerrainDebrisKind = 'clods' | 'chips' | 'shards' | 'splinters' | 'dust'\n\n/** How a material of the destruction catalogue behaves as ground. `id` is the catalogue's. */\nexport interface TerrainMaterial {\n readonly id: string\n readonly hits: Partial<Record<TerrainBlow, TerrainBlowResponse>>\n readonly debris: TerrainDebrisKind\n /** Share of what a blow removes that piles up on the rim; the rest is thrown. Rigid materials have none. */\n readonly rimShare?: number\n /** Steepest slope in degrees it holds; loose ground slides until it is back to it. */\n readonly reposeDegrees?: number\n readonly fire?: TerrainFireResponse\n /** Linear rgb, 0..1, of the material where it is exposed. */\n readonly color: readonly [number, number, number]\n /** Surface pattern a renderer draws while the stratum is intact (`TERRAIN_PATTERNS`). */\n readonly pattern?: TerrainPattern\n}\n\nexport interface TerrainFireResponse {\n /** How black it gets, 0..1: concrete only soots, wood and turf char through. */\n readonly maxScorch: number\n /** Scorch gained per second in a flame. */\n readonly scorchPerSecond: number\n /** Metres per second the flame eats away (wood char). */\n readonly burnsAway?: number\n /** Catches and carries the fire to the next cells on its own. */\n readonly flammable?: boolean\n}\n\nexport const TERRAIN_PATTERNS = ['plain', 'grass', 'soil', 'sand', 'asphalt', 'concrete', 'tile', 'planks', 'stone'] as const\nexport type TerrainPattern = (typeof TERRAIN_PATTERNS)[number]\n\n/** One layer of a column, from the top down. */\nexport interface TerrainStratum {\n /** A `TerrainMaterial.id`. */\n readonly material: string\n /** Metres. */\n readonly thickness: number\n /** Bars inside the layer: exposed at `cover`, they make the digging `resistance` times harder. */\n readonly reinforcement?: {\n readonly material: string\n readonly cover: number\n readonly spacing: number\n readonly resistance: number\n /** Joules on one spot of bare bars before they give way (default `DEFAULT_BAR_YIELD_JOULES`). */\n readonly yieldJoules?: number\n }\n}\n\n/** What a column of ground is made of. The strata end at the digging limit: under them nothing is removed. */\nexport interface TerrainProfile {\n readonly id: string\n readonly strata: readonly TerrainStratum[]\n /** A slab with nothing under it: where its bars give way the floor opens, and the ground is this many metres further down (the floor below). Without it the ground under the slab holds it up. */\n readonly drop?: number\n}\n\nexport interface TerrainBudget {\n /** Side in metres of the squares that hold a limited number of marks. */\n readonly markAreaSize: number\n readonly maxMarksPerArea: number\n readonly maxMarks: number\n /** Chunks a renderer redraws per frame; the rest wait. */\n readonly maxDirtyChunksPerFrame: number\n readonly maxDebris: number\n /** Thrown pieces of one blow. */\n readonly maxDebrisPerBlow: number\n /** Cells checked for sliding per frame. */\n readonly maxSlideCellsPerFrame: number\n /** Cells on fire at once. */\n readonly maxBurningCells: number\n}\n\nexport interface TerrainOptions {\n /** World rectangle `[x0, z0, x1, z1]` in metres. */\n readonly bounds: readonly [number, number, number, number]\n /** Metres per cell (default 0.1). */\n readonly cellSize?: number\n /** Cells per side of a chunk (default 32). */\n readonly chunkCells?: number\n /** Which profile is where. */\n readonly layout?: GroundLayout\n /** Extra or overriding profiles, by id. */\n readonly profiles?: readonly TerrainProfile[]\n /** Extra or overriding materials, by id. */\n readonly materials?: readonly TerrainMaterial[]\n readonly budget?: Partial<TerrainBudget>\n /** Height of the untouched ground (default flat at 0). */\n readonly baseHeight?: (x: number, z: number) => number\n /** Metres per second squared. */\n readonly gravity?: number\n readonly seed?: number\n}\n\n/** A fine mark: a bullet pock or a chip, smaller than a cell. It grows with the blows on it until it is dug into the height field. */\nexport interface TerrainMark {\n readonly id: number\n x: number\n z: number\n radius: number\n depth: number\n /** The material the mark shows at the bottom. */\n material: string\n blow: TerrainBlow\n /** Blows and marks merged into this one. */\n count: number\n /** Order of creation: the oldest is the one recycled. */\n born: number\n}\n\nexport interface TerrainDebris {\n readonly id: number\n readonly material: string\n readonly kind: TerrainDebrisKind\n readonly radius: number\n readonly position: [number, number, number]\n readonly velocity: [number, number, number]\n readonly spin: [number, number, number]\n atRest: boolean\n bounces: number\n /** Order of creation: the oldest is the one recycled. */\n readonly born: number\n}\n\n/** What a blow did. */\nexport interface TerrainBlowResult {\n readonly point: readonly [number, number, number]\n /** Bowl radius in metres; 0 when the blow left nothing. */\n readonly radius: number\n /** Metres removed at the point. */\n readonly depth: number\n /** Metres under the untouched surface the point is now. */\n readonly totalDepth: number\n /** Materials removed, top first, with the cubic metres of each. */\n readonly removed: readonly { readonly material: string; readonly volume: number }[]\n /** Material now exposed at the point. */\n readonly exposed: string\n /** The column has no more to give here: the slab's bottom, the end of the rock. */\n readonly atLimit: boolean\n /** Reinforcement is showing at the point. */\n readonly rebarExposed: boolean\n /** The bars gave way here and the slab opened (`TerrainProfile.drop`). */\n readonly collapsed: boolean\n /** Left a fine mark (`true`) or dug the height field (`false`). */\n readonly fine: boolean\n}\n\nexport interface TerrainRegion {\n readonly x: number\n readonly z: number\n readonly radius: number\n}\n\nexport interface TerrainColumn {\n readonly profile: string\n readonly material: string\n readonly stratum: number\n /** Metres under the untouched surface. */\n readonly depth: number\n /** Metres that can still be dug here. */\n readonly remaining: number\n readonly scorch: number\n readonly loose: number\n}\n\nexport interface TerrainStats {\n readonly marks: number\n readonly debris: number\n readonly debrisMoving: number\n readonly dirtyChunks: number\n readonly burning: number\n}\n\nexport interface TerrainChunk {\n readonly index: number\n /** First column and row of the chunk's vertices. */\n readonly column: number\n readonly row: number\n readonly cells: number\n /** True while nothing touched it and it has one profile: one flat quad draws it. */\n readonly pristine: boolean\n}\n\nexport interface Terrain {\n readonly bounds: readonly [number, number, number, number]\n readonly cellSize: number\n readonly columns: number\n readonly rows: number\n /** Vertices per row. */\n readonly stride: number\n readonly chunkCells: number\n readonly chunksX: number\n readonly chunksZ: number\n readonly budget: TerrainBudget\n /** Per vertex: metres removed under the untouched surface. */\n readonly dug: Float32Array\n /** Per vertex: metres of loose ground heaped on top. */\n readonly loose: Float32Array\n /** Per vertex: 0..1, how burnt. */\n readonly scorch: Float32Array\n /** Per vertex: how far the bare bars have given, 0 straight, 1 or more gone. */\n readonly barBend: Float32Array\n /** Per vertex: index in `profileList`. */\n readonly profileIndex: Uint8Array\n readonly profileList: readonly TerrainProfile[]\n material(id: string): TerrainMaterial\n layout(): GroundLayout\n setLayout(layout: GroundLayout): void\n /** Height at (x, z) as things stand on it. */\n heightAt(x: number, z: number): number\n /** Height of vertex (column, row). */\n vertexHeight(column: number, row: number): number\n /** Material exposed at a vertex. */\n vertexMaterial(column: number, row: number): TerrainMaterial\n columnAt(x: number, z: number): TerrainColumn\n contains(x: number, z: number): boolean\n /** First point of the ground along a ray, or null. */\n raycast(origin: readonly number[], direction: readonly number[], maxDistance: number): { point: [number, number, number]; distance: number; normal: [number, number, number] } | null\n /** A blow at (x, z). `energy` in joules, `direction` where it travels (it throws the pieces back along it). */\n strike(blow: TerrainBlow, spec: { x: number; z: number; energy: number; direction?: readonly number[]; contactRadius?: number }): TerrainBlowResult\n /** A flame over a disc for `seconds`. */\n burn(spec: { x: number; z: number; radius: number; temperature: number; seconds: number }): void\n /** Applies a world hit (`Hit` of the destruction contract); null when it does nothing to the ground. */\n applyHit(hit: Hit): TerrainBlowResult | null\n /** Follow the ground changing: `region` is the disc it changed in. What rests there has lost its support and must look again. Returns the unsubscribe function. */\n onDeform(listener: (region: TerrainRegion) => void): () => void\n /** Moves the pieces, the sliding ground and the fire. */\n update(dt: number): void\n /** Takes up to the budget's chunks that changed since the last call. */\n drainDirtyChunks(max?: number): TerrainChunk[]\n chunk(index: number): TerrainChunk\n marks(): readonly TerrainMark[]\n debris(): readonly TerrainDebris[]\n /** Cells on fire now, as world points. */\n burningPoints(): readonly (readonly [number, number])[]\n /** Goes up when the marks change. */\n readonly marksVersion: number\n stats(): TerrainStats\n /** Back to the untouched ground. */\n reset(): void\n serialize(): TerrainSnapshot\n load(snapshot: TerrainSnapshot): void\n}\n\nexport interface TerrainSnapshot {\n readonly layout: GroundLayout\n readonly dug: readonly (readonly [number, number])[]\n readonly loose: readonly (readonly [number, number])[]\n readonly scorch: readonly (readonly [number, number])[]\n readonly barBend?: readonly (readonly [number, number])[]\n readonly marks: readonly TerrainMark[]\n}\n"],"mappings":";AAGO,IAAM,oBAAgD;AAAA,EAC3D;AAAA,IACE,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,eAAe;AAAA,IACf,OAAO,CAAC,MAAM,KAAK,IAAI;AAAA,IACvB,SAAS;AAAA,IACT,MAAM;AAAA,MACJ,WAAW,EAAE,gBAAgB,KAAK,QAAQ,IAAI;AAAA,MAC9C,OAAO,EAAE,gBAAgB,KAAK,QAAQ,KAAK,iBAAiB,GAAG;AAAA,MAC/D,OAAO,EAAE,gBAAgB,KAAK,QAAQ,IAAI;AAAA,MAC1C,WAAW,EAAE,gBAAgB,KAAK,QAAQ,KAAK;AAAA,IACjD;AAAA,IACA,MAAM,EAAE,WAAW,GAAG,iBAAiB,MAAM,WAAW,KAAK;AAAA,EAC/D;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,eAAe;AAAA,IACf,OAAO,CAAC,KAAK,MAAM,IAAI;AAAA,IACvB,SAAS;AAAA,IACT,MAAM;AAAA,MACJ,WAAW,EAAE,gBAAgB,KAAK,QAAQ,IAAI;AAAA,MAC9C,OAAO,EAAE,gBAAgB,KAAK,QAAQ,KAAK,iBAAiB,GAAG;AAAA,MAC/D,OAAO,EAAE,gBAAgB,KAAK,QAAQ,IAAI;AAAA,MAC1C,WAAW,EAAE,gBAAgB,KAAK,QAAQ,KAAK;AAAA,IACjD;AAAA,IACA,MAAM,EAAE,WAAW,KAAK,iBAAiB,KAAK;AAAA,EAChD;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,eAAe;AAAA,IACf,OAAO,CAAC,MAAM,KAAK,GAAG;AAAA,IACtB,SAAS;AAAA,IACT,MAAM;AAAA,MACJ,WAAW,EAAE,gBAAgB,MAAO,QAAQ,IAAI;AAAA,MAChD,OAAO,EAAE,gBAAgB,KAAK,QAAQ,KAAK,iBAAiB,GAAG;AAAA,MAC/D,OAAO,EAAE,gBAAgB,MAAO,QAAQ,IAAI;AAAA,MAC5C,WAAW,EAAE,gBAAgB,KAAK,QAAQ,KAAK;AAAA,IACjD;AAAA,IACA,MAAM,EAAE,WAAW,KAAK,iBAAiB,KAAK;AAAA,EAChD;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,eAAe;AAAA,IACf,OAAO,CAAC,MAAM,MAAM,IAAI;AAAA,IACxB,SAAS;AAAA,IACT,MAAM;AAAA,MACJ,WAAW,EAAE,gBAAgB,KAAK,QAAQ,IAAI;AAAA,MAC9C,OAAO,EAAE,gBAAgB,KAAK,QAAQ,KAAK,iBAAiB,IAAI;AAAA,MAChE,OAAO,EAAE,gBAAgB,KAAK,QAAQ,KAAK,iBAAiB,IAAI;AAAA,MAChE,WAAW,EAAE,gBAAgB,KAAK,QAAQ,KAAK;AAAA,IACjD;AAAA,IACA,MAAM,EAAE,WAAW,KAAK,iBAAiB,KAAK;AAAA,EAChD;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR,OAAO,CAAC,MAAM,MAAM,KAAK;AAAA,IACzB,SAAS;AAAA,IACT,MAAM;AAAA,MACJ,WAAW,EAAE,gBAAgB,KAAK,QAAQ,KAAK,WAAW,KAAK;AAAA,MAC/D,OAAO,EAAE,gBAAgB,KAAK,QAAQ,KAAK,iBAAiB,IAAI;AAAA,MAChE,OAAO,EAAE,gBAAgB,KAAK,QAAQ,KAAK,iBAAiB,IAAI;AAAA,MAChE,WAAW,EAAE,gBAAgB,KAAK,QAAQ,KAAK;AAAA,IACjD;AAAA,IACA,MAAM,EAAE,WAAW,MAAM,iBAAiB,KAAK,WAAW,KAAQ;AAAA,EACpE;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR,OAAO,CAAC,MAAM,MAAM,IAAI;AAAA,IACxB,SAAS;AAAA,IACT,MAAM;AAAA,MACJ,WAAW,EAAE,gBAAgB,MAAO,QAAQ,MAAM,WAAW,MAAM;AAAA,MACnE,OAAO,EAAE,gBAAgB,KAAK,QAAQ,MAAM,iBAAiB,IAAI;AAAA,MACjE,OAAO,EAAE,gBAAgB,KAAK,QAAQ,KAAK,iBAAiB,IAAI;AAAA,MAChE,WAAW,EAAE,gBAAgB,MAAO,QAAQ,KAAK;AAAA,IACnD;AAAA,IACA,MAAM,EAAE,WAAW,MAAM,iBAAiB,KAAK;AAAA,EACjD;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR,OAAO,CAAC,MAAM,KAAK,IAAI;AAAA,IACvB,SAAS;AAAA,IACT,MAAM;AAAA,MACJ,WAAW,EAAE,gBAAgB,KAAK,QAAQ,IAAI;AAAA,MAC9C,OAAO,EAAE,gBAAgB,KAAK,QAAQ,KAAK,iBAAiB,IAAI;AAAA,MAChE,OAAO,EAAE,gBAAgB,KAAK,QAAQ,KAAK,iBAAiB,IAAI;AAAA,MAChE,WAAW,EAAE,gBAAgB,KAAK,QAAQ,KAAK;AAAA,IACjD;AAAA,IACA,MAAM,EAAE,WAAW,MAAM,iBAAiB,KAAK;AAAA,EACjD;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR,OAAO,CAAC,MAAM,KAAK,IAAI;AAAA,IACvB,SAAS;AAAA,IACT,MAAM;AAAA,MACJ,WAAW,EAAE,gBAAgB,KAAK,QAAQ,KAAK,WAAW,KAAK;AAAA,MAC/D,OAAO,EAAE,gBAAgB,KAAK,QAAQ,MAAM,iBAAiB,IAAI,WAAW,KAAK;AAAA,MACjF,OAAO,EAAE,gBAAgB,KAAK,QAAQ,KAAK,iBAAiB,KAAK,WAAW,KAAK;AAAA,MACjF,WAAW,EAAE,gBAAgB,KAAK,QAAQ,MAAM,WAAW,KAAK;AAAA,IAClE;AAAA,IACA,MAAM,EAAE,WAAW,KAAK,iBAAiB,KAAK;AAAA,EAChD;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR,OAAO,CAAC,KAAK,MAAM,IAAI;AAAA,IACvB,SAAS;AAAA,IACT,MAAM;AAAA,MACJ,WAAW,EAAE,gBAAgB,MAAO,QAAQ,MAAM,WAAW,MAAM;AAAA,MACnE,OAAO,EAAE,gBAAgB,KAAK,QAAQ,KAAK,iBAAiB,IAAI;AAAA,MAChE,OAAO,EAAE,gBAAgB,MAAO,QAAQ,KAAK,iBAAiB,GAAG;AAAA,MACjE,WAAW,EAAE,gBAAgB,KAAK,QAAQ,KAAK,WAAW,IAAI;AAAA,IAChE;AAAA,IACA,MAAM,EAAE,WAAW,GAAG,iBAAiB,KAAK,WAAW,OAAQ,WAAW,KAAK;AAAA,EACjF;AAAA,EACA;AAAA,IACE,IAAI;AAAA,IACJ,QAAQ;AAAA,IACR,OAAO,CAAC,MAAM,MAAM,GAAG;AAAA,IACvB,SAAS;AAAA,IACT,MAAM;AAAA,MACJ,WAAW,EAAE,gBAAgB,MAAO,QAAQ,MAAM,WAAW,MAAM;AAAA,MACnE,OAAO,EAAE,gBAAgB,KAAK,QAAQ,MAAM,iBAAiB,KAAK;AAAA,MAClE,OAAO,EAAE,gBAAgB,KAAK,QAAQ,KAAK,iBAAiB,KAAK;AAAA,MACjE,WAAW,EAAE,gBAAgB,KAAK,QAAQ,KAAK;AAAA,IACjD;AAAA,IACA,MAAM,EAAE,WAAW,KAAK,iBAAiB,KAAK;AAAA,EAChD;AACF;AAEO,IAAM,mBAA8C;AAAA,EACzD,EAAE,IAAI,QAAQ,QAAQ,CAAC,EAAE,UAAU,QAAQ,WAAW,KAAK,GAAG,EAAE,UAAU,QAAQ,WAAW,IAAI,GAAG,EAAE,UAAU,SAAS,WAAW,IAAI,CAAC,EAAE;AAAA,EAC3I,EAAE,IAAI,QAAQ,QAAQ,CAAC,EAAE,UAAU,QAAQ,WAAW,IAAI,GAAG,EAAE,UAAU,SAAS,WAAW,IAAI,CAAC,EAAE;AAAA,EACpG,EAAE,IAAI,QAAQ,QAAQ,CAAC,EAAE,UAAU,QAAQ,WAAW,IAAI,CAAC,EAAE;AAAA,EAC7D,EAAE,IAAI,QAAQ,QAAQ,CAAC,EAAE,UAAU,WAAW,WAAW,KAAK,GAAG,EAAE,UAAU,UAAU,WAAW,KAAK,GAAG,EAAE,UAAU,QAAQ,WAAW,IAAI,CAAC,EAAE;AAAA,EAChJ,EAAE,IAAI,iBAAiB,QAAQ,CAAC,EAAE,UAAU,YAAY,WAAW,MAAM,eAAe,EAAE,UAAU,SAAS,OAAO,MAAM,SAAS,MAAM,YAAY,EAAE,EAAE,CAAC,EAAE;AAAA,EAC5J,EAAE,IAAI,kBAAkB,MAAM,GAAG,QAAQ,CAAC,EAAE,UAAU,YAAY,WAAW,MAAM,eAAe,EAAE,UAAU,SAAS,OAAO,MAAM,SAAS,MAAM,YAAY,EAAE,EAAE,CAAC,EAAE;AAAA,EACtK,EAAE,IAAI,cAAc,QAAQ,CAAC,EAAE,UAAU,WAAW,WAAW,KAAM,GAAG,EAAE,UAAU,UAAU,WAAW,KAAK,GAAG,EAAE,UAAU,YAAY,WAAW,KAAK,eAAe,EAAE,UAAU,SAAS,OAAO,MAAM,SAAS,MAAM,YAAY,EAAE,EAAE,CAAC,EAAE;AAAA,EAC5O,EAAE,IAAI,cAAc,QAAQ,CAAC,EAAE,UAAU,aAAa,WAAW,MAAM,GAAG,EAAE,UAAU,UAAU,WAAW,KAAK,GAAG,EAAE,UAAU,YAAY,WAAW,KAAK,eAAe,EAAE,UAAU,SAAS,OAAO,MAAM,SAAS,MAAM,YAAY,EAAE,EAAE,CAAC,EAAE;AAAA,EAC9O,EAAE,IAAI,gBAAgB,QAAQ,CAAC,EAAE,UAAU,SAAS,WAAW,KAAK,GAAG,EAAE,UAAU,UAAU,WAAW,IAAI,GAAG,EAAE,UAAU,QAAQ,WAAW,IAAI,CAAC,EAAE;AACvJ;AAGO,IAAM,2BAA2B;AAGjC,IAAM,kBAAkB;;;AC9J/B,IAAM,aAAa;AACnB,IAAM,cAAc;AACpB,IAAM,WAAW;AACjB,IAAM,cAAc;AACpB,IAAM,WAAW;AAiBV,SAAS,kBAAkB,KAAgC;AAChE,QAAM,OAAwB,CAAC;AAC/B,MAAI,SAAS;AAEb,WAAS,WAAiB;AACxB,QAAI,KAAK,SAAS,IAAI,EAAG;AACzB,QAAI,KAAK;AACT,QAAI,SAAS;AACb,QAAI,gBAAgB;AACpB,QAAI,cAAc;AAClB,SAAK,QAAQ,CAAC,OAAO,UAAU;AAC7B,UAAI,MAAM,OAAO,QAAQ;AACvB,iBAAS,MAAM;AACf,aAAK;AAAA,MACP;AACA,UAAI,MAAM,UAAU,MAAM,OAAO,aAAa;AAC5C,sBAAc,MAAM;AACpB,wBAAgB;AAAA,MAClB;AAAA,IACF,CAAC;AACD,SAAK,OAAO,iBAAiB,IAAI,gBAAgB,IAAI,CAAC;AAAA,EACxD;AAEA,SAAO;AAAA,IACL;AAAA,IACA,WAAW,MAAM;AACf,eAAS;AACT,WAAK,KAAK,EAAE,GAAG,MAAM,IAAI,EAAE,QAAQ,MAAM,QAAQ,QAAQ,OAAO,SAAS,EAAE,CAAC;AAAA,IAC9E;AAAA,IACA,OAAO,IAAI,OAAO;AAChB,eAAS,IAAI,KAAK,SAAS,GAAG,KAAK,GAAG,KAAK;AACzC,cAAM,QAAQ,KAAK,CAAC;AACpB,YAAI,MAAM,QAAQ;AAEhB,gBAAM,QAAQ,MAAM,SAAS,MAAM,SAAS,CAAC,GAAG,MAAM,SAAS,CAAC,CAAC,IAAI,MAAM,SAAS;AACpF,cAAI,MAAM,SAAS,CAAC,IAAI,QAAQ,SAAU,OAAM,SAAS;AAAA,mBAChD,MAAM,SAAS,CAAC,IAAI,QAAQ,SAAU,OAAM,SAAS,CAAC,IAAI;AACnE,cAAI,MAAM,OAAQ;AAAA,QACpB;AACA,cAAM,EAAE,UAAU,SAAS,IAAI;AAC/B,iBAAS,CAAC,KAAK,MAAM,UAAU;AAC/B,iBAAS,CAAC,KAAK,SAAS,CAAC,IAAI;AAC7B,iBAAS,CAAC,KAAK,SAAS,CAAC,IAAI;AAC7B,iBAAS,CAAC,KAAK,SAAS,CAAC,IAAI;AAC7B,cAAM,SAAS,MAAM,SAAS,SAAS,CAAC,GAAG,SAAS,CAAC,CAAC,IAAI,MAAM,SAAS;AACzE,YAAI,SAAS,CAAC,IAAI,OAAQ;AAC1B,iBAAS,CAAC,IAAI;AACd,cAAM,QAAQ,KAAK,MAAM,SAAS,CAAC,GAAG,SAAS,CAAC,GAAG,SAAS,CAAC,CAAC;AAC9D,YAAI,QAAQ,cAAc,MAAM,WAAW,aAAa;AACtD,gBAAM,SAAS;AACf,cAAI,MAAM,OAAO,KAAK,EAAG,MAAK,OAAO,GAAG,CAAC;AACzC;AAAA,QACF;AACA,cAAM;AACN,iBAAS,CAAC,IAAI,KAAK,IAAI,SAAS,CAAC,CAAC,IAAI;AACtC,iBAAS,CAAC,KAAK;AACf,iBAAS,CAAC,KAAK;AAAA,MACjB;AAAA,IACF;AAAA,IACA,QAAQ;AACN,WAAK,SAAS;AAAA,IAChB;AAAA,EACF;AACF;;;ACnFA,IAAM,YAAY;AAeX,SAAS,gBAAgB,QAAkC;AAChE,QAAM,OAAsB,CAAC;AAC7B,QAAM,QAAQ,oBAAI,IAA2B;AAC7C,MAAI,SAAS;AACb,MAAI,UAAU;AACd,QAAM,UAAU,CAAC,GAAW,MAAsB,KAAK,MAAM,IAAI,OAAO,YAAY,IAAI,SAAS,KAAK,MAAM,IAAI,OAAO,YAAY;AAEnI,WAAS,OAAO,MAAyB;AACvC,UAAM,MAAM,QAAQ,KAAK,GAAG,KAAK,CAAC;AAClC,UAAM,OAAO,MAAM,IAAI,GAAG;AAC1B,QAAI,MAAM;AACR,YAAMA,MAAK,KAAK,QAAQ,IAAI;AAC5B,UAAIA,OAAM,EAAG,MAAK,OAAOA,KAAI,CAAC;AAC9B,UAAI,KAAK,WAAW,EAAG,OAAM,OAAO,GAAG;AAAA,IACzC;AACA,UAAM,KAAK,KAAK,QAAQ,IAAI;AAC5B,QAAI,MAAM,EAAG,MAAK,OAAO,IAAI,CAAC;AAC9B;AAAA,EACF;AAEA,WAAS,OAAO,MAAyB;AACvC,UAAM,MAAM,QAAQ,KAAK,GAAG,KAAK,CAAC;AAClC,UAAM,OAAO,MAAM,IAAI,GAAG;AAC1B,QAAI,KAAM,MAAK,KAAK,IAAI;AAAA,QACnB,OAAM,IAAI,KAAK,CAAC,IAAI,CAAC;AAC1B,SAAK,KAAK,IAAI;AACd;AAAA,EACF;AAEA,WAAS,iBAAiB,MAA2B;AACnD,QAAI,QAAQ,KAAK,CAAC;AAClB,QAAI,QAAQ,KAAK,CAAC;AAClB,QAAI,OAAO;AACX,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,eAAS,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACxC,cAAM,WAAW,KAAK,MAAM,KAAK,CAAC,EAAG,IAAI,KAAK,CAAC,EAAG,GAAG,KAAK,CAAC,EAAG,IAAI,KAAK,CAAC,EAAG,CAAC;AAC5E,YAAI,WAAW,MAAM;AACnB,iBAAO;AACP,kBAAQ,KAAK,CAAC;AACd,kBAAQ,KAAK,CAAC;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AACA,UAAM,SAAS,MAAM,UAAU,IAAI,MAAM,UAAU;AACnD,UAAM,SAAS,SAAS,IAAI,MAAM,UAAU,IAAI,SAAS;AACzD,WAAO,KAAK;AACZ,UAAM,MAAM,MAAM,IAAI,MAAM,KAAK;AACjC,UAAM,MAAM,MAAM,IAAI,MAAM,KAAK;AACjC,UAAM,SAAS,KAAK,KAAK,MAAM;AAC/B,UAAM,QAAQ,KAAK,IAAI,MAAM,OAAO,MAAM,KAAK;AAC/C,UAAM,SAAS,MAAM;AACrB;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,IAAI,MAAM;AACR,YAAM,OAAoB,EAAE,GAAG,MAAM,IAAI,EAAE,QAAQ,OAAO,GAAG,MAAM,OAAO;AAC1E,aAAO,IAAI;AACX,YAAM,OAAO,MAAM,IAAI,QAAQ,KAAK,GAAG,KAAK,CAAC,CAAC;AAC9C,UAAI,KAAK,SAAS,OAAO,gBAAiB,kBAAiB,IAAI;AAC/D,UAAI,KAAK,SAAS,OAAO,SAAU,QAAO,KAAK,OAAO,CAAC,QAAQ,cAAe,UAAU,OAAO,OAAO,OAAO,YAAY,MAAO,CAAC;AACjI,aAAO;AAAA,IACT;AAAA,IACA,KAAK,GAAG,GAAG,QAAQ;AACjB,UAAI;AACJ,UAAI,OAAO;AACX,YAAM,QAAQ,KAAK,MAAM,SAAS,OAAO,OAAO,YAAY;AAC5D,YAAM,QAAQ,KAAK,MAAM,IAAI,OAAO,YAAY;AAChD,YAAM,QAAQ,KAAK,MAAM,IAAI,OAAO,YAAY;AAChD,eAAS,KAAK,CAAC,OAAO,MAAM,OAAO,MAAM;AACvC,iBAAS,KAAK,CAAC,OAAO,MAAM,OAAO,MAAM;AACvC,qBAAW,QAAQ,MAAM,KAAK,QAAQ,MAAM,SAAS,QAAQ,EAAE,KAAK,CAAC,GAAG;AACtE,kBAAM,WAAW,KAAK,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC;AAClD,gBAAI,WAAW,QAAQ,WAAW,KAAK,IAAI,KAAK,QAAQ,MAAM,IAAI,WAAW;AAC3E,qBAAO;AACP,sBAAQ;AAAA,YACV;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,IACA,QAAQ,GAAG,GAAG;AACZ,UAAI,QAAQ;AACZ,iBAAW,QAAQ,MAAM,IAAI,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG;AACjD,cAAM,WAAW,KAAK,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC;AAClD,YAAI,WAAW,KAAK,OAAQ,SAAQ,KAAK,IAAI,OAAO,KAAK,SAAS,KAAK,WAAW,KAAK,WAAW,EAAE;AAAA,MACtG;AACA,aAAO;AAAA,IACT;AAAA,IACA,QAAQ;AAAA,IACR,aAAa,GAAG,GAAG,QAAQ;AACzB,iBAAW,QAAQ,CAAC,GAAG,IAAI,EAAG,KAAI,KAAK,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,KAAK,SAAS,MAAM,OAAQ,QAAO,IAAI;AAAA,IAChH;AAAA,IACA,QAAQ;AACN,WAAK,SAAS;AACd,YAAM,MAAM;AACZ;AAAA,IACF;AAAA,IACA,KAAK,OAAO;AACV,WAAK,MAAM;AACX,iBAAW,QAAQ,OAAO;AACxB,eAAO,EAAE,GAAG,KAAK,CAAC;AAClB,iBAAS,KAAK,IAAI,QAAQ,KAAK,EAAE;AAAA,MACnC;AAAA,IACF;AAAA,IACA,IAAI,UAAU;AACZ,aAAO;AAAA,IACT;AAAA,EACF;AACF;;;AChIO,SAAS,aAAa,MAA4B;AACvD,MAAI,QAAQ,OAAO;AACnB,SAAO,MAAM;AACX,YAAS,QAAQ,aAAc;AAC/B,QAAI,QAAQ,KAAK,KAAK,QAAS,UAAU,IAAK,IAAI,KAAK;AACvD,YAAS,QAAQ,KAAK,KAAK,QAAS,UAAU,GAAI,KAAK,KAAK,IAAK;AACjE,aAAS,QAAS,UAAU,QAAS,KAAK;AAAA,EAC5C;AACF;;;ACFO,IAAM,yBAAwC;AAAA,EACnD,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB,UAAU;AAAA,EACV,wBAAwB;AAAA,EACxB,WAAW;AAAA,EACX,kBAAkB;AAAA,EAClB,uBAAuB;AAAA,EACvB,iBAAiB;AACnB;AAEA,IAAM,UAAU;AAEhB,IAAM,aAAa;AAEnB,IAAM,mBAAmB;AACzB,IAAM,iBAAiB;AAEvB,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAC7B,IAAM,YAAY;AAElB,IAAM,gBAAgB;AAEtB,IAAM,cAAc;AAEpB,IAAM,qBAAqB;AAE3B,IAAM,cAAc;AAEpB,IAAM,YAAY;AAClB,IAAM,eAAe;AACrB,IAAM,yBAAyB;AAC/B,IAAM,cAAc;AACpB,IAAM,gBAAgB;AAEtB,IAAM,eAA0D,EAAE,OAAO,OAAO,OAAO,OAAO,QAAQ,OAAO,WAAW,MAAM,MAAM,MAAM;AAE1I,IAAM,kBAA+C,EAAE,WAAW,IAAI,WAAW,GAAG,OAAO,KAAK,OAAO,IAAI;AAE3G,IAAM,aAAa,CAAC,OAAe,QAAwB,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,CAAC;AAC3F,IAAM,SAAS,CAAC,UAA4C;AAC1D,QAAM,UAA8B,CAAC;AACrC,QAAM,QAAQ,CAAC,OAAO,UAAU;AAC9B,QAAI,UAAU,EAAG,SAAQ,KAAK,CAAC,OAAO,KAAK,CAAC;AAAA,EAC9C,CAAC;AACD,SAAO;AACT;AACA,IAAM,aAAa,CAAC,OAAqB,YAA0D;AACjG,QAAM,KAAK,CAAC;AACZ,aAAW,CAAC,OAAO,KAAK,KAAK,QAAS,OAAM,KAAK,IAAI;AACvD;AAGA,SAAS,eAAe,SAAyB,OAAwE;AACvH,MAAI,MAAM;AACV,WAASC,SAAQ,GAAGA,SAAQ,QAAQ,OAAO,QAAQA,UAAS;AAC1D,UAAMC,WAAU,QAAQ,OAAOD,MAAK;AACpC,QAAI,QAAQ,MAAMC,SAAQ,YAAY,KAAM,QAAO,EAAE,OAAAD,QAAO,SAAAC,UAAS,IAAI;AACzE,WAAOA,SAAQ;AAAA,EACjB;AACA,QAAM,QAAQ,QAAQ,OAAO,SAAS;AACtC,QAAM,UAAU,QAAQ,OAAO,KAAK;AACpC,SAAO,EAAE,OAAO,SAAS,KAAK,MAAM,QAAQ,UAAU;AACxD;AACA,IAAM,iBAAiB,CAAC,YAAoC,QAAQ,OAAO,OAAO,CAAC,KAAK,YAAY,MAAM,QAAQ,WAAW,CAAC;AAEvH,SAAS,cAAc,SAAkC;AAC9D,QAAM,CAAC,IAAI,IAAI,IAAI,EAAE,IAAI,QAAQ;AACjC,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,aAAa,QAAQ,cAAc;AACzC,QAAM,UAAU,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,MAAM,QAAQ,CAAC;AAC3D,QAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,MAAM,QAAQ,CAAC;AACxD,QAAM,SAAS,UAAU;AACzB,QAAM,cAAc,UAAU,OAAO;AACrC,QAAM,UAAU,KAAK,KAAK,UAAU,UAAU;AAC9C,QAAM,UAAU,KAAK,KAAK,OAAO,UAAU;AAC3C,QAAM,SAAwB,EAAE,GAAG,wBAAwB,GAAG,QAAQ,OAAO;AAC7E,QAAM,UAAU,QAAQ,WAAW;AACnC,QAAM,YAAY,IAAI,IAA6B,CAAC,GAAG,mBAAmB,GAAI,QAAQ,aAAa,CAAC,CAAE,EAAE,IAAI,CAAC,aAAa,CAAC,SAAS,IAAI,QAAQ,CAAC,CAAC;AAClJ,QAAM,aAAa,IAAI,IAA4B,CAAC,GAAG,kBAAkB,GAAI,QAAQ,YAAY,CAAC,CAAE,EAAE,IAAI,CAAC,YAAY,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAC;AAC7I,QAAM,cAAc,CAAC,GAAG,WAAW,OAAO,CAAC;AAC3C,aAAW,WAAW,aAAa;AACjC,eAAW,WAAW,QAAQ,OAAQ,KAAI,CAAC,UAAU,IAAI,QAAQ,QAAQ,EAAG,OAAM,IAAI,MAAM,0BAA0B,QAAQ,EAAE,oBAAoB,QAAQ,QAAQ,kCAAkC;AAAA,EACxM;AACA,QAAM,iBAAiB,IAAI,IAAI,YAAY,IAAI,CAAC,SAAS,UAAU,CAAC,QAAQ,IAAI,KAAK,CAAC,CAAC;AACvF,QAAM,aAAa,YAAY,IAAI,cAAc;AAEjD,QAAM,OAAO,IAAI,aAAa,WAAW;AACzC,MAAI,QAAQ,YAAY;AACtB,aAAS,MAAM,GAAG,OAAO,MAAM,MAAO,UAAS,SAAS,GAAG,UAAU,SAAS,SAAU,MAAK,MAAM,SAAS,MAAM,IAAI,QAAQ,WAAW,KAAK,SAAS,UAAU,KAAK,MAAM,QAAQ;AAAA,EACtL;AACA,QAAM,MAAM,IAAI,aAAa,WAAW;AACxC,QAAM,QAAQ,IAAI,aAAa,WAAW;AAC1C,QAAM,SAAS,IAAI,aAAa,WAAW;AAC3C,QAAM,UAAU,IAAI,aAAa,WAAW;AAC5C,QAAM,eAAe,IAAI,WAAW,WAAW;AAC/C,QAAM,UAAU,IAAI,WAAW,UAAU,OAAO;AAChD,QAAM,QAAQ,IAAI,WAAW,UAAU,OAAO;AAC9C,QAAM,QAAQ,oBAAI,IAAY;AAC9B,QAAM,QAAQ,gBAAgB,MAAM;AACpC,QAAM,cAAc,kBAAkB,MAAM,OAAO,SAAS;AAC5D,QAAM,UAAU,oBAAI,IAAY;AAChC,QAAM,UAAU,oBAAI,IAAoB;AACxC,QAAM,SAAS,aAAa,QAAQ,QAAQ,CAAC;AAC7C,MAAI,gBAA8B,QAAQ,UAAU,EAAE,SAAS,gBAAgB;AAE/E,QAAM,kBAAkB,oBAAI,IAAqC;AACjE,QAAM,aAAa,CAAC,GAAW,GAAW,WAAyB;AACjE,eAAW,YAAY,gBAAiB,UAAS,EAAE,GAAG,GAAG,OAAO,CAAC;AAAA,EACnE;AAEA,QAAM,gBAAgB,CAAC,QAAgB,QAAwB,KAAK,IAAI,UAAU,GAAG,KAAK,MAAM,MAAM,UAAU,CAAC,IAAI,UAAU,KAAK,IAAI,UAAU,GAAG,KAAK,MAAM,SAAS,UAAU,CAAC;AAEpL,WAAS,YAAY,QAAgB,KAAmB;AACtD,UAAMC,SAAQ,cAAc,QAAQ,GAAG;AACvC,YAAQA,MAAK,IAAI;AACjB,UAAM,IAAIA,MAAK;AACf,QAAI,SAAS,eAAe,KAAK,SAAS,EAAG,WAAUA,SAAQ,CAAC;AAChE,QAAI,MAAM,eAAe,KAAK,MAAM,EAAG,WAAUA,SAAQ,OAAO;AAChE,QAAI,SAAS,eAAe,KAAK,MAAM,eAAe,KAAK,SAAS,KAAK,MAAM,EAAG,WAAUA,SAAQ,UAAU,CAAC;AAAA,EACjH;AACA,WAAS,UAAUA,QAAqB;AACtC,YAAQA,MAAK,IAAI;AACjB,UAAM,IAAIA,MAAK;AAAA,EACjB;AAEA,QAAM,YAAY,CAAC,OAAuB,eAAe,IAAI,EAAE,KAAK,eAAe,IAAI,eAAe,KAAK;AAE3G,WAAS,YAAY,QAA4B;AAC/C,oBAAgB;AAChB,iBAAa,KAAK,UAAU,OAAO,OAAO,CAAC;AAC3C,eAAW,QAAQ,OAAO,SAAS,CAAC,GAAG;AACrC,YAAM,QAAQ,UAAU,KAAK,OAAO;AACpC,YAAM,CAAC,KAAK,KAAK,KAAK,GAAG,IAAI,KAAK;AAClC,YAAM,UAAU,WAAW,KAAK,OAAO,MAAM,MAAM,QAAQ,GAAG,OAAO;AACrE,YAAM,UAAU,WAAW,KAAK,OAAO,MAAM,MAAM,QAAQ,GAAG,OAAO;AACrE,YAAM,OAAO,WAAW,KAAK,OAAO,MAAM,MAAM,QAAQ,GAAG,IAAI;AAC/D,YAAM,OAAO,WAAW,KAAK,OAAO,MAAM,MAAM,QAAQ,GAAG,IAAI;AAC/D,eAAS,MAAM,MAAM,OAAO,MAAM,MAAO,cAAa,KAAK,OAAO,MAAM,SAAS,SAAS,MAAM,SAAS,UAAU,CAAC;AAAA,IACtH;AACA,aAAS,SAAS,GAAG,SAAS,SAAS,UAAU;AAC/C,eAAS,SAAS,GAAG,SAAS,SAAS,UAAU;AAC/C,cAAMA,SAAQ,SAAS,UAAU;AACjC,cAAM,QAAQ,aAAc,SAAS,aAAc,SAAS,SAAS,UAAU;AAC/E,YAAI,UAAU;AACd,cAAM,UAAU,KAAK,IAAI,OAAO,SAAS,KAAK,UAAU;AACxD,cAAM,aAAa,KAAK,IAAI,UAAU,SAAS,KAAK,UAAU;AAC9D,iBAAS,MAAM,SAAS,YAAY,OAAO,WAAW,CAAC,SAAS,OAAO;AACrE,mBAAS,SAAS,SAAS,YAAY,UAAU,YAAY,UAAU;AACrE,gBAAI,aAAa,MAAM,SAAS,MAAM,MAAM,OAAO;AACjD,wBAAU;AACV;AAAA,YACF;AAAA,UACF;AAAA,QACF;AACA,cAAMA,MAAK,IAAI;AACf,cAAM,IAAIA,MAAK;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,eAAe,CAAC,QAAgB,QAAwB;AAC5D,UAAM,QAAQ,MAAM,SAAS;AAC7B,WAAO,KAAK,KAAK,IAAK,IAAI,KAAK,IAAK,MAAM,KAAK;AAAA,EACjD;AACA,QAAM,WAAW,CAAC,GAAW,MAAuB,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK;AAE1F,WAAS,SAAS,GAAW,GAAmB;AAE9C,QAAI,CAAC,SAAS,GAAG,CAAC,EAAG,QAAO,QAAQ,aAAa,GAAG,CAAC,KAAK;AAC1D,UAAM,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,UAAU,OAAO,IAAI,MAAM,QAAQ,CAAC;AACpE,UAAM,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,OAAO,IAAI,MAAM,QAAQ,CAAC;AACjE,UAAM,SAAS,KAAK;AACpB,UAAM,MAAM,KAAK;AACjB,UAAM,KAAK,KAAK;AAChB,UAAM,KAAK,KAAK;AAChB,UAAM,QAAQ,MAAM,SAAS;AAC7B,UAAM,IAAI,CAAC,MAAsB,KAAK,CAAC,IAAK,IAAI,CAAC,IAAK,MAAM,CAAC;AAC7D,YAAQ,EAAE,KAAK,KAAK,IAAI,MAAM,EAAE,QAAQ,CAAC,IAAI,OAAO,IAAI,OAAO,EAAE,QAAQ,MAAM,KAAK,IAAI,MAAM,EAAE,QAAQ,SAAS,CAAC,IAAI,MAAM;AAAA,EAC9H;AAEA,QAAM,WAAW,CAAC,GAAW,MAA8D;AACzF,UAAM,SAAS,WAAW,KAAK,OAAO,IAAI,MAAM,QAAQ,GAAG,OAAO;AAClE,UAAM,MAAM,WAAW,KAAK,OAAO,IAAI,MAAM,QAAQ,GAAG,IAAI;AAC5D,WAAO,EAAE,QAAQ,KAAK,OAAO,MAAM,SAAS,OAAO;AAAA,EACrD;AAEA,WAAS,eAAe,QAAgB,KAA8B;AACpE,UAAM,QAAQ,MAAM,SAAS;AAC7B,WAAO,UAAU,IAAI,eAAe,YAAY,aAAa,KAAK,CAAE,GAAI,IAAI,KAAK,CAAE,EAAE,QAAQ,QAAQ;AAAA,EACvG;AAEA,WAAS,SAAS,GAAW,GAA0B;AACrD,UAAM,EAAE,MAAM,IAAI,SAAS,GAAG,CAAC;AAC/B,UAAM,QAAQ,aAAa,KAAK;AAChC,UAAM,UAAU,YAAY,KAAK;AACjC,UAAM,QAAQ,KAAK,IAAI,WAAW,KAAK,GAAI,IAAI,KAAK,IAAK,MAAM,QAAQ,GAAG,CAAC,CAAC;AAC5E,UAAM,QAAQ,eAAe,SAAS,KAAK;AAC3C,WAAO,EAAE,SAAS,QAAQ,IAAI,UAAU,MAAM,QAAQ,UAAU,SAAS,MAAM,OAAO,OAAO,WAAW,WAAW,KAAK,IAAK,OAAO,QAAQ,OAAO,KAAK,GAAI,OAAO,MAAM,KAAK,EAAG;AAAA,EACnL;AAGA,WAAS,iBAAiB,OAAe,QAAwB;AAC/D,UAAM,YAAY,KAAK,IAAI,MAAM,KAAK,GAAI,MAAM;AAChD,UAAM,KAAK,IAAI,MAAM,KAAK,IAAK;AAC/B,UAAM,aAAa,KAAK,IAAI,WAAW,aAAa,KAAK,CAAE,IAAK,IAAI,KAAK,GAAI,SAAS,SAAS;AAC/F,QAAI,aAAa,EAAG,KAAI,KAAK,IAAI,IAAI,KAAK,IAAK;AAC/C,WAAO,YAAY,KAAK,IAAI,GAAG,UAAU;AAAA,EAC3C;AAEA,WAAS,YAAY,OAAe,QAAgB,aAA4B;AAC9E,UAAM,SAAS,cAAc,KAAK,IAAI,IAAI,KAAK,GAAI,MAAM,IAAI;AAC7D,QAAI,KAAK,IAAI,IAAI,KAAK,IAAK;AAC3B,UAAM,KAAK,IAAI,MAAM,KAAK,IAAK,SAAS;AAAA,EAC1C;AACA,QAAM,gBAAgB,CAAC,UAA2B,UAAU,IAAI,eAAe,YAAY,aAAa,KAAK,CAAE,GAAI,IAAI,KAAK,CAAE,EAAE,QAAQ,QAAQ,EAAG,kBAAkB;AAGrK,WAAS,UAAU,GAAW,GAAW,QAAgB,OAAe,WAAyB;AAC/F,UAAM,QAAQ,SAAS;AACvB,UAAM,UAAU,WAAW,KAAK,OAAO,IAAI,QAAQ,MAAM,QAAQ,GAAG,OAAO;AAC3E,UAAM,UAAU,WAAW,KAAK,MAAM,IAAI,QAAQ,MAAM,QAAQ,GAAG,OAAO;AAC1E,UAAM,OAAO,WAAW,KAAK,OAAO,IAAI,QAAQ,MAAM,QAAQ,GAAG,IAAI;AACrE,UAAM,OAAO,WAAW,KAAK,MAAM,IAAI,QAAQ,MAAM,QAAQ,GAAG,IAAI;AACpE,UAAM,SAAS,OAAO,IAAI;AAC1B,UAAM,SAAS,OAAO,IAAI;AAC1B,UAAM,UAAU,CAAC,IAAY,OAAuB;AAClD,YAAM,QAAQ,KAAK,MAAM,KAAK,GAAG,KAAK,CAAC;AACvC,aAAO,KAAK,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,UAAU,IAAI,OAAO,KAAK,IAAI,QAAQ,IAAI,MAAM,IAAI,OAAO,KAAK,IAAI,QAAQ,KAAK,MAAM;AAAA,IAC9H;AACA,QAAI,YAAY;AAChB,QAAI,YAAY,GAAG;AACjB,eAAS,MAAM,MAAM,OAAO,MAAM,OAAO;AACvC,iBAAS,SAAS,SAAS,UAAU,SAAS,UAAU;AACtD,gBAAM,IAAI,QAAQ,KAAK,SAAS,UAAU,KAAK,MAAM,QAAQ;AAC7D,cAAI,KAAK,KAAK,IAAI,UAAW,cAAa,KAAK,KAAM,IAAI,MAAM,YAAY,KAAM,KAAK,EAAE;AAAA,QAC1F;AAAA,MACF;AAAA,IACF;AACA,UAAM,WAAW,WAAW;AAC5B,aAAS,MAAM,MAAM,OAAO,MAAM,OAAO;AACvC,eAAS,SAAS,SAAS,UAAU,SAAS,UAAU;AACtD,cAAM,IAAI,QAAQ,KAAK,SAAS,UAAU,KAAK,MAAM,QAAQ;AAC7D,cAAM,QAAQ,MAAM,SAAS;AAC7B,YAAI,IAAI,GAAG;AACT,2BAAiB,OAAO,SAAS,IAAI,IAAI,MAAM,OAAO,OAAO,IAAI,KAAK;AACtE,kBAAQ,IAAI,KAAK;AACjB,sBAAY,QAAQ,GAAG;AAAA,QACzB,WAAW,IAAI,aAAa,YAAY,GAAG;AACzC,gBAAM,KAAK,IAAI,MAAM,KAAK,IAAM,YAAY,KAAK,KAAM,IAAI,MAAM,YAAY,KAAM,KAAK,EAAE,KAAM,YAAY;AAC5G,kBAAQ,IAAI,KAAK;AACjB,sBAAY,QAAQ,GAAG;AAAA,QACzB;AAAA,MACF;AAAA,IACF;AACA,UAAM,aAAa,GAAG,GAAG,MAAM;AAC/B,eAAW,GAAG,GAAG,KAAK;AAAA,EACxB;AAEA,WAAS,YAAY,MAAiM;AACpN,UAAM,SAAS,aAAa,KAAK,SAAS,MAAM;AAChD,UAAM,cAAe,IAAI,IAAK,KAAK,KAAK,UAAU;AAClD,UAAM,QAAQ,KAAK,IAAI,KAAK,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,SAAS,WAAW,CAAC,CAAC;AACrF,UAAM,OAAO,KAAK,IAAI,MAAM,KAAK,SAAS,IAAI;AAC9C,UAAM,SAAS,KAAK,IAAI,gBAAgB,KAAK,IAAI,GAAG,KAAK,KAAM,IAAI,KAAK,SAAS,cAAe,IAAI,CAAC;AACrG,aAAS,IAAI,GAAG,IAAI,OAAO,KAAK;AAC9B,YAAM,QAAQ,OAAO,IAAI;AACzB,YAAM,MAAM,KAAK,aAAa,KAAK,KAAK,OAAO,CAAC,IAAI;AACpD,YAAM,QAAQ,UAAU,MAAM,OAAO,IAAI;AACzC,YAAM,SAAS,OAAO,OAAO,IAAI;AACjC,YAAM,QAAQ,KAAK,YAAY,EAAE,KAAK,UAAU,CAAC,KAAK,KAAK,MAAM;AACjE,YAAM,QAAQ,KAAK,YAAY,EAAE,KAAK,UAAU,CAAC,KAAK,KAAK,MAAM;AACjE,kBAAY,WAAW;AAAA,QACrB,UAAU,KAAK,SAAS;AAAA,QACxB,MAAM,KAAK,SAAS;AAAA,QACpB,QAAQ,UAAU,MAAM,OAAO,IAAI;AAAA,QACnC,UAAU,CAAC,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,GAAG;AAAA,QACxF,UAAU,EAAE,KAAK,IAAI,KAAK,IAAI,SAAS,SAAS,QAAQ,MAAM,OAAO,IAAI,OAAO,QAAQ,KAAK,IAAI,KAAK,IAAI,SAAS,SAAS,KAAK;AAAA,QACjI,MAAM,EAAE,OAAO,IAAI,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK,OAAO,IAAI,OAAO,EAAE;AAAA,MAC5E,CAAC;AAAA,IACH;AAAA,EACF;AAEA,WAAS,OAAO,MAAmB,MAA0H;AAC3J,UAAM,EAAE,GAAG,EAAE,IAAI;AACjB,UAAM,QAAQ,SAAS,GAAG,CAAC;AAC3B,UAAM,UAAU,WAAW,IAAI,MAAM,OAAO;AAC5C,UAAM,UAAkD,CAAC;AACzD,UAAM,QAAkC,CAAC,GAAG,SAAS,GAAG,CAAC,GAAG,CAAC;AAC7D,QAAI,SAAS,KAAK;AAClB,QAAI,QAAQ,MAAM;AAClB,QAAI,SAAS;AACb,QAAI,SAAS;AACb,UAAM,gBAAgB,UAAU,IAAI,MAAM,QAAQ;AAClD,QAAI,MAAM,SAAS,GAAG;AACpB,iBAAS;AACP,cAAM,QAAQ,eAAe,SAAS,KAAK;AAC3C,cAAM,SAAS,MAAM,MAAM,MAAM,QAAQ;AACzC,cAAM,OAAO,SAAS;AACtB,YAAI,QAAQ,KAAM;AAClB,cAAM,WAAW,UAAU,IAAI,MAAM,QAAQ,QAAQ;AACrD,cAAM,WAAW,SAAS,KAAK,IAAI;AACnC,YAAI,CAAC,YAAY,UAAU,SAAS,mBAAmB,GAAI;AAC3D,cAAM,OAAO,MAAM,QAAQ;AAC3B,cAAM,YAAY,SAAS,UAAa,QAAQ,MAAM,OAAO,KAAK,QAAQ;AAC1E,cAAM,iBAAiB,SAAS,kBAAkB,YAAY,KAAK,aAAa;AAChF,cAAM,QAAQ,QAAQ,CAAC,YAAY,KAAK,IAAI,MAAM,MAAM,MAAM,KAAK,QAAQ,KAAK,IAAI;AACpF,cAAM,SAAS,SAAS;AACxB,cAAM,SAAS,KAAK,KAAM,IAAI,UAAW,KAAK,KAAK,SAAS,OAAO;AACnE,cAAM,cAAc,SAAS,SAAS;AACtC,cAAM,aAAa,KAAK,IAAI,aAAa,KAAK;AAC9C,cAAM,cAAc,aAAa,cAAc,aAAa,SAAS,SAAS;AAC9E,cAAM,cAAe,KAAK,KAAK,cAAc,cAAc,aAAc;AACzE,kBAAU,cAAc;AACxB,iBAAS;AACT,kBAAU;AACV,iBAAS,KAAK,IAAI,QAAQ,aAAa,SAAS,aAAa,GAAG,KAAK,iBAAiB,CAAC;AACvF,cAAM,OAAO,QAAQ,QAAQ,SAAS,CAAC;AACvC,YAAI,MAAM,aAAa,SAAS,GAAI,CAAC,KAA4B,UAAU;AAAA,YACtE,SAAQ,KAAK,EAAE,UAAU,SAAS,IAAI,QAAQ,YAAY,CAAC;AAChE,YAAI,UAAU,QAAQ,cAAc,cAAc,KAAM;AAAA,MAC1D;AAAA,IACF,OAAO;AAEL,YAAM,WAAW,cAAc,KAAK,IAAI;AACxC,UAAI,YAAY,WAAW,SAAS,mBAAmB,IAAI;AACzD,cAAM,SAAS,SAAS,SAAS;AACjC,iBAAS,KAAK,KAAM,IAAI,UAAW,KAAK,KAAK,SAAS,OAAO;AAC7D,iBAAS,SAAS,SAAS;AAC3B,gBAAQ,KAAK,EAAE,UAAU,cAAc,IAAI,OAAO,CAAC;AAAA,MACrD;AAAA,IACF;AACA,UAAM,YAAY,SAAS,MAAM,KAAK,QAAQ,GAAG,GAAG,OAAO;AAC3D,QAAI,UAAU,EAAG,QAAO,EAAE,OAAO,QAAQ,GAAG,OAAO,GAAG,YAAY,SAAS,GAAG,CAAC,EAAE,OAAO,SAAS,CAAC,GAAG,SAAS,MAAM,UAAU,SAAS,MAAM,aAAa,MAAM,cAAc,aAAa,SAAS,MAAM,KAAK,GAAG,WAAW,MAAM,KAAK;AAGxO,QAAI,cAAc,kBAAkB,UAAa,MAAM,SAAS,EAAG,WAAU,IAAI,kBAAkB,MAAM,QAAQ,kBAAkB,OAAO;AAE1I,UAAM,cAAc,QAAQ,OAAO,CAAC,KAAK,UAAU,MAAM,MAAM,QAAQ,CAAC;AACxE,UAAM,OAAO,SAAS,WAAW;AACjC,QAAI,KAAM,aAAY,EAAE,GAAG,GAAG,QAAQ,OAAO,QAAQ,MAAM,SAAS,KAAK,kBAAkB,OAAO,EAAE,CAAC;AAAA,SAChG;AACH,YAAM,WAAW,UAAU,IAAI,QAAQ,CAAC,EAAG,QAAQ,EAAG,YAAY;AAClE,gBAAU,GAAG,GAAG,QAAQ,QAAQ,cAAc,QAAQ;AAAA,IACxD;AACA,QAAI,QAAQ,OAAO;AACnB,eAAW,SAAS,SAAS;AAC3B,YAAM,WAAW,UAAU,IAAI,MAAM,QAAQ;AAC7C,YAAM,SAAS,MAAM,UAAU,KAAK,OAAO,IAAK,SAAS,YAAY;AACrE,UAAI,UAAU,KAAK,SAAS,EAAG;AAC/B,YAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,MAAO,QAAQ,MAAM,SAAU,WAAW,CAAC;AAC1E,kBAAY,EAAE,GAAG,GAAG,MAAM,CAAC,GAAG,GAAG,QAAQ,QAAQ,UAAU,QAAQ,KAAK,UAAU,MAAM,SAAS,cAAc,WAAW,KAAK,WAAW,OAAO,OAAO,YAAY,QAAQ,KAAK,CAAC;AAClL,eAAS;AAAA,IACX;AACA,UAAM,QAAQ,SAAS,GAAG,CAAC;AAC3B,WAAO,EAAE,OAAO,QAAQ,OAAO,QAAQ,YAAY,MAAM,OAAO,SAAS,SAAS,MAAM,UAAU,SAAS,MAAM,aAAa,MAAM,cAAc,aAAa,SAAS,MAAM,KAAK,GAAG,WAAW,KAAK;AAAA,EACxM;AAKA,WAAS,SAAS,MAAmB,QAAgB,GAAW,GAAW,SAAkC;AAC3G,UAAM,OAAO,QAAQ,OAAO,KAAK,CAAC,YAAY,QAAQ,aAAa;AACnE,QAAI,CAAC,MAAM,cAAe,QAAO;AACjC,UAAM,WAAW,UAAU,IAAI,KAAK,QAAQ,EAAG,KAAK,IAAI;AACxD,QAAI,CAAC,YAAY,UAAU,SAAS,mBAAmB,GAAI,QAAO;AAClE,UAAM,cAAc,KAAK,cAAc,eAAe;AACtD,QAAI,QAAQ,KAAK,cAAc;AAC/B,eAAW,WAAW,QAAQ,QAAQ;AACpC,UAAI,YAAY,KAAM;AACtB,eAAS,QAAQ;AAAA,IACnB;AACA,UAAM,QAAQ,KAAK,IAAI,WAAW,YAAY,KAAK,KAAM,IAAI,SAAU,SAAS,kBAAkB,KAAK,KAAK,SAAS,OAAO,KAAK,IAAI,eAAe;AACpJ,UAAM,UAAU,WAAW,KAAK,OAAO,IAAI,QAAQ,MAAM,QAAQ,GAAG,OAAO;AAC3E,UAAM,UAAU,WAAW,KAAK,MAAM,IAAI,QAAQ,MAAM,QAAQ,GAAG,OAAO;AAC1E,UAAM,OAAO,WAAW,KAAK,OAAO,IAAI,QAAQ,MAAM,QAAQ,GAAG,IAAI;AACrE,UAAM,OAAO,WAAW,KAAK,MAAM,IAAI,QAAQ,MAAM,QAAQ,GAAG,IAAI;AACpE,UAAM,QAAQ,kBAAkB,OAAO;AACvC,QAAI,YAAY;AAChB,aAAS,MAAM,MAAM,OAAO,MAAM,OAAO;AACvC,eAAS,SAAS,SAAS,UAAU,SAAS,UAAU;AACtD,cAAM,QAAQ,MAAM,SAAS;AAC7B,YAAI,IAAI,KAAK,IAAK,MAAO;AACzB,cAAM,IAAI,KAAK,MAAM,KAAK,SAAS,WAAW,GAAG,KAAK,MAAM,WAAW,CAAC,IAAI;AAC5E,YAAI,KAAK,EAAG;AACZ,gBAAQ,KAAK,IAAI,QAAQ,KAAK,IAAM,SAAS,eAAgB,IAAI,IAAI;AACrE,oBAAY,QAAQ,GAAG;AACvB,YAAI,QAAQ,KAAK,KAAM,KAAK,QAAQ,SAAS,UAAa,IAAI,KAAK,KAAM,QAAQ,wBAAwB,IAAI,KAAK,IAAK,QAAQ,QAAQ,MAAM;AAC3I,cAAI,KAAK,IAAI,QAAQ,QAAQ;AAC7B,sBAAY;AAAA,QACd;AAAA,MACF;AAAA,IACF;AACA,QAAI,UAAW,YAAW,GAAG,GAAG,KAAK;AAErC,QAAI,aAAa,QAAQ,SAAS,QAAW;AAC3C,eAAS,MAAM,MAAM,OAAO,MAAM,OAAO;AACvC,iBAAS,SAAS,SAAS,UAAU,SAAS,UAAU;AACtD,gBAAM,QAAQ,MAAM,SAAS;AAC7B,cAAI,QAAQ,KAAK,KAAM,wBAAwB,IAAI,KAAK,IAAK,QAAQ,QAAQ,MAAM;AACjF,gBAAI,KAAK,IAAI,QAAQ,QAAQ;AAC7B,wBAAY,QAAQ,GAAG;AAAA,UACzB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,oBAAoB,CAAC,YAAoC,WAAW,eAAe,IAAI,QAAQ,EAAE,CAAE;AACzG,WAAS,aAAa,SAAyB,OAAwB;AACrE,UAAM,QAAQ,eAAe,SAAS,KAAK;AAC3C,WAAO,MAAM,QAAQ,kBAAkB,UAAa,QAAQ,MAAM,OAAO,MAAM,QAAQ,cAAc,QAAQ;AAAA,EAC/G;AAEA,WAAS,YAAY,MAA8H;AACjJ,UAAM,EAAE,GAAG,GAAG,QAAQ,OAAO,MAAM,SAAS,IAAI,IAAI;AACpD,UAAM,UAAU,IAAI,SAAS,GAAG,CAAC,EAAE,KAAK;AACxC,UAAM,WAAW,MAAM,KAAK,GAAG,GAAG,MAAM;AACxC,QAAI;AACJ,QAAI,UAAU;AACZ,eAAS,SAAS,KAAK,MAAM,SAAS,QAAQ,MAAM;AACpD,eAAS,QAAQ,KAAK,IAAI,MAAM,SAAS,SAAS,QAAQ,KAAK;AAC/D,eAAS;AACT,eAAS,OAAO;AAChB,aAAO;AAAA,IACT,OAAO;AACL,aAAO,MAAM,IAAI,EAAE,GAAG,GAAG,QAAQ,OAAO,KAAK,IAAI,MAAM,SAAS,KAAK,GAAG,MAAM,UAAU,GAAG,CAAC;AAAA,IAC9F;AACA,SAAK,WAAW,eAAe,SAAS,UAAU,KAAK,QAAQ,IAAI,EAAE,QAAQ;AAC7E,QAAI,KAAK,UAAU,WAAW,cAAc,KAAK,SAAS,WAAW,kBAAkB;AACrF,YAAM,aAAa,KAAK,IAAI,KAAK,QAAQ,WAAW,UAAU;AAC9D,YAAM,YAAY,KAAK;AACvB,YAAM,OAAO,IAAI;AACjB,gBAAU,KAAK,GAAG,KAAK,GAAG,YAAY,WAAW,CAAC;AAAA,IACpD;AAAA,EACF;AAEA,WAAS,KAAK,MAA4F;AACxG,QAAI,KAAK,cAAc,cAAe;AACtC,UAAM,UAAU,WAAW,KAAK,OAAO,KAAK,IAAI,KAAK,SAAS,MAAM,QAAQ,GAAG,OAAO;AACtF,UAAM,UAAU,WAAW,KAAK,MAAM,KAAK,IAAI,KAAK,SAAS,MAAM,QAAQ,GAAG,OAAO;AACrF,UAAM,OAAO,WAAW,KAAK,OAAO,KAAK,IAAI,KAAK,SAAS,MAAM,QAAQ,GAAG,IAAI;AAChF,UAAM,OAAO,WAAW,KAAK,MAAM,KAAK,IAAI,KAAK,SAAS,MAAM,QAAQ,GAAG,IAAI;AAC/E,aAAS,MAAM,MAAM,OAAO,MAAM,OAAO;AACvC,eAAS,SAAS,SAAS,UAAU,SAAS,UAAU;AACtD,YAAI,KAAK,MAAM,KAAK,SAAS,WAAW,KAAK,GAAG,KAAK,MAAM,WAAW,KAAK,CAAC,IAAI,KAAK,OAAQ;AAC7F,mBAAW,QAAQ,KAAK,KAAK,OAAO;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AAEA,WAAS,WAAW,QAAgB,KAAa,SAAuB;AACtE,UAAM,QAAQ,MAAM,SAAS;AAC7B,UAAM,WAAW,eAAe,QAAQ,GAAG;AAC3C,UAAM,WAAW,SAAS;AAC1B,QAAI,CAAC,SAAU;AACf,UAAM,SAAS,OAAO,KAAK;AAC3B,WAAO,KAAK,IAAI,KAAK,IAAI,QAAQ,KAAK,IAAI,SAAS,WAAW,SAAS,SAAS,kBAAkB,OAAO,CAAC;AAC1G,QAAI,SAAS,UAAW,kBAAiB,OAAO,SAAS,YAAY,OAAO;AAC5E,QAAI,OAAO,KAAK,MAAM,UAAU,SAAS,UAAW,aAAY,QAAQ,GAAG;AAC3E,QAAI,SAAS,UAAW,QAAO,KAAK,SAAS,UAAU,KAAK,MAAM,QAAQ;AAAA,EAC5E;AAEA,QAAM,UAAU,CAAC,GAAW,MAAsB,KAAK,OAAO,IAAI,MAAM,SAAS,IAAI,QAAQ,KAAK,OAAO,IAAI,MAAM,SAAS;AAC5H,WAAS,OAAO,GAAW,GAAiB;AAC1C,UAAM,MAAM,QAAQ,GAAG,CAAC;AACxB,QAAI,QAAQ,IAAI,GAAG,KAAK,QAAQ,QAAQ,OAAO,gBAAiB;AAChE,UAAM,QAAQ,SAAS,GAAG,CAAC,EAAE;AAC7B,QAAI,OAAO,KAAK,KAAM,EAAG;AACzB,YAAQ,IAAI,KAAK,YAAY;AAAA,EAC/B;AAEA,WAAS,WAAW,IAAkB;AACpC,eAAW,CAAC,KAAK,SAAS,KAAK,CAAC,GAAG,OAAO,GAAG;AAC3C,YAAM,UAAU,KAAK,MAAM,MAAM,KAAK;AACtC,YAAM,aAAa,MAAM,UAAU;AACnC,YAAM,IAAI,MAAM,aAAa,OAAO;AACpC,YAAM,IAAI,MAAM,UAAU,OAAO;AACjC,WAAK,EAAE,GAAG,GAAG,QAAQ,YAAY,MAAM,aAAa,KAAK,SAAS,GAAG,CAAC;AACtE,UAAI,OAAO,IAAI,yBAAyB,IAAI;AAC1C,cAAM,QAAQ,KAAK,MAAM,OAAO,IAAI,CAAC,KAAK,KAAK,KAAK;AACpD,cAAM,QAAQ,IAAI,KAAK,IAAI,KAAK,IAAI;AACpC,cAAM,QAAQ,IAAI,KAAK,IAAI,KAAK,IAAI;AACpC,YAAI,SAAS,OAAO,KAAK,GAAG;AAC1B,gBAAM,EAAE,QAAQ,KAAK,MAAM,IAAI,SAAS,OAAO,KAAK;AACpD,cAAI,eAAe,QAAQ,GAAG,EAAE,MAAM,aAAa,OAAO,KAAK,IAAK,EAAG,QAAO,OAAO,KAAK;AAAA,QAC5F;AAAA,MACF;AACA,UAAI,YAAY,MAAM,EAAG,SAAQ,OAAO,GAAG;AAAA,UACtC,SAAQ,IAAI,KAAK,YAAY,EAAE;AAAA,IACtC;AAAA,EACF;AAEA,WAAS,eAAqB;AAC5B,QAAI,QAAQ,SAAS,EAAG;AACxB,QAAI,aAAa,OAAO;AACxB,QAAI,OAAO;AACX,QAAI,OAAO;AACX,QAAI,OAAO;AACX,QAAI,OAAO;AACX,eAAW,SAAS,SAAS;AAC3B,UAAI,gBAAgB,EAAG;AACvB,cAAQ,OAAO,KAAK;AACpB,YAAM,SAAS,QAAQ;AACvB,YAAM,OAAO,QAAQ,UAAU;AAC/B,UAAI,CAAC,cAAc,KAAK,EAAG;AAC3B,YAAM,WAAW,eAAe,QAAQ,GAAG;AAC3C,YAAM,QAAQ,KAAK,KAAM,SAAS,iBAAiB,MAAM,KAAK,KAAM,GAAG,IAAI;AAC3E,YAAM,SAAS,aAAa,QAAQ,GAAG;AACvC,YAAM,aAAiC,CAAC,CAAC,SAAS,GAAG,GAAG,GAAG,CAAC,SAAS,GAAG,GAAG,GAAG,CAAC,QAAQ,MAAM,CAAC,GAAG,CAAC,QAAQ,MAAM,CAAC,CAAC;AAClH,iBAAW,CAAC,YAAY,OAAO,KAAK,YAAY;AAC9C,YAAI,aAAa,KAAK,UAAU,KAAK,aAAa,WAAW,UAAU,KAAM;AAC7E,cAAM,SAAS,SAAS,aAAa,YAAY,OAAO,IAAI;AAC5D,YAAI,UAAU,cAAe;AAC7B,cAAM,QAAQ,iBAAiB,OAAO,SAAS,WAAW;AAC1D,YAAI,SAAS,EAAG;AAChB,cAAM,OAAO,UAAU,SAAS;AAChC,oBAAY,MAAM,OAAO,cAAc,IAAI,CAAC;AAC5C,gBAAQ,IAAI,KAAK;AACjB,gBAAQ,IAAI,IAAI;AAChB,oBAAY,QAAQ,GAAG;AACvB,oBAAY,YAAY,OAAO;AAC/B,cAAM,KAAK,KAAK,SAAS;AACzB,cAAM,KAAK,KAAK,MAAM;AACtB,eAAO,KAAK,IAAI,MAAM,EAAE;AACxB,eAAO,KAAK,IAAI,MAAM,EAAE;AACxB,eAAO,KAAK,IAAI,MAAM,EAAE;AACxB,eAAO,KAAK,IAAI,MAAM,EAAE;AAAA,MAC1B;AAAA,IACF;AACA,QAAI,QAAQ,KAAM,aAAY,OAAO,QAAQ,IAAI,OAAO,QAAQ,GAAG,KAAK,MAAM,OAAO,MAAM,OAAO,IAAI,IAAI,IAAI,WAAW,CAAC;AAAA,EAC5H;AAGA,WAAS,OAAO,OAA+B;AAC7C,UAAM,WAAW,UAAU,IAAI,MAAM,QAAQ;AAC7C,QAAI,CAAC,YAAY,SAAS,kBAAkB,OAAW,QAAO;AAC9D,QAAI,CAAC,SAAS,MAAM,SAAS,CAAC,GAAG,MAAM,SAAS,CAAC,CAAC,EAAG,QAAO;AAC5D,UAAM,EAAE,OAAO,QAAQ,IAAI,IAAI,SAAS,MAAM,SAAS,CAAC,GAAG,MAAM,SAAS,CAAC,CAAC;AAC5E,gBAAY,OAAS,IAAI,IAAK,KAAK,KAAK,MAAM,UAAU,KAAM,WAAW,WAAW,KAAK;AACzF,YAAQ,IAAI,KAAK;AACjB,gBAAY,QAAQ,GAAG;AACvB,WAAO;AAAA,EACT;AAEA,WAAS,SAAS,KAAoC;AACpD,UAAM,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI;AACtB,YAAQ,IAAI,MAAM;AAAA,MAChB,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,SAAS;AACZ,YAAI,CAAC,IAAI,OAAQ,QAAO;AACxB,cAAM,gBAAgB,IAAI,SAAS,UAAU,IAAI,SAAS;AAC1D,eAAO,OAAO,IAAI,MAAM,EAAE,GAAG,GAAG,QAAQ,IAAI,QAAQ,GAAI,IAAI,YAAY,EAAE,WAAW,IAAI,UAAU,IAAI,CAAC,GAAI,GAAI,kBAAkB,SAAY,EAAE,cAAc,IAAI,CAAC,EAAG,CAAC;AAAA,MACzK;AAAA,MACA,KAAK,aAAa;AAChB,YAAI,CAAC,IAAI,OAAQ,QAAO;AACxB,cAAM,QAAQ,KAAK,IAAI,GAAG,IAAI,SAAS,GAAG,CAAC,CAAC;AAC5C,cAAM,SAAS,IAAI,UAAU,KAAK;AAClC,YAAI,SAAS,MAAO,QAAO;AAC3B,eAAO,OAAO,aAAa,EAAE,GAAG,GAAG,QAAQ,IAAI,UAAU,IAAI,QAAQ,UAAU,EAAE,CAAC;AAAA,MACpF;AAAA,MACA,KAAK;AAAA,MACL,KAAK;AACH,YAAI,IAAI,SAAS,GAAG,CAAC,KAAK,IAAI,UAAU,OAAO,YAAa,QAAO;AACnE,aAAK,EAAE,GAAG,GAAG,QAAQ,IAAI,UAAU,KAAK,aAAa,IAAI,eAAe,GAAG,SAAS,IAAI,YAAY,MAAM,CAAC;AAC3G,eAAO;AAAA,MACT;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAEA,WAAS,QAAQ,QAA2B,WAA8B,aAAqH;AAC7L,UAAM,CAAC,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC,IAAI;AACjC,UAAM,CAAC,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC,IAAI;AACjC,UAAM,OAAO,WAAW;AACxB,QAAI,WAAW;AACf,aAAS,IAAI,GAAG,KAAK,aAAa,KAAK,MAAM;AAC3C,YAAM,IAAI,KAAK,KAAK;AACpB,YAAM,IAAI,KAAK,KAAK;AACpB,UAAI,SAAS,GAAG,CAAC,KAAK,KAAK,KAAK,KAAK,SAAS,GAAG,CAAC,GAAG;AACnD,YAAI,MAAM;AACV,YAAI,OAAO;AACX,iBAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,gBAAM,UAAU,MAAM,QAAQ;AAC9B,cAAI,KAAK,KAAK,UAAU,SAAS,KAAK,KAAK,QAAQ,KAAK,KAAK,MAAM,EAAG,QAAO;AAAA,cACxE,OAAM;AAAA,QACb;AACA,cAAM,KAAK,KAAK,KAAK;AACrB,cAAM,KAAK,KAAK,KAAK;AACrB,cAAM,KAAK,SAAS,KAAK,UAAU,EAAE,IAAI,SAAS,KAAK,UAAU,EAAE;AACnE,cAAM,KAAK,SAAS,IAAI,KAAK,QAAQ,IAAI,SAAS,IAAI,KAAK,QAAQ;AACnE,cAAM,SAAS,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE;AAC9C,eAAO,EAAE,OAAO,CAAC,IAAI,KAAK,KAAK,MAAM,EAAE,GAAG,UAAU,MAAM,QAAQ,CAAC,CAAC,KAAK,QAAS,IAAI,WAAY,QAAQ,CAAC,KAAK,MAAM,EAAE;AAAA,MAC1H;AACA,iBAAW;AAAA,IACb;AACA,WAAO;AAAA,EACT;AAEA,WAAS,MAAM,OAA6B;AAC1C,UAAM,SAAS,KAAK,MAAM,QAAQ,OAAO;AACzC,UAAM,SAAS,QAAQ,SAAS;AAChC,WAAO,EAAE,OAAO,QAAQ,SAAS,YAAY,KAAK,SAAS,YAAY,OAAO,YAAY,UAAU,CAAC,QAAQ,KAAK,KAAK,CAAC,MAAM,KAAK,KAAK,CAAC,QAAQ,WAAW;AAAA,EAC9J;AAEA,WAAS,QAAc;AACrB,QAAI,KAAK,CAAC;AACV,UAAM,KAAK,CAAC;AACZ,WAAO,KAAK,CAAC;AACb,YAAQ,KAAK,CAAC;AACd,YAAQ,KAAK,CAAC;AACd,UAAM,MAAM;AACZ,gBAAY,MAAM;AAClB,YAAQ,MAAM;AACd,YAAQ,MAAM;AACd,gBAAY,aAAa;AAAA,EAC3B;AAEA,cAAY,aAAa;AAEzB,SAAO;AAAA,IACL,QAAQ,QAAQ;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU,CAAC,OAAO;AAChB,YAAM,WAAW,UAAU,IAAI,EAAE;AACjC,UAAI,CAAC,SAAU,OAAM,IAAI,MAAM,mCAAmC,EAAE,GAAG;AACvE,aAAO;AAAA,IACT;AAAA,IACA,QAAQ,MAAM;AAAA,IACd,UAAU,QAAQ;AAChB,sBAAgB;AAChB,YAAM;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,UAAU;AACjB,sBAAgB,IAAI,QAAQ;AAC5B,aAAO,MAAM,gBAAgB,OAAO,QAAQ;AAAA,IAC9C;AAAA,IACA,OAAO,IAAI;AACT,kBAAY,OAAO,IAAI,EAAE,UAAU,SAAS,OAAO,CAAC;AACpD,mBAAa;AACb,iBAAW,EAAE;AAAA,IACf;AAAA,IACA,iBAAiB,MAAM,OAAO,wBAAwB;AACpD,YAAM,QAAwB,CAAC;AAC/B,iBAAW,SAAS,OAAO;AACzB,YAAI,MAAM,UAAU,IAAK;AACzB,cAAM,OAAO,KAAK;AAClB,cAAM,KAAK,MAAM,KAAK,CAAC;AAAA,MACzB;AACA,aAAO;AAAA,IACT;AAAA,IACA;AAAA,IACA,OAAO,MAAM,MAAM;AAAA,IACnB,QAAQ,MAAM,YAAY;AAAA,IAC1B,eAAe,MAAM,CAAC,GAAG,QAAQ,KAAK,CAAC,EAAE,IAAI,CAAC,QAAQ;AACpD,YAAM,UAAU,KAAK,MAAM,MAAM,KAAK;AACtC,YAAM,aAAa,MAAM,UAAU;AACnC,aAAO,CAAC,MAAM,aAAa,OAAO,WAAW,MAAM,UAAU,OAAO,SAAS;AAAA,IAC/E,CAAC;AAAA,IACD,IAAI,eAAe;AACjB,aAAO,MAAM;AAAA,IACf;AAAA,IACA,OAAO,OAAO,EAAE,OAAO,MAAM,KAAK,QAAQ,QAAQ,YAAY,KAAK,QAAQ,cAAc,YAAY,KAAK,OAAO,CAAC,UAAU,CAAC,MAAM,MAAM,EAAE,QAAQ,aAAa,MAAM,MAAM,SAAS,QAAQ,KAAK;AAAA,IAClM;AAAA,IACA,YAA6B;AAC3B,aAAO,EAAE,QAAQ,eAAe,KAAK,OAAO,GAAG,GAAG,OAAO,OAAO,KAAK,GAAG,QAAQ,OAAO,MAAM,GAAG,SAAS,OAAO,OAAO,GAAG,OAAO,MAAM,KAAK,IAAI,CAAC,UAAU,EAAE,GAAG,KAAK,EAAE,EAAE;AAAA,IAC3K;AAAA,IACA,KAAK,UAAU;AACb,sBAAgB,SAAS;AACzB,YAAM;AACN,iBAAW,KAAK,SAAS,GAAG;AAC5B,iBAAW,OAAO,SAAS,KAAK;AAChC,iBAAW,QAAQ,SAAS,MAAM;AAClC,iBAAW,SAAS,SAAS,WAAW,CAAC,CAAC;AAC1C,YAAM,KAAK,SAAS,KAAK;AACzB,eAAS,aAAa,GAAG,aAAa,QAAQ,QAAQ,aAAc,WAAU,UAAU;AAAA,IAC1F;AAAA,EACF;AACF;;;ACnsBA,IAAM,UAAU;AAChB,IAAM,aAAa;AACnB,IAAM,cAAc;AAab,SAAS,kBAAkB,SAAkB,SAA+C;AACjG,QAAM,EAAE,GAAG,IAAI;AACf,QAAM,CAAC,IAAI,IAAI,IAAI,EAAE,IAAI,QAAQ;AACjC,QAAM,OAAO,OAAyB;AAAA,IACpC,MAAM,QAAQ,QAAQ;AAAA,IACtB,OAAO;AAAA,MACL;AAAA,QACE,IAAI;AAAA,QACJ,UAAU,QAAQ,UAAU,KAAK,MAAM,IAAI,KAAK,MAAM,CAAC,EAAE;AAAA,QACzD,OAAO,EAAE,MAAM,OAAO,MAAM,CAAC,KAAK,IAAI,YAAY,KAAK,EAAE,EAAE;AAAA,QAC3D,UAAU,EAAE,KAAK,MAAM,GAAG,CAAC,aAAa,IAAI,KAAK,MAAM,CAAC;AAAA,QACxD,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,MAAM,CAAC,SAAS;AAAA,MAClB;AAAA,IACF;AAAA,IACA,QAAQ,CAAC;AAAA,EACX;AACA,QAAM,UAAU,CAAC,QAAkB;AACjC,QAAI,IAAI,SAAS,eAAe,IAAI,SAAS,WAAW,IAAI,SAAS,QAAS,QAAO;AACrF,QAAI,CAAC,IAAI,UAAW,QAAO,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,MAAM,CAAC,GAAG,QAAQ,SAAS,IAAI,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE;AACvH,UAAM,CAAC,IAAI,IAAI,EAAE,IAAI,IAAI;AACzB,UAAM,OAAO,CAAC,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,IAAI,MAAM,CAAC,IAAI,KAAK,WAAW;AAC/G,UAAM,WAAW,QAAQ,QAAQ,MAAM,IAAI,WAAW,cAAc,UAAU;AAC9E,WAAO,WAAW,EAAE,GAAG,KAAK,OAAO,SAAS,MAAM,IAAI;AAAA,EACxD;AACA,SAAO;AAAA,IACL;AAAA,IACA,GAAI,QAAQ,OAAO,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;AAAA,IAC7C,UAAU;AAAA,IACV,IAAI,KAAyB;AAC3B,YAAM,SAAS,QAAQ,GAAG;AAC1B,YAAM,SAAS,QAAQ,SAAS,MAAM;AACtC,UAAI,CAAC,UAAU,OAAO,UAAU,EAAG,QAAO,CAAC;AAC3C,cAAQ,SAAS,QAAQ,MAAM;AAC/B,aAAO,CAAC,EAAE,MAAM,UAAU,QAAQ,IAAI,MAAM,GAAG,MAAM,SAAS,QAAQ,GAAG,IAAI,MAAM,YAAY,IAAI,MAAM,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC,EAAG,CAAC;AAAA,IAC1J;AAAA,IACA,OAAO,IAAI;AACT,cAAQ,OAAO,EAAE;AACjB,aAAO,CAAC;AAAA,IACV;AAAA,IACA,QAAqB;AACnB,aAAO;AAAA,QACL;AAAA,QACA,UAAU,CAAC,GAAG,GAAG,CAAC;AAAA,QAClB,UAAU,CAAC,GAAG,GAAG,GAAG,CAAC;AAAA,QACrB,OAAO,CAAC;AAAA,QACR,QAAQ,CAAC;AAAA,QACT,QAAQ,CAAC,CAAC,OAAO,CAAC;AAAA,QAClB,WAAW;AAAA,MACb;AAAA,IACF;AAAA,IACA,OAAO,MAAM,QAAQ,MAAM;AAAA,IAC3B,WAAW,MAAM,QAAQ,UAAU;AAAA,IACnC,MAAM,CAAC,SAAS,QAAQ,KAAK,IAAwC;AAAA,EACvE;AACF;;;AC1BO,IAAM,mBAAmB,CAAC,SAAS,SAAS,QAAQ,QAAQ,WAAW,YAAY,QAAQ,UAAU,OAAO;","names":["at","index","stratum","chunk"]}
package/package.json CHANGED
@@ -1,6 +1,52 @@
1
1
  {
2
2
  "name": "@adatechnology/game-terrain",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.1.1",
4
+ "license": "MIT",
5
+ "description": "Deformable ground: a height field in chunks with strata per column (turf over soil over rock, asphalt over gravel, tile over mortar over slab). Blows dig the top stratum and reach the next when it runs out, down to a limit each profile has; fine marks with a budget per area; thrown clods that collide; fire that chars and spreads.",
6
+ "keywords": [
7
+ "game",
8
+ "terrain",
9
+ "heightmap",
10
+ "destruction"
11
+ ],
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/Andersonfrfilho/adatechnology-game-kit.git",
15
+ "directory": "packages/game-terrain"
16
+ },
17
+ "publishConfig": {
18
+ "access": "public"
19
+ },
20
+ "type": "module",
21
+ "main": "dist/index.js",
22
+ "module": "dist/index.js",
23
+ "types": "dist/index.d.ts",
24
+ "unpkg": "dist/index.global.js",
25
+ "jsdelivr": "dist/index.global.js",
26
+ "sideEffects": false,
27
+ "exports": {
28
+ ".": {
29
+ "types": "./dist/index.d.ts",
30
+ "import": "./dist/index.js"
31
+ },
32
+ "./global": "./dist/index.global.js"
33
+ },
34
+ "files": [
35
+ "dist"
36
+ ],
37
+ "dependencies": {
38
+ "@adatechnology/game-contracts": "0.19.0",
39
+ "@adatechnology/game-destruction": "0.12.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/node": "^22.10.7",
43
+ "tsup": "^8.5.1",
44
+ "typescript": "^5.7.3",
45
+ "vitest": "^3.2.4"
46
+ },
47
+ "scripts": {
48
+ "build": "tsup",
49
+ "typecheck": "tsc -p tsconfig.json --noEmit",
50
+ "test": "vitest run"
51
+ }
6
52
  }